python 离群值检验算法对比实战

前言

离群数据统计检验是数据分析中的一个重要环节,用于识别和处理那些与主体数据集显著不同的数据点。在水质在线数据分析过程中往往会遇到各种异常值,需要我们进行识别。

本文尝试通过对比不同的离群值检验方法,探究适合本地水质在线数据的检验方法。

常用的离群数据统计检验方法有四分位法、Z-Score 方法、孤立森林法、3σ原则等 4 种方法。
经过对比分析,Z-Score 与 3σ原则方法是最适合水质在线数据离群值检验的方法。具有离群值检验准确,原理清晰易懂,实现简单,配置参数少等优点。

示例数据集概览

fig1. 数据集折线图

上图是一个实际环境中运行的水质变化曲线,可见存在明显的离群值,如果不去除异常值,则是对后续分析是不利的。

不同离群值检验方法实现

IQR 法(四分位距)方法

IQR 方法是识别极端值的非参数方法,不需要数据遵循正态分布。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import matplotlib.pyplot as plt
import pandas as pd # Load the uploaded CSV file
file_path = '/mnt/data/2024-06-05T03-18_export.csv'
data = pd.read_csv(file_path)
# Convert '监测时间' to datetime format for better plotting
data['监测时间'] = pd.to_datetime(data['监测时间'])
# Sort the data by '监测时间' for better visualization in the plot
data_sorted = data.sort_values(by='监测时间')
# Create a boxplot for the '双河口' column
plt.figure(figsize=(10, 6))
plt.boxplot(data_sorted['双河口'], vert=False)
plt.title('Box Plot of 双河口')
plt.xlabel('双河口 Value')
plt.grid(True)
plt.show()

# Calculate IQR
Q1 = data_sorted['双河口'].quantile(0.25)
Q3 = data_sorted['双河口'].quantile(0.75)
IQR = Q3 - Q1
# Define the boundaries for outliers
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Filter out the outliers
outliers = data_sorted[(data_sorted['双河口'] < lower_bound) | (data_sorted['双河口'] > upper_bound)]
# Display the outliers
outliers

fig2.箱线图

Z-Score 方法

Z-Score 方法,也称为标准分数,是一种用于评估数据点相对于数据集平均值的标准偏差的统计方法。这种方法通过计算每个数据点与数据集平均值的偏差,然后除以数据集的标准差,来衡量每个数据点的异常程度。具体来说,Z-Score 的计算公式如下:
$$
Z = \frac{(X - \mu)}{\sigma}
$$
其中:

  • 𝑍是标准分数。
  • 𝑋 是数据点的值。
  • 𝜇是数据集的平均值。
  • 𝜎 是数据集的标准差。

Z-Score 的值可以用于判断数据点是否为离群值。一般来说,如果一个数据点的 Z-Score 大于 3 或小于-3,那么它就被认为是离群值。这是因为,根据正态分布的性质,大约 99.7%的数据点(在正态分布中)的 Z-Score 将落在-3 到 3 之间。因此,Z-Score 大于 3 或小于-3 的数据点可以被认为是异常值。

总之,Z-Score 方法是一种简单而强大的离群值检测方法,它通过计算数据点与数据集平均值的标准偏差来衡量每个数据点的异常程度。

1
2
3
4
5
6
7
8
9
from scipy import stats
# Calculate Z-Scores for the '双河口' column
data_sorted['z_score'] = stats.zscore(data_sorted['双河口'])
# Define the threshold for outliers based on Z-Score
z_threshold = 3
outliers_z_score = data_sorted[(data_sorted['z_score'] > z_threshold) | (data_sorted['z_score'] < -z_threshold)]
# Display the outliers based on Z-Score
outliers_z_score[['监测时间', '双河口', 'z_score']]

使用 Z-Score 方法检测到的离群值及其对应的监测时间如下:

  • 2024-04-25 00 时,值为 0.744,Z-Score 为 10.098
  • 2024-05-03 16 时,值为 0.665,Z-Score 为 8.908
  • 2024-05-03 20 时,值为 0.694,Z-Score 为 9.345
  • 2024-05-04 00 时,值为 0.650,Z-Score 为 8.682
  • 2024-05-04 04 时,值为 0.608,Z-Score 为 8.049
  • 2024-05-04 08 时,值为 0.717,Z-Score 为 9.691
  • 2024-05-04 20 时,值为 0.685,Z-Score 为 9.209
  • 2024-05-07 12 时,值为 0.685,Z-Score 为 9.209

