博客專欄

EEPW首頁 > 博客 > 14種異常檢測(cè)方法匯總(附代碼)!(2)

14種異常檢測(cè)方法匯總(附代碼)?。?)

發(fā)布人:計(jì)算機(jī)視覺工坊 時(shí)間:2022-09-26 來源:工程師 發(fā)布文章
五、基于樹的方法1. Isolation Forest (iForest)

資料來源:

[8] 異常檢測(cè)算法 -- 孤立森林(Isolation Forest)剖析 - 風(fēng)控大魚,知乎:https://zhuanlan.zhihu.com/p/74508141[9] 孤立森林(isolation Forest)-一個(gè)通過瞎幾把亂分進(jìn)行異常檢測(cè)的算法 - 小伍哥聊風(fēng)控,知乎:https://zhuanlan.zhihu.com/p/484495545[10] 孤立森林閱讀 - Mark_Aussie,博文:https://blog.csdn.net/MarkAustralia/article/details/120181899

孤立森林中的 “孤立” (isolation) 指的是 “把異常點(diǎn)從所有樣本中孤立出來”,論文中的原文是 “separating an instance from the rest of the instances”。我們用一個(gè)隨機(jī)超平面對(duì)一個(gè)數(shù)據(jù)空間進(jìn)行切割,切一次可以生成兩個(gè)子空間。接下來,我們?cè)倮^續(xù)隨機(jī)選取超平面,來切割第一步得到的兩個(gè)子空間,以此循環(huán)下去,直到每子空間里面只包含一個(gè)數(shù)據(jù)點(diǎn)為止。我們可以發(fā)現(xiàn),那些密度很高的簇要被切很多次才會(huì)停止切割,即每個(gè)點(diǎn)都單獨(dú)存在于一個(gè)子空間內(nèi),但那些分布稀疏的點(diǎn),大都很早就停到一個(gè)子空間內(nèi)了。所以,整個(gè)孤立森林的算法思想:異常樣本更容易快速落入葉子結(jié)點(diǎn)或者說,異常樣本在決策樹上,距離根節(jié)點(diǎn)更近。隨機(jī)選擇m個(gè)特征,通過在所選特征的最大值和最小值之間隨機(jī)選擇一個(gè)值來分割數(shù)據(jù)點(diǎn)。觀察值的劃分遞歸地重復(fù),直到所有的觀察值被孤立。圖片圖10:孤立森林獲得 t 個(gè)孤立樹后,單棵樹的訓(xùn)練就結(jié)束了。接下來就可以用生成的孤立樹來評(píng)估測(cè)試數(shù)據(jù)了,即計(jì)算異常分?jǐn)?shù) s。對(duì)于每個(gè)樣本 x,需要對(duì)其綜合計(jì)算每棵樹的結(jié)果,通過下面的公式計(jì)算異常得分:

  • h(x):為樣本在iTree上的PathLength;

  • E(h(x)):為樣本在t棵iTree的PathLength的均值;

  •  : 為  個(gè)樣本構(gòu)建一個(gè)二叉搜索樹BST中的末成功搜索平均路徑長(zhǎng)度 (均值h(x)對(duì)外部節(jié)點(diǎn)終端的估計(jì)等同于BST中的末成功搜索)。 是對(duì)樣本x的路徑長(zhǎng)度  進(jìn)行標(biāo)準(zhǔn)化處理。 是調(diào)和數(shù), 可使用  (歐拉常數(shù)) 估算。

指數(shù)部分值域?yàn)??∞,0),因此s值域?yàn)?0,1)。當(dāng)PathLength越小,s越接近1,此時(shí)樣本為異常值的概率越大。

# Ref:https://zhuanlan.zhihu.com/p/484495545
from sklearn.datasets import load_iris 
from sklearn.ensemble import IsolationForest

