使用 Hampel 进行离群点检测


在时间序列数据分析领域,识别和处理异常点是至关重要的任务。异常点或离群点是明显偏离预期模式的数据点,可能表明存在错误、欺诈或有价值的见解。

应对这一挑战的一种有效技术是汉普尔过滤器(Hampel Filter)。

在本文中,我们将利用 hampel 库[1],探讨如何应用这种离群点检测技术。

解密汉普尔滤波法

汉普尔滤波法(Hampel filter)是检测和处理时间序列数据中离群值的一种稳健的方法。它依赖于中位数绝对偏差(MAD)[2] 并采用滚动窗口来识别离群值。MAD 是一种稳健的数据离散度量,以偏离中值的绝对偏差的中值计算。推荐关注@众号数据STUDIO 更多优质好文~

配置汉普尔滤波器涉及两个参数:

  • 窗口大小:该参数决定用于评估每个数据点的移动窗口的大小。它基本上定义了我们查找异常值的范围。
  • 阈值:仔细选择阈值对于避免触发有价值数据的异常值检测至关重要。

Hampel与 Python 的结合

要在 Python 项目中使用 Hampel 过滤器,首先要通过 pip 安装软件包:

pip install hampel

然后在 Python 脚本中导入它:

from hampel import hampel

hampel函数有三个可用参数:

  • data 要过滤的输入一维数据(pandas.Series 或 numpy.ndarray)。
  • window_size(可选):用于离群点检测的移动窗口大小(默认为 5)。
  • n_sigma(可选):异常值检测的标准差个数(默认值为 3.0)。它与上一节讨论的阈值概念有关,即通过调整该参数,我们可以对可能的异常值有或多或少的容忍度

现在,生成合成数据,在其中的 20、40、60、80 位置引入四个离群值(当然,在实际情况中问题不会这么简单,但这是一个很好的例子,可以了解 hampel 如何工作 )。

import matplotlib.pyplot as plt
import numpy as np
from hampel import hampel

original_data = np.sin(np.linspace(010100)) + np.random.normal(00.1100)

# Add outliers to the original data
for index, value in zip([20406080], [2.0-1.92.1-0.5]):
    original_data[index] = value

绘制 original_data 时,会看到如下内容:

要直观地检测出我们引入的四个离群值非常容易,看看Hampel 是否也可以

result = hampel(original_data, window_size=10)

函数 hampel 返回一个 Result 数据类型,它包含以下属性:

  • filtered_data:已替换异常值的数据。
  • outlier_indices: 检测到的异常值的指数。
  • medians:滑动窗口内的中值。
  • median_absolute_deviations:滑动窗口内的绝对偏差中值 (MAD)。
  • thresholds:异常值检测的阈值。

可以像这样简单地访问这些属性:

filtered_data = result.filtered_data
outlier_indices = result.outlier_indices
medians = result.medians
mad_values = result.median_absolute_deviations
thresholds = result.thresholds

例如,如果我们现在打印 filtered_data ,我们就会得到一个经过清理的 original_data 版本,即没有异常值的版本。

Hampel 设法删除了之前添加的异常值!

不过,可以利用 hampel提供的信息,设计出个更有趣的图表。在我的例子中,我会把个异常值画成红点,还会个灰色带,代表算法在每个点使用的阈值。此外,我还会在第一个图的下方创建另一个图,显示过滤后的数据

使用 matplotlib 可以非常轻松地完成这项工作:

fig, axes = plt.subplots(21, figsize=(86))
# Plot the original data with estimated standard deviations in the first subplot
axes[0].plot(original_data, label='Original Data', color='b')
axes[0].fill_between(range(len(original_data)), medians + thresholds,
                     medians - thresholds, color='gray', alpha=0.5, label='Median +- Threshold')
axes[0].set_xlabel('Data Point')
axes[0].set_ylabel('Value')
axes[0].set_title('Original Data with Bands representing Upper and Lower limits')

for i in outlier_indices:
    axes[0].plot(i, original_data[i], 'ro', markersize=5)  # Mark as red

