時(shí)序預(yù)測(cè)競(jìng)賽之異常檢測(cè)算法綜述
異常分類(lèi)
時(shí)間序列的異常檢測(cè)問(wèn)題通常表示為相對(duì)于某些標(biāo)準(zhǔn)信號(hào)或常見(jiàn)信號(hào)的離群點(diǎn)。雖然有很多的異常類(lèi)型,但是我們只關(guān)注業(yè)務(wù)角度中最重要的類(lèi)型,比如意外的峰值、下降、趨勢(shì)變化以及等級(jí)轉(zhuǎn)換(level shifts)。
常見(jiàn)的異常有如下幾種:
革新性異常:innovational outlier (IO),造成離群點(diǎn)干擾不僅作用于X(T),而且影響T時(shí)刻以后序列的所有觀察值。
附加性異常:additive outlier (AO),造成這種離群點(diǎn)的干擾,只影響該干擾發(fā)生的那一個(gè)時(shí)刻T上的序列值,而不影響該時(shí)刻以后的序列值。
水平移位異常:level shift (LS),造成這種離群點(diǎn)的干擾是在某一時(shí)刻T,系統(tǒng)的結(jié)構(gòu)發(fā)生了變化,并持續(xù)影響T時(shí)刻以后的所有行為,在數(shù)列上往往表現(xiàn)出T時(shí)刻前后的序列均值發(fā)生水平位移。
暫時(shí)變更異常temporary change (TC):造成這種離群點(diǎn)的干擾是在T時(shí)刻干擾發(fā)生時(shí)具有一定初始效應(yīng),以后隨時(shí)間根據(jù)衰減因子的大小呈指數(shù)衰減。
上面的解釋可能不太容易理解,我們結(jié)合圖片來(lái)看一下:

通常,異常檢測(cè)算法應(yīng)該將每個(gè)時(shí)間點(diǎn)標(biāo)記為異常/非異常,或者預(yù)測(cè)某個(gè)點(diǎn)的信號(hào),并衡量這個(gè)點(diǎn)的真實(shí)值與預(yù)測(cè)值的差值是否足夠大,從而將其視為異常。使用后面的方法,你將能夠得到一個(gè)可視化的置信區(qū)間,這有助于理解為什么會(huì)出現(xiàn)異常并進(jìn)行驗(yàn)證。
常見(jiàn)異常檢測(cè)方法
從分類(lèi)看,當(dāng)前發(fā)展階段的時(shí)序異常檢測(cè)算法和模型可以分為一下幾類(lèi):

統(tǒng)計(jì)模型:優(yōu)點(diǎn)是復(fù)雜度低,計(jì)算速度快,泛化能力強(qiáng)悍。因?yàn)闆](méi)有訓(xùn)練過(guò)程,即使沒(méi)有前期的數(shù)據(jù)積累,也可以快速的投入生產(chǎn)使用。缺點(diǎn)是準(zhǔn)確率一般。但是這個(gè)其實(shí)是看場(chǎng)景的,并且也有簡(jiǎn)單的方法來(lái)提高業(yè)務(wù)層面的準(zhǔn)確率。這個(gè)后面會(huì)提到。
機(jī)器學(xué)習(xí)模型:魯棒性較好,準(zhǔn)確率較高。需要訓(xùn)練模型,泛化能力一般。
深度學(xué)習(xí)模型:普遍需要喂大量的數(shù)據(jù),計(jì)算復(fù)雜度高。整體看,準(zhǔn)確性高,尤其是近段時(shí)間,強(qiáng)化學(xué)習(xí)的引入,進(jìn)一步鞏固其準(zhǔn)確性方面的領(lǐng)先優(yōu)勢(shì)。
3-Sigma
3-Sigma原則又稱為拉依達(dá)準(zhǔn)則,該準(zhǔn)則定義如下:假設(shè)一組檢測(cè)數(shù)據(jù)只含有隨機(jī)誤差,對(duì)原始數(shù)據(jù)進(jìn)行計(jì)算處理得到標(biāo)準(zhǔn)差,然后按一定的概率確定一個(gè)區(qū)間,認(rèn)為誤差超過(guò)這個(gè)區(qū)間的就屬于異常值。