使用折线图来展示整个时间序列,并使用红圈标出 Z-Score 方法识别出的离群值。这样可以直观地看到这些离群值在整个时间序列中的分布情况。

1
2
3
4
5
6
7
8
9
10
11
12
plt.figure(figsize=(14, 7))
plt.plot(data_sorted['监测时间'], data_sorted['双河口'], label='双河口 Value')
outliers_z_score.plot(x='监测时间', y='双河口', kind='scatter', color='red', ax=plt.gca(), label='Outliers')
plt.title('双河口 Time Series with Outliers Highlighted')
plt.xlabel('Monitoring Time')
plt.ylabel('双河口 Value')
plt.legend()
plt.grid(True)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

fig3. Z-Score 方法离群值可视化

3σ原则

3σ原则(3 倍标准差原则)是一种用于检测数据集中离群值的经典方法。根据这个原则,如果一个数据点的值大于 𝜇+3𝜎或小于 𝜇−3𝜎(其中 𝜇是数据的平均值,𝜎 是标准差),那么这个数据点就可以被认为是离群值。可以看到 3σ原则与 Z-Score 方法 z_threshold 取 3 意义是一样的,
两者的异同点如下:

  • 相同点: 两者都依赖于数据的均值 (𝜇) 和标准差 (𝜎),并且都是用来识别数据中的极端值或离群点。
  • 不同点: Z-Score 提供了每个数据点相对于分布中心位置的标准化度量,适用于更广泛的分析场景,包括但不限于离群值检测;而 3σ原则是一个更具体的规则,直接用来界定离群值的界限,且主要基于正态分布的特性。
  • 适用性: Z-Score 方法更为灵活,可以用于理解数据点的相对位置,而 3σ原则则是一个快速且直观的筛选工具,尤其适合正态分布数据集的初步离群值识别。

Python 代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 加载CSV文件 
file_path = '/mnt/data/2024-06-05T03-18_export.csv'
df = pd.read_csv(file_path)
# 使用双河口列的数据
data_column = '双河口'
# 计算 mean 和 std
mean = df[data_column].mean()
std = df[data_column].std()

# 应用3σ法则来检测离群值
outliers = abs(df[data_column] - mean) > 3 * std
# 将监测时间列转换为日期时间格式
df['监测时间'] = pd.to_datetime(df['监测时间'])

# 重新绘制时间序列和离群值
plt.figure(figsize=(12, 6))
plt.plot(df['监测时间'], df[data_column], label="时间序列")
plt.plot(df['监测时间'][outliers], df[data_column][outliers], 'ro', label="离群值") # 离群值用红色圆圈标记
plt.axhline(mean + 3 * std, color='r', linestyle='--', label="上界")
plt.axhline(mean - 3 * std, color='r', linestyle='--', label="下界")
plt.legend()
plt.title("时间序列离群值检测")
plt.xlabel("监测时间")
plt.ylabel("双河口值")
plt.tight_layout() # 调整布局
plt.show()
# 计算有多少异常值
outliers.sum()

fig4. 3σ原则离群值可视化

途中可以看出异常值的分布情况,共检测到了 8 个离群值。与 Z-Score 方法更接近。

孤立森林法

孤立森林(Isolation Forest)是一种用于检测离群值的机器学习方法,它适用于高维数据集,并且是一种无监督学习方法,不需要标签数据。但是缺点也很明显,就是配置参数较多,使用不方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from sklearn.ensemble import IsolationForest
def detect_outliers_isolation_forest(data_series):
iso_forest = IsolationForest(n_estimators=100, random_state=42)
outliers = iso_forest.fit_predict(data_series.values.reshape(-1, 1))
return data_series[outliers == -1]
# Apply the Isolation Forest method to detect outliers in the '双河口' column
outliers_isolation_forest = detect_outliers_isolation_forest(data_sorted['双河口'])
# Create a boolean mask for the outliers for plotting
outliers_mask = data_sorted['双河口'].isin(outliers_isolation_forest)
# Plot the time series with outliers highlighted using Isolation Forest
plt.figure(figsize=(14, 7))
plt.plot(data_sorted['监测时间'], data_sorted['双河口'], label='双河口 Value')
# Highlight the outliers with red circles
plt.scatter(data_sorted[outliers_mask]['监测时间'],
data_sorted[outliers_mask]['双河口'],
color='red',
label='Outliers')