data = load_iris(as_frame=True
X,y = data.data,data.target 
df = data.frame 

# 模型訓(xùn)練
iforest = IsolationForest(n_estimators=100, max_samples='auto',  
                          contamination=0.05, max_features=4,  
                          bootstrap=False, n_jobs=-1, random_state=1)

#  fit_predict 函數(shù) 訓(xùn)練和預(yù)測(cè)一起 可以得到模型是否異常的判斷,-1為異常,1為正常
df['label'] = iforest.fit_predict(X) 

# 預(yù)測(cè) decision_function 可以得出 異常評(píng)分
df['scores'] = iforest.decision_function(X)
六、基于降維的方法1. Principal Component Analysis (PCA)

資料來源:

[11] 機(jī)器學(xué)習(xí)-異常檢測(cè)算法(三):Principal Component Analysis - 劉騰飛,知乎:https://zhuanlan.zhihu.com/p/29091645[12] Anomaly Detection異常檢測(cè)--PCA算法的實(shí)現(xiàn) - CC思SS,知乎:https://zhuanlan.zhihu.com/p/48110105

PCA在異常檢測(cè)方面的做法,大體有兩種思路:(1) 將數(shù)據(jù)映射到低維特征空間,然后在特征空間不同維度上查看每個(gè)數(shù)據(jù)點(diǎn)跟其它數(shù)據(jù)的偏差;(2) 將數(shù)據(jù)映射到低維特征空間,然后由低維特征空間重新映射回原空間,嘗試用低維特征重構(gòu)原始數(shù)據(jù),看重構(gòu)誤差的大小。PCA在做特征值分解,會(huì)得到:

  • 特征向量:反應(yīng)了原始數(shù)據(jù)方差變化程度的不同方向;

  • 特征值:數(shù)據(jù)在對(duì)應(yīng)方向上的方差大小。

所以,最大特征值對(duì)應(yīng)的特征向量為數(shù)據(jù)方差最大的方向,最小特征值對(duì)應(yīng)的特征向量為數(shù)據(jù)方差最小的方向。原始數(shù)據(jù)在不同方向上的方差變化反應(yīng)了其內(nèi)在特點(diǎn)。如果單個(gè)數(shù)據(jù)樣本跟整體數(shù)據(jù)樣本表現(xiàn)出的特點(diǎn)不太一致,比如在某些方向上跟其它數(shù)據(jù)樣本偏離較大,可能就表示該數(shù)據(jù)樣本是一個(gè)異常點(diǎn)。在前面提到第一種做法中,樣本的異常分?jǐn)?shù)為該樣本在所有方向上的偏離程度:其中,  為樣本在重構(gòu)空間里離特征向量的距離。若存在樣本點(diǎn)偏離各主成分越遠(yuǎn),  會(huì)越大, 意味偏移程度大, 異常分?jǐn)?shù)高。 是特征值, 用于歸一化, 使不同方向上的偏離程度具有可比性。在計(jì)算異常分?jǐn)?shù)時(shí),關(guān)于特征向量(即度量異常用的標(biāo)桿)選擇又有兩種方式:

  • 考慮在前k個(gè)特征向量方向上的偏差:前k個(gè)特征向量往往直接對(duì)應(yīng)原始數(shù)據(jù)里的某幾個(gè)特征,在前幾個(gè)特征向量方向上偏差比較大的數(shù)據(jù)樣本,往往就是在原始數(shù)據(jù)中那幾個(gè)特征上的極值點(diǎn)。

  • 考慮后r個(gè)特征向量方向上的偏差:后r個(gè)特征向量通常表示某幾個(gè)原始特征的線性組合,線性組合之后的方差比較小反應(yīng)了這幾個(gè)特征之間的某種關(guān)系。在后幾個(gè)特征方向上偏差比較大的數(shù)據(jù)樣本,表示它在原始數(shù)據(jù)里對(duì)應(yīng)的那幾個(gè)特征上出現(xiàn)了與預(yù)計(jì)不太一致的情況。

得分大于閾值C則判斷為異常。第二種做法,PCA提取了數(shù)據(jù)的主要特征,如果一個(gè)數(shù)據(jù)樣本不容易被重構(gòu)出來,表示這個(gè)數(shù)據(jù)樣本的特征跟整體數(shù)據(jù)樣本的特征不一致,那么它顯然就是一個(gè)異常的樣本:其中,  是基于  維特征向量重構(gòu)的樣本。基于低維特征進(jìn)行數(shù)據(jù)樣本的重構(gòu)時(shí),舍棄了較小的特征值對(duì)應(yīng)的特征向量方向上的信息。換一句話說,重構(gòu)誤差其實(shí)主要來自較小的特征值對(duì)應(yīng)的特征向量方向上的信息。基于這個(gè)直觀的理解,PCA在異常檢測(cè)上的兩種不同思路都會(huì)特別關(guān)注較小的特征值對(duì)應(yīng)的特征向量。所以,我們說PCA在做異常檢測(cè)時(shí)候的兩種思路本質(zhì)上是相似的,當(dāng)然第一種方法還可以關(guān)注較大特征值對(duì)應(yīng)的特征向量。