axes[0].legend()
# Plot the filtered data in the second subplot
axes[1].plot(filtered_data, label='Filtered Data', color='g')
axes[1].set_xlabel('Data Point')
axes[1].set_ylabel('Value')
axes[1].set_title('Filtered Data')
axes[1].legend()

# Adjust spacing between subplots
plt.tight_layout()

# Show the plots
plt.show()

运行该代码段后,应该会看到这样一幅美丽的图画

万一你想复制粘贴完整的 Python 脚本 …👇👇 👇

import matplotlib.pyplot as plt
import numpy as np
from hampel import hampel
# 推荐关注@公众号:数据STUDIO 更多优质推文定期推送
original_data = np.sin(np.linspace(010100)) + np.random.normal(00.1100)

# Add outliers to the original data
for index, value in zip([20406080], [2.0-1.92.1-0.5]):
    original_data[index] = value

result = hampel(original_data, window_size=10)

filtered_data = result.filtered_data
outlier_indices = result.outlier_indices
medians = result.medians
thresholds = result.thresholds

fig, axes = plt.subplots(21, figsize=(86))

# Plot the original data with estimated standard deviations in the first subplot
axes[0].plot(original_data, label='Original Data', color='b')
axes[0].fill_between(range(len(original_data)), medians + thresholds,
                     medians - thresholds, color='gray', alpha=0.5, label='Median +- Threshold')
axes[0].set_xlabel('Data Point')
axes[0].set_ylabel('Value')
axes[0].set_title('Original Data with Bands representing Upper and Lower limits')

for i in outlier_indices:
    axes[0].plot(i, original_data[i], 'ro', markersize=5)  # Mark as red

axes[0].legend()

# Plot the filtered data in the second subplot
axes[1].plot(filtered_data, label='Filtered Data', color='g')
axes[1].set_xlabel('Data Point')
axes[1].set_ylabel('Value')
axes[1].set_title('Filtered Data')
axes[1].legend()

# Adjust spacing between subplots
plt.tight_layout()

# Show the plots
plt.show()

参考资料

[1]

hampel 库: https://github.com/MichaelisTrofficus/hampel_filter

[2]

中位数绝对偏差(MAD): https://en.wikipedia.org/wiki/Median_absolute_deviation


🏴‍☠️宝藏级🏴‍☠️ 原创公众号『数据STUDIO』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括可戳👉 PythonMySQL数据分析数据可视化机器学习与数据挖掘爬虫 等,从入门到进阶!

长按👇关注- 数据STUDIO -设为星标,干货速递

相关推荐

  • LLM推理技术之StreamingLLM:如何拥有无限长生成能力
  • 爆了!金融界也开始卷 AI 了...
  • 没有数据搞不成 ChatGPT,六大技术专家教你如何用好数据!
  • B 站广州研发工作室宣布解散;OpenAI 廉价版 GPT-4 夭折;微软推出云原生应用程序平台 Radius|极客头条
  • 面试官:如何判断两个数组的内容是否相等
  • 编写 if 时尽量不要带 else
  • java 使用mongoTemplate查询指定字段的值
  • shutdown() 、 shutdownNow() 、 awaitTermination() 区别
  • 如何使用 Promise 去控制并发请求?
  • 使用一致性哈希让数据均匀分布
  • 如何优雅的创建线程?
  • 一站式图计算平台 GraphScope,支持图分析、图的交互式查询和图学习任务
  • 使用React和Node构建实时协作的白板应用
  • 聊一聊 ReentrantLock 类的一些玩法
  • 大视觉语言模型基准数据集ReForm-Eval:新瓶装旧酒,给旧有的基准数据集换个形式就能用来评估新的大视觉语言模型
  • GPT-4V被曝离谱bug:突然执行神秘代码,空白图片读出打折信息,网友们都看呆了
  • 时序LightTS: 轻量采样的MLP结构网络
  • [开源]MIT开源协议,开箱即用的 layui vue 3.0 企业级前端模板
  • Linux 内核崩了,只因拔掉罗技的 USB 接收器.....
  • 开源联合、聚力共赢丨2023 CCF中国开源大会会议通知