使用3-Sigma的前提是數(shù)據(jù)服從正態(tài)分布,滿足這個(gè)條件之后,在3-Sigma范圍
import numpy as npdef three_sigma(df_col):'''df_col:DataFrame數(shù)據(jù)的某一列'''rule = (df_col.mean() - 3 * df_col.std() > df_col) | (df_col.mean() + 3 * df_col.std() < df_col)index = np.arange(df_col.shape[0])[rule]out_range = df_col.iloc[index]return out_range
對(duì)于異常值檢測(cè)出來(lái)的結(jié)果,有多種處理方式,如果是時(shí)間序列中的值,那么我們可以認(rèn)為這個(gè)時(shí)刻的操作屬于異常的;如果是將異常值檢測(cè)用于數(shù)據(jù)預(yù)處理階段,處理方法有以下四種:
刪除帶有異常值的數(shù)據(jù);
將異常值視為缺失值,交給缺失值處理方法來(lái)處理;
用平均值進(jìn)行修正;
當(dāng)然我們也可以選擇不處理。
Grubbs測(cè)試
Grubbs’Test為一種假設(shè)檢驗(yàn)的方法,常被用來(lái)檢驗(yàn)服從正太分布的單變量數(shù)據(jù)集(univariate data set)Y 中的單個(gè)異常值。若有異常值,則其必為數(shù)據(jù)集中的最大值或最小值。原假設(shè)與備擇假設(shè)如下:
H0: 數(shù)據(jù)集中沒(méi)有異常值
H1: 數(shù)據(jù)集中有一個(gè)異常值
使用Grubbs測(cè)試需要總體是正態(tài)分布的。算法流程:
樣本從小到大排序
求樣本的mean和dev
計(jì)算min/max與mean的差距,更大的那個(gè)為可疑值
求可疑值的z-score (standard score),如果大于Grubbs臨界值,那么就是outlier
Grubbs臨界值可以查表得到,它由兩個(gè)值決定:檢出水平
from outliers import smirnov_grubbs as grubbsprint(grubbs.test([8, 9, 10, 1, 9], alpha=0.05))print(grubbs.min_test_outliers([8, 9, 10, 1, 9], alpha=0.05))print(grubbs.max_test_outliers([8, 9, 10, 1, 9], alpha=0.05))print(grubbs.max_test_indices([8, 9, 10, 50, 9], alpha=0.05))
S-ESD與S-H-ESD
鑒于時(shí)間序列數(shù)據(jù)具有周期性(seasonal)、趨勢(shì)性(trend),異常檢測(cè)時(shí)不能作為孤立的樣本點(diǎn)處理;故而Twitter的工程師提出了S- ESD (Seasonal ESD)與S-H-ESD (Seasonal Hybrid ESD)算法,將ESD擴(kuò)展到時(shí)間序列數(shù)據(jù)。
STL分解
STL (Seasonal-Trend decomposition procedure based on Loess) 為時(shí)序分解中一種常見(jiàn)的算法,基于LOESS將某時(shí)刻的數(shù)據(jù)Yv分解為趨勢(shì)分量(trend component)、季節(jié)性分量(seasonal component)和殘差(remainder component):


?
由上到下依次為:原始時(shí)間序列和使用 STL 分解得到的季節(jié)變化部分、趨勢(shì)變化部分以及殘差部分。
STL分為內(nèi)循環(huán)(inner loop)與外循環(huán)(outer loop),其中內(nèi)循環(huán)主要做了趨勢(shì)擬合與周期分量的計(jì)算。假定T(k)v、Sv(k)為內(nèi)循環(huán)中第k-1次pass結(jié)束時(shí)的趨勢(shì)分量、周期分量,初始時(shí)T(k)v=0;并有以下參數(shù):
n(i)內(nèi)層循環(huán)數(shù)
n(o)外層循環(huán)數(shù)
n(p)為一個(gè)周期的樣本數(shù)
n(s)為Step 2中LOESS平滑參數(shù)
n(l)為Step 3中LOESS平滑參數(shù)
n(t)為Step 6中LOESS平滑參數(shù)
每個(gè)周期相同位置的樣本點(diǎn)組成一個(gè)子序列(subseries),容易知道這樣的子序列共有共有n(p)個(gè),我們稱其為cycle-subseries。
Python的statsmodels實(shí)現(xiàn)了一個(gè)簡(jiǎn)單版的時(shí)序分解,通過(guò)加權(quán)滑動(dòng)平均提取趨勢(shì)分量,然后對(duì)cycle-subseries每個(gè)時(shí)間點(diǎn)數(shù)據(jù)求平均組成周期分量:
使用示例:
import numpy as npimport pandas as pdfrom statsmodels.tsa.seasonal import seasonal_decomposeimport matplotlib.pyplot as plt# Generate some datanp.random.seed(0)n = 1500dates = np.array('2019-01-01', dtype=np.datetime64) + np.arange(n)data = 12 * np.sin(2 * np.pi * np.arange(n) / 365) + np.random.normal(12, 2, 1500)df = pd.DataFrame({'data': data}, index=dates)# Reproduce the example in OPseasonal_decompose(df, model='additive', period=1).plot()plt.show()
S-ESD
STL將時(shí)間序列數(shù)據(jù)分解為趨勢(shì)分量、周期分量和余項(xiàng)分量。想當(dāng)然的解法——將ESD運(yùn)用于STL分解后的余項(xiàng)分量中,即可得到時(shí)間序列上的異常點(diǎn)。但是,我們會(huì)發(fā)現(xiàn)在余項(xiàng)分量中存在著部分假異常點(diǎn)(spurious anomalies)。如下圖所示:

在紅色矩形方框中,向下突起點(diǎn)被誤報(bào)為異常點(diǎn)。為了解決這種假陽(yáng)性降低準(zhǔn)確率的問(wèn)題,S-ESD算法用中位數(shù)(median)替換掉趨勢(shì)分量;
使用示例:
import numpy as npimport sesdts = np.random.random(100)# Introduce artificial anomaliests[14] = 9ts[83] = 10outliers_indices = sesd.seasonal_esd(ts, periodicity=20, hybrid=True, max_anomalies=2)for idx in outliers_indices:print(f'Anomaly index: {idx}, anomaly value: {ts[idx]}')
移動(dòng)平均/加權(quán)移動(dòng)平均/指數(shù)加權(quán)移動(dòng)平均
移動(dòng)平均 moving average
給定一個(gè)時(shí)間序列和窗口長(zhǎng)度N,moving average等于當(dāng)前data point之前N個(gè)點(diǎn)(包括當(dāng)前點(diǎn))的平均值。不停地移動(dòng)這個(gè)窗口,就得到移動(dòng)平均曲線。
累加移動(dòng)平均 cumulative moving average
設(shè)

加權(quán)移動(dòng)平均 weighted moving average
加權(quán)移動(dòng)平均值是先前w個(gè)數(shù)據(jù)的加權(quán)平均值

指數(shù)加權(quán)移動(dòng)平均 exponential weighted moving average
指數(shù)移動(dòng)與移動(dòng)平均有些不同:
并沒(méi)有時(shí)間窗口,用的是從時(shí)間序列第一個(gè)data point到當(dāng)前data point之間的所有點(diǎn)。
每個(gè)data point的權(quán)重不同,離當(dāng)前時(shí)間點(diǎn)越近的點(diǎn)的權(quán)重越大,歷史時(shí)間點(diǎn)的權(quán)重隨著離當(dāng)前時(shí)間點(diǎn)的距離呈指數(shù)衰減,從當(dāng)前data point往前的data point,權(quán)重依次為

該算法可以檢測(cè)一個(gè)異常較短時(shí)間后發(fā)生另外一個(gè)異常的情況,異常持續(xù)一段時(shí)間后可能被判定為正常。
ARIMA 模型
自回歸移動(dòng)平均模型(ARIMA)是一種設(shè)計(jì)上非常簡(jiǎn)單的方法,但其效果足夠強(qiáng)大,可以預(yù)測(cè)信號(hào)并發(fā)現(xiàn)其中的異常。該方法的思路是從過(guò)去的幾個(gè)數(shù)據(jù)點(diǎn)來(lái)生成下一個(gè)數(shù)據(jù)點(diǎn)的預(yù)測(cè),在過(guò)程中添加一些隨機(jī)變量(通常是添加白噪聲)。以此類(lèi)推,預(yù)測(cè)得到的數(shù)據(jù)點(diǎn)可以用來(lái)生成新的預(yù)測(cè)。很明顯:它會(huì)使得后續(xù)預(yù)測(cè)信號(hào)數(shù)據(jù)更平滑。使用這種方法最困難的部分是選擇差異數(shù)量、自回歸數(shù)量和預(yù)測(cè)誤差系數(shù)。另一個(gè)障礙是信號(hào)經(jīng)過(guò)差分后應(yīng)該是固定的。也就是說(shuō),這意味著信號(hào)不應(yīng)該依賴于時(shí)間,這是一個(gè)比較顯著的限制。

異常檢測(cè)是利用離群點(diǎn)來(lái)建立一個(gè)經(jīng)過(guò)調(diào)整的信號(hào)模型,然后利用t-統(tǒng)計(jì)量來(lái)檢驗(yàn)該模型是否比原模型能更好的擬合數(shù)據(jù)。

在這種情況下,你可以找到適合信號(hào)的 ARIMA 模型,它可以檢測(cè)出所有類(lèi)型的異常。
神經(jīng)網(wǎng)絡(luò)
與CART方法一樣,神經(jīng)網(wǎng)絡(luò)有兩種應(yīng)用方式:監(jiān)督學(xué)習(xí)和無(wú)監(jiān)督學(xué)習(xí)。我們處理的數(shù)據(jù)是時(shí)間序列,所以最適合的神經(jīng)網(wǎng)絡(luò)類(lèi)型是 LSTM。如果構(gòu)建得當(dāng),這種循環(huán)神經(jīng)網(wǎng)絡(luò)將可以建模實(shí)現(xiàn)時(shí)間序列中最復(fù)雜的依賴關(guān)系,包括高級(jí)的季節(jié)性依賴關(guān)系。如果存在多個(gè)時(shí)間序列相互耦合,該方法也非常有用。該領(lǐng)域還在研究中,可以參考這里,構(gòu)建時(shí)序模型需要大量的工作。構(gòu)建成功完成后,就可能在精確度方面取得優(yōu)異的成績(jī)。