# Ref: [https://zhuanlan.zhihu.com/p/48110105](https://zhuanlan.zhihu.com/p/48110105)
from sklearn.decomposition import PCA
pca = PCA()
pca.fit(centered_training_data)
transformed_data = pca.transform(training_data)
y = transformed_data

# 計(jì)算異常分?jǐn)?shù)
lambdas = pca.singular_values_
M = ((y*y)/lambdas)

# 前k個(gè)特征向量和后r個(gè)特征向量
q = 5
print "Explained variance by first q terms: ", sum(pca.explained_variance_ratio_[:q])
q_values = list(pca.singular_values_ < .2)
r = q_values.index(True)

# 對(duì)每個(gè)樣本點(diǎn)進(jìn)行距離求和的計(jì)算
major_components = M[:,range(q)]
minor_components = M[:,range(r, len(features))]
major_components = np.sum(major_components, axis=1)
minor_components = np.sum(minor_components, axis=1)

# 人為設(shè)定c1、c2閾值
components = pd.DataFrame({'major_components': major_components, 
                               'minor_components': minor_components})
c1 = components.quantile(0.99)['major_components']
c2 = components.quantile(0.99)['minor_components']

# 制作分類器
def classifier(major_components, minor_components):  
    major = major_components > c1
    minor = minor_components > c2    
    return np.logical_or(major,minor)

results = classifier(major_components=major_components, minor_components=minor_components)
2. AutoEncoder

資料來源:

[13] 利用Autoencoder進(jìn)行無監(jiān)督異常檢測(cè)(Python) - SofaSofa.io,知乎:https://zhuanlan.zhihu.com/p/46188296[14] 自編碼器AutoEncoder解決異常檢測(cè)問題(手把手寫代碼) - 數(shù)據(jù)如琥珀,知乎:https://zhuanlan.zhihu.com/p/260882741

PCA是線性降維,AutoEncoder是非線性降維。根據(jù)正常數(shù)據(jù)訓(xùn)練出來的AutoEncoder,能夠?qū)⒄颖局亟ㄟ€原,但是卻無法將異于正常分布的數(shù)據(jù)點(diǎn)較好地還原,導(dǎo)致還原誤差較大。因此如果一個(gè)新樣本被編碼,解碼之后,它的誤差超出正常數(shù)據(jù)編碼和解碼后的誤差范圍,則視作為異常數(shù)據(jù)。需要注意的是,AutoEncoder訓(xùn)練使用的數(shù)據(jù)是正常數(shù)據(jù)(即無異常值),這樣才能得到重構(gòu)后誤差分布范圍是多少以內(nèi)是合理正常的。所以AutoEncoder在這里做異常檢測(cè)時(shí),算是一種有監(jiān)督學(xué)習(xí)的方法。圖片圖11:自編碼器

# Ref: [https://zhuanlan.zhihu.com/p/260882741](https://zhuanlan.zhihu.com/p/260882741)
import tensorflow as tf
from keras.models import Sequential
from keras.layers import Dense

# 標(biāo)準(zhǔn)化數(shù)據(jù)
scaler = preprocessing.MinMaxScaler()
X_train = pd.DataFrame(scaler.fit_transform(dataset_train),
                              columns=dataset_train.columns,
                              index=dataset_train.index)
# Random shuffle training data
X_train.sample(frac=1)
X_test = pd.DataFrame(scaler.transform(dataset_test),
                             columns=dataset_test.columns,
                             index=dataset_test.index)

tf.random.set_seed(10)
act_func = 'relu'
# Input layer:
model=Sequential()
# First hidden layer, connected to input vector X.
model.add(Dense(10,activation=act_func,
                kernel_initializer='glorot_uniform',
                kernel_regularizer=regularizers.l2(0.0),
                input_shape=(X_train.shape[1],)
               )
         )
model.add(Dense(2,activation=act_func,
                kernel_initializer='glorot_uniform'))
model.add(Dense(10,activation=act_func,
                kernel_initializer='glorot_uniform'))
