时间序列分析|异常值检测
原创
©著作权归作者所有:来自51CTO博客作者mb60b8e4a00e141的原创作品,请联系作者获取转载授权,否则将追究法律责任
目录
前言
很多数据算法工程师在做时间序列分析的时候都会去做时序的平稳性检测,从而获得ARIMA(p,d,q)中的参数d,然而, 还有一项工作比平稳性检测来得更前置,那就是时序的异常值检测。
异常分类
一个时间序列里可能包含各种各样的异常值,异常片段,归纳起来主要有2种类型的异常值检测。
所谓离群多指离开其他同伴而孤立,故离群值检测就是从时序里面挑出那些众叛亲离的观测点,那些远离其他大多数观测值的观测点,离群值检测常常是把整个时序作为训练对象,这其中可能包含异常值,对整个时序进行无监督训练,得到一个异常值检测器,那些偏离大多数的观测点便是离群值。
异常值检测常用一段被认为是“正常”的,不会受到异常值的污染的时序进行半监督训练,得到一个检测器,然后将这个检测器运用到新的数据上,假设正常的训练数据符合某个分布,而新的观测值不符合这个分布的则可以认为是异常值。
实践案例
我们以air_passenger数据集为对象进行auto_arima调参,先来看一下原数据长什么样子并对其进行可视化
import datetime
import time
import tsod
import pandas as pd
import pmdarima as pm
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
from sklearn.metrics import mean_absolute_error
from tsod import RangeDetector,GradientDetector,RollingStandardDeviationDetector,DiffDetector
air_passenger = pd.read_csv(r"D:\项目\时间序列\air_passenger.csv") #读取数据
air_passenger['month'] = pd.to_datetime(air_passenger['month']) #datetime格式化
air_passenger.set_index("month", inplace = True) #设置time列为索引列
ts = air_passenger['passenger'] #乘客时序
print(ts.head(5)) #查看头5行
print(ts.tail(5)) #查看尾5行
fig = plt.figure(figsize = (6,4)) #新建6*4的画布
ts.plot(label = 'origin ts') #原时序图
plt.xticks(rotation =45) #横坐标逆时针倾斜45度
plt.legend()
plt.show()
范围检测可以根据业务经验和前置的观测结果给出一个范围,超过这个范围的一律被认为异常值,这对那些有额定值,如上座率等时序比较友好,但是对有趋势变化的时序不太友好。
range_dector = RangeDetector(min_value=np.min(ts)*1.1, max_value=np.max(ts)*0.9) #以最近20%样例最大值最小值为范围
res = range_dector.detect(ts)
plt.figure(figsize=(16,4))
plt.plot(ts, label = 'origin ts') #原序列图
plt.plot(ts[res], 'ro', label='anomaly') #给异常值描红点
plt.xticks(rotation = 45)
plt.legend()
plt.title("RangeDetector")
plt.show()
ts = ts.drop(labels=ts[res].index) #过滤掉极大极小值的时序
print("范围检测后长度", len(ts))
梯度检测主要是指那些陡降陡升的观测值
g_dector = GradientDetector().fit(ts[-14:]) #以近14期为训练集训练异常梯度检测
res = g_dector.detect(ts)
plt.figure(figsize=(16,4))
plt.plot(ts, label = 'origin ts') #原序列图
plt.plot(ts[res], 'ro', label='anomaly') #给异常值描红点
plt.xticks(rotation = 45)
plt.legend()
plt.title("GradientDetector")
plt.show()
ts = ts.drop(labels=ts[res].index)
print("异方差检测后长度",len(ts))
- RollingStandardDeviationDetector
滚动标准差检测是以某个固定的滚动窗口而进行标准差的检测
rstd_dector = RollingStandardDeviationDetector(window_size=7, center=True).fit(ts[-14:]) #滚动标准差异常检测,最近20%作为时序作为训练集
res = rstd_dector.detect(ts) #二进制
plt.figure(figsize=(16,4))
plt.plot(ts, label = 'origin ts') #原序列图
plt.plot(ts[res], 'ro', label='anomaly') #给异常值描红点
plt.xticks(rotation = 45)
plt.legend()
plt.title("RollingStandardDeviationDetector")
plt.show()
ts = ts.drop(labels=ts[res].index) #过滤掉异常的时序
print("滚动标准差检测后长度", len(ts))
- DiffDetector
差分检测是对那些异常差分进行检测
diff_dector = DiffDetector().fit(ts[-14:]) #差分异常检测
res = diff_dector.detect(ts) #二进制
plt.figure(figsize=(16,4))
plt.plot(ts, label = 'origin ts') #原序列图
plt.plot(ts[res], 'ro', label='anomaly') #给异常值描红点
plt.xticks(rotation = 45)
plt.legend()
plt.title("DiffDetector")
plt.show()
ts = ts.drop(labels=ts[res].index) #过滤掉异常的时序
print("差分检测后长度",len(ts))
参考文献
2,tsod,时序异常检测