1 引言
我们在今天你异常了吗这篇文章中曾介绍过KDD Cup2021的时间序列异常检测竞赛。竞赛要求我们在250个时间序列中找出每个序列中的唯一异常点所在区间。
最近,赛事公布了最终高分团队的解决方案[1]。扶我起来我还能学,今天就让我们一起来看一下这些高分方案吧。
2 背景介绍
第一名是来自深兰科技(DeepBlue Technology)的团队。这家公司有一些AI机器人的产品,也很热衷于参加各类竞赛。它们的解决方案是:TsaDetect: An efficient and flexible time series anomaly detection framework。
总的来说,他们集成了几种时间序列异常检测的算法,得到了不错的效果。
3 寻找周期
由于本次竞赛提供的时间序列都是很规律、周期很明显的序列,其中的异常点,其实更可以被称为异常周期。如何找到时间序列的周期成为了我们需要解决的第一个问题。
我们自己在竞赛中,采用了傅里叶变换的方式寻找周期。那么,什么是傅里叶变换呢?
首先,傅里叶级数的概念是说任何周期函数都可以分解成不同周期(或者说不同频率,频率等于周期的倒数)的正弦函数相加。那么这些不同频率就构成了这个序列的频谱。横轴为频率,纵轴为振幅。
一般来说,在频谱中,振幅最大的点的频率就是原始序列的频率,因为此时这个频率以及振幅的正弦函数包括了原始序列的峰谷值。我们可以通过这种方式确定原始序列的周期。
我们可以通过以下代码,在Python中绘制序列的频谱图。
import scipy
import matplotlib.pyplot as plt
X = scipy.fft.fft(this.values.reshape((-1,))) #傅里叶变换后的值
freqs = scipy.fft.fftfreq(len(this.values),1)
fig=plt.figure(figsize=(20,12))
plt.plot(freqs,np.abs(X))#np.abs是模
我们使用竞赛提供的如下序列试一试,
现实很骨感,通过这种方式并不能很好地找到原始序列的周期。
可以说傅里叶变换寻找周期是一种传统的寻找周期的方式,但在某些序列中并不适合。
下面,我们来看看高分方案是怎么做的。
给定一个周期长度(gap distance),找到每个周期的峰值,然后计算峰值之间的距离(peak intervals)。最终的score等于std(peak intervals)/sqrt(gap distance)。通过遍历不同的周期长度,得到最小的score,此时的周期长度即为序列的周期。
从直观上来讲,峰值之间的距离越稳定,周期长度越大(偏好更大尺度的周期),此时的周期越可能为原始序列的周期。可以看到这种方式也挺科学的。
4 异常检测算法
找到周期之后,下一步就是使用不同的时间序列异常检测算法。高分方案主要使用了傅里叶滤波算法,上篇文章介绍过的Matrix Profile算法,基于回归的算法等。
4.1 傅里叶滤波算法
傅里叶滤波算法是指将原始序列做傅里叶变换后,在频域中去除某些频率的成分,然后做傅里叶逆变换重新转换为时域的序列。最终和原始序列做差,得到残差,从而找到异常点。高分方案采用了高通、低通滤波以及平滑的方式,都可以成功地得到异常点所在位置。值得一提的是,这个序列的异常点用人眼其实很难识别出来。
4.2 Matrix Profile算法
Matrix Profile算法在上篇中已经详细地介绍过,具体的思想是计算每个区间和其他区间的欧式距离,得到异常区间。
4.3 基于回归的算法
基于回归的算法是指用模型做一个回归问题,来预测某个点的值。然后在测试集用预测值和真实值做差,得到残差,残差最大的点即为异常点。高分方案尝试了不同的算法,最终选择的是GBDT和CNN算法。值得一提的是,X可以取预测值左右两边的数据。同时异常点附近可能都是异常的,为此,X和预测值之间留了一点gap。
5 模型集成
有了一些不错的基础模型后,高分方案最终采用了加权集成的方式。在权重设定方面,他们采用了每个模型的置信度。
每个模型的置信度的计算为,最大的残差/第二大的残差。直观上理解,如果这个值越大,说明这个模型对最大的残差所在的点是异常点更为自信。这在只有一个异常点的任务设定中是适用的。
6 小结
可以看到高分方案其实也是采用了一些较为传统的时间序列异常检测算法。但值得学习的是,方案很注重每个环节的细节,无论是最开始周期长度的确定,还是选择不同的有效算法,以及最后加权权重的确定,高分团队都有自己的思考和经验,值得我们学习。
参考资料