model.add(Dense(X_train.shape[1],
                kernel_initializer='glorot_uniform'))
model.compile(loss='mse',optimizer='adam')
print(model.summary())

# Train model for 100 epochs, batch size of 10:
NUM_EPOCHS=100
BATCH_SIZE=10
history=model.fit(np.array(X_train),np.array(X_train),
                  batch_size=BATCH_SIZE,
                  epochs=NUM_EPOCHS,
                  validation_split=0.05,
                  verbose = 1)

plt.plot(history.history['loss'],
         'b',
         label='Training loss')
plt.plot(history.history['val_loss'],
         'r',
         label='Validation loss')
plt.legend(loc='upper right')
plt.xlabel('Epochs')
plt.ylabel('Loss, [mse]')
plt.ylim([0,.1])
plt.show()

# 查看訓(xùn)練集還原的誤差分布如何,以便制定正常的誤差分布范圍
X_pred = model.predict(np.array(X_train))
X_pred = pd.DataFrame(X_pred,
                      columns=X_train.columns)
X_pred.index = X_train.index

scored = pd.DataFrame(index=X_train.index)
scored['Loss_mae'] = np.mean(np.abs(X_pred-X_train), axis = 1)
plt.figure()
sns.distplot(scored['Loss_mae'],
             bins = 10,
             kde= True,
            color = 'blue')
plt.xlim([0.0,.5])

# 誤差閾值比對(duì),找出異常值
X_pred = model.predict(np.array(X_test))
X_pred = pd.DataFrame(X_pred,
                      columns=X_test.columns)
X_pred.index = X_test.index
threshod = 0.3
scored = pd.DataFrame(index=X_test.index)
scored['Loss_mae'] = np.mean(np.abs(X_pred-X_test), axis = 1)
scored['Threshold'] = threshod
scored['Anomaly'] = scored['Loss_mae'] > scored['Threshold']
scored.head()
七、基于分類的方法1. One-Class SVM

資料來源:

[15] Python機(jī)器學(xué)習(xí)筆記:One Class SVM - zoukankan,博文:http://t.zoukankan.com/wj-1314-p-10701708.html[16] 單類SVM: SVDD - 張義策,知乎:https://zhuanlan.zhihu.com/p/65617987

One-Class SVM,這個(gè)算法的思路非常簡(jiǎn)單,就是尋找一個(gè)超平面將樣本中的正例圈出來,預(yù)測(cè)就是用這個(gè)超平面做決策,在圈內(nèi)的樣本就認(rèn)為是正樣本,在圈外的樣本是負(fù)樣本,用在異常檢測(cè)中,負(fù)樣本可看作異常樣本。它屬于無監(jiān)督學(xué)習(xí),所以不需要標(biāo)簽。圖片圖12:One-Class SVMOne-Class SVM又一種推導(dǎo)方式是SVDD(Support Vector Domain Description,支持向量域描述),對(duì)于SVDD來說,我們期望所有不是異常的樣本都是正類別,同時(shí)它采用一個(gè)超球體,而不是一個(gè)超平面來做劃分,該算法在特征空間中獲得數(shù)據(jù)周圍的球形邊界,期望最小化這個(gè)超球體的體積,從而最小化異常點(diǎn)數(shù)據(jù)的影響。假設(shè)產(chǎn)生的超球體參數(shù)為中心 o 和對(duì)應(yīng)的超球體半徑r>0,超球體體積V(r)被最小化,中心o是支持行了的線性組合;跟傳統(tǒng)SVM方法相似,可以要求所有訓(xùn)練數(shù)據(jù)點(diǎn)xi到中心的距離嚴(yán)格小于r。但是同時(shí)構(gòu)造一個(gè)懲罰系數(shù)為C的松弛變量 ζi,優(yōu)化問題入下所示:C是調(diào)節(jié)松弛變量的影響大小,說的通俗一點(diǎn)就是,給那些需要松弛的數(shù)據(jù)點(diǎn)多少松弛空間,如果C比較小,會(huì)給離群點(diǎn)較大的彈性,使得它們可以不被包含進(jìn)超球體。詳細(xì)推導(dǎo)過程參考資料[15] [16]。

