修改时间序列数据中由传感器故障引起的异常值
Modify outliers caused by sensor-failures in timeseries data
我正在处理以 5 分钟为间隔从传感器收集的时间序列数据。不幸的是,在某些情况下,测量值(以瓦特为单位的光伏发电量)突然为 0 或非常高。前后值正确:
我的目标是识别这些“异常值”并(在第二步中)计算前一个值和下一个值的平均值以修正测量值。到目前为止,我已经尝试了两种方法,但收到了很多 'outliers' 这不是测量错误。因此,我正在寻找更好的方法。
尝试 1:使用 IQR 进行经典异常值检测
def updateOutliersIQR(group):
Q1 = group.yield.quantile(0.25)
Q3 = group.yield.quantile(0.75)
IQR = Q3 - Q1
outliers = (group.yield < (Q1 - 1.5 * IQR)) | (group.yield > (Q3 + 1.5 * IQR))
print(outliers[outliers == True])
# calling the function on a per-day level
df.groupby(df.index.date).apply(updateOutliers)
尝试2:核密度估计Source
def updateOutliersKDE(group):
a = 0.9
r = group.yield.rolling(3, min_periods=1, win_type='parzen').sum()
n = r.max()
outliers = (r > n*a)
print(outliers[outliers == True])
# calling the function on a per-day level
df.groupby(df.index.date).apply(updateOutliers)
尝试 3:中值滤波器
(由 Jonnor 建议)
def median_filter(num_std=3):
def _median_filter(x):
_median = np.median(x)
_std = np.std(x)
s = x[-3]
if (s >= _median - num_std * _std and s <= _median + num_std * _std):
return s
else:
return _median
return _median_filter
# calling the function
df.yield.rolling(5, center=True).apply(median_filter(2), raw=True)
编辑:使用 try 3 和 window 5 和 std 3,它最终捕捉到大量异常值,但也会降低其他(非故障)传感器测量的准确性:
是否有更好的方法来检测所描述的 'outliers' 或在具有 偶尔 传感器测量问题的时间序列数据中执行平滑?
你的异常值在
这个意义上是异常的
- 数值与其周围的数值偏差很大
- 从一个时间步到另一个时间步的值变化非常快
因此,需要的是一个过滤器,它可以查看短时间上下文以过滤掉这些。
最简单和最有效的方法之一是 median filter。
filtered = pandas.rolling_median(df, window=5)
window越长,滤镜越强
另一种方法是使用低通滤波器。虽然设置适当的截止频率可能更难,但它会给信号带来平滑度。
当然也可以创建更多自定义过滤器。例如,计算一阶差分,拒绝高于某个阈值的变化。您可以绘制差异直方图以确定阈值。将这些标记为缺失 (NaN),然后使用 median/mean.
估算缺失值
如果您的目标是异常检测,您还可以使用自动编码器。我希望光伏输出具有非常强劲的每日模式。因此,在日常序列上对其进行训练应该效果很好(前提是您有足够的数据)。这比简单的过滤器复杂得多,但具有能够检测许多其他类型异常的优势,而不仅仅是此处识别的模式。
我正在处理以 5 分钟为间隔从传感器收集的时间序列数据。不幸的是,在某些情况下,测量值(以瓦特为单位的光伏发电量)突然为 0 或非常高。前后值正确:
我的目标是识别这些“异常值”并(在第二步中)计算前一个值和下一个值的平均值以修正测量值。到目前为止,我已经尝试了两种方法,但收到了很多 'outliers' 这不是测量错误。因此,我正在寻找更好的方法。
尝试 1:使用 IQR 进行经典异常值检测
def updateOutliersIQR(group):
Q1 = group.yield.quantile(0.25)
Q3 = group.yield.quantile(0.75)
IQR = Q3 - Q1
outliers = (group.yield < (Q1 - 1.5 * IQR)) | (group.yield > (Q3 + 1.5 * IQR))
print(outliers[outliers == True])
# calling the function on a per-day level
df.groupby(df.index.date).apply(updateOutliers)
尝试2:核密度估计Source
def updateOutliersKDE(group):
a = 0.9
r = group.yield.rolling(3, min_periods=1, win_type='parzen').sum()
n = r.max()
outliers = (r > n*a)
print(outliers[outliers == True])
# calling the function on a per-day level
df.groupby(df.index.date).apply(updateOutliers)
尝试 3:中值滤波器
def median_filter(num_std=3):
def _median_filter(x):
_median = np.median(x)
_std = np.std(x)
s = x[-3]
if (s >= _median - num_std * _std and s <= _median + num_std * _std):
return s
else:
return _median
return _median_filter
# calling the function
df.yield.rolling(5, center=True).apply(median_filter(2), raw=True)
编辑:使用 try 3 和 window 5 和 std 3,它最终捕捉到大量异常值,但也会降低其他(非故障)传感器测量的准确性:
是否有更好的方法来检测所描述的 'outliers' 或在具有 偶尔 传感器测量问题的时间序列数据中执行平滑?
你的异常值在
这个意义上是异常的- 数值与其周围的数值偏差很大
- 从一个时间步到另一个时间步的值变化非常快
因此,需要的是一个过滤器,它可以查看短时间上下文以过滤掉这些。
最简单和最有效的方法之一是 median filter。
filtered = pandas.rolling_median(df, window=5)
window越长,滤镜越强
另一种方法是使用低通滤波器。虽然设置适当的截止频率可能更难,但它会给信号带来平滑度。
当然也可以创建更多自定义过滤器。例如,计算一阶差分,拒绝高于某个阈值的变化。您可以绘制差异直方图以确定阈值。将这些标记为缺失 (NaN),然后使用 median/mean.
估算缺失值如果您的目标是异常检测,您还可以使用自动编码器。我希望光伏输出具有非常强劲的每日模式。因此,在日常序列上对其进行训练应该效果很好(前提是您有足够的数据)。这比简单的过滤器复杂得多,但具有能够检测许多其他类型异常的优势,而不仅仅是此处识别的模式。