plt.title('双河口 Time Series with Outliers Highlighted by Isolation Forest')
plt.xlabel('Monitoring Time')
plt.ylabel('双河口 Value')
plt.legend()
plt.grid(True)
plt.xticks(rotation=45) # Rotate x-axis labels for better readability
plt.tight_layout() # Adjust layout to ensure all labels are displayed
# Show the plot
plt.show()
# Display the outliers detected by Isolation Forest
outliers_isolation_forest

结果。
fig5. 孤立森林法离群值可视化

监测到离群值的数量太多,即使修改参数也很难达到想要的效果。
以下是 IsolationForest 算法中一些重要参数的介绍:

  1. n_estimators:
    • 表示决策树的数量。
    • 增加 n_estimators 的值可以提高模型的稳定性,但同时可能会增加计算成本。
    • 减少 n_estimators 的值可能会使模型对离群值的检测更加“宽容”,从而减少检测到的离群值数量。
  2. max_samples:
    • 表示从数据集中抽取用于训练每棵决策树的最大样本数。
    • 减少 max_samples 的值可能会使模型对离群值的检测更加“宽容”,因为它限制了每棵树看到的数据点的数量。
    • 默认值是‘auto’,表示每个节点都会从所有样本中随机抽取一个子样本。
  3. contamination:
    • 表示数据集中离群值的比例。
    • 默认为 0.1,意味着模型会假设数据集中大约 10% 的数据是离群值。
    • 如果设置为‘auto’,模型会自动估计数据集中的离群值比例。
  4. random_state:
    • 表示随机数生成器的种子,用于确保结果的可重复性。
    • 设置 random_state 为一个固定的值(例如 42),可以确保每次运行模型时,生成的随机数序列是相同的。
      在使用 IsolationForest 算法时,通常需要根据具体的数据集和应用场景来调整这些参数。在实际应用中,可能需要多次尝试不同的参数设置,以找到最适合特定数据集的配置。

总结

Z-Score 方法和 3σ原则确实是离群值检验中广泛应用且效果显著的方法,尤其在处理水质在线监测数据时展现出其独特的优势。这两种方法之所以成为优选,原因可归纳为以下几点:

  1. 离群值检验准确:Z-Score 通过将每个数据点转化为标准分数,能够准确反映其相对于数据集平均值的偏离程度,而 3σ原则利用正态分布的特性,能有效识别出极少数的极端值,确保了检验结果的准确性。
  2. 原理一致且易于理解:二者均基于正态分布的统计理论,原理相通,易于解释。Z-Score 通过标准化处理使数据间的比较标准化,而 3σ原则直接依据正态分布的性质设定离群值边界,逻辑简洁明了。
  3. 实现简便,配置参数少:这两种方法的计算过程相对直接,仅需均值 (𝜇μ) 和标准差 (𝜎σ) 两个基本统计量即可实施,无需复杂的模型训练或调整大量参数,降低了实际操作的技术门槛。
  4. 适应水质数据特性:一个重要前提是水质在线数据往往倾向于呈现正态或近似正态分布,这与自然环境因素的随机波动、监测设备的稳定性能等因素有关。因此,基于正态分布假设的 Z-Score 和 3σ原则能够较好地匹配水质数据的特点,有效识别出因设备故障、污染事件或其他异常情况引起的离群值。

综上所述,Z-Score 方法和 3σ原则凭借其检验准确度高、原理直观、实现便捷以及对水质在线数据特性的良好匹配性,成为了这类数据离群值检验的理想选择,特别是在追求高效实时监控和数据分析的水质管理领域。

感谢看完,如果对你有用请点赞关注哦。


python 离群值检验算法对比实战
https://maoyu92.github.io/2024/06/05/01 时间序列/python 离群值检验算法对比实战/
作者
陈文茂
发布于
2024年6月5日
许可协议