from sklearn import svm
# fit the model
clf = svm.OneClassSVM(nu=0.1, kernel='rbf', gamma=0.1)
clf.fit(X)
y_pred = clf.predict(X)
n_error_outlier = y_pred[y_pred == -1].size
八、基于預(yù)測(cè)的方法

資料來源:

[17] 【TS技術(shù)課堂】時(shí)間序列異常檢測(cè) - 時(shí)序人,文章:https://mp.weixin.qq.com/s/9TimTB_ccPsme2MNPuy6uA

對(duì)于單條時(shí)序數(shù)據(jù),根據(jù)其預(yù)測(cè)出來的時(shí)序曲線和真實(shí)的數(shù)據(jù)相比,求出每個(gè)點(diǎn)的殘差,并對(duì)殘差序列建模,利用KSigma或者分位數(shù)等方法便可以進(jìn)行異常檢測(cè)。具體的流程如下:圖片圖13:基于預(yù)測(cè)的方法

九、總結(jié)

異常檢測(cè)方法總結(jié)如下:圖片參考資料[1] 時(shí)序預(yù)測(cè)競(jìng)賽之異常檢測(cè)算法綜述 - 魚遇雨欲語與余,知乎:https://zhuanlan.zhihu.com/p/336944097[2] 剔除異常值柵格計(jì)算器_數(shù)據(jù)分析師所需的統(tǒng)計(jì)學(xué):異常檢測(cè) - weixin_39974030,CSDN:https://blog.csdn.net/weixin_39974030/article/details/112569610[3] 異常檢測(cè)算法之(KNN)-K Nearest Neighbors - 小伍哥聊風(fēng)控,知乎:https://zhuanlan.zhihu.com/p/501691799[4] 一文讀懂異常檢測(cè) LOF 算法(Python代碼)- 東哥起飛,知乎:https://zhuanlan.zhihu.com/p/448276009[5] Nowak-Brzezińska, A., & Horyń, C. (2020). Outliers in rules-the comparision of LOF, COF and KMEANS algorithms. *Procedia Computer Science*, *176*, 1420-1429.[6] 機(jī)器學(xué)習(xí)_學(xué)習(xí)筆記系列(98):基於連接異常因子分析(Connectivity-Based Outlier Factor)  - 劉智皓 (Chih-Hao Liu)[7] 異常檢測(cè)之SOS算法 - 呼廣躍,知乎:https://zhuanlan.zhihu.com/p/34438518[8] 異常檢測(cè)算法 -- 孤立森林(Isolation Forest)剖析 - 風(fēng)控大魚,知乎:https://zhuanlan.zhihu.com/p/74508141[9] 孤立森林(isolation Forest)-一個(gè)通過瞎幾把亂分進(jìn)行異常檢測(cè)的算法 - 小伍哥聊風(fēng)控,知乎:https://zhuanlan.zhihu.com/p/484495545[10] 孤立森林閱讀 - Mark_Aussie,博文:https://blog.csdn.net/MarkAustralia/article/details/12018189[11] 機(jī)器學(xué)習(xí)-異常檢測(cè)算法(三):Principal Component Analysis - 劉騰飛,知乎:https://zhuanlan.zhihu.com/p/29091645[12] Anomaly Detection異常檢測(cè)--PCA算法的實(shí)現(xiàn) - CC思SS,知乎:https://zhuanlan.zhihu.com/p/48110105[13] 利用Autoencoder進(jìn)行無監(jiān)督異常檢測(cè)(Python) - SofaSofa.io,知乎:https://zhuanlan.zhihu.com/p/46188296[14] 自編碼器AutoEncoder解決異常檢測(cè)問題(手把手寫代碼) - 數(shù)據(jù)如琥珀,知乎:https://zhuanlan.zhihu.com/p/260882741[15] Python機(jī)器學(xué)習(xí)筆記:One Class SVM - zoukankan,博文:http://t.zoukankan.com/wj-1314-p-10701708.html[16] 單類SVM: SVDD - 張義策,知乎:https://zhuanlan.zhihu.com/p/65617987[17] 【TS技術(shù)課堂】時(shí)間序列異常檢測(cè) - 時(shí)序人,文章:https://mp.weixin.qq.com/s/9TimTB_ccPsme2MNPuy6uA

本文僅做學(xué)術(shù)分享,如有侵權(quán),請(qǐng)聯(lián)系刪文。


*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



關(guān)鍵詞: AI

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