異常檢測項目流程
前言
首先這不是一篇簡單探究算法的文章,本文是從項目的角度出發來探究如何對數據進行異常值檢測,重點是機器學習算法(針對有異常和無異常的各種情況),當然後面還會包括一些模型部署、產品上線的內容。
一、項目流程
1.目標確立
要開始一個項目,首先就得明確一個目的,根據這個目的從而思考一下幾個問題:
- 做什麼?
- 爲什麼要做?
- 誰來做?
- 什麼時候做?
- 怎麼做?
- 優勢在哪?
當然你或許考慮的更多,不光是技術,還有人力、成本、利潤、營銷等問題。但是一般這個不是你該考慮的問題,除非你就是項目經理。.
就拿本文來說,檢測離羣點或異常值是數據挖掘的核心問題之一。數據的爆發和持續增長以及物聯網設備的傳播,使我們重新思考處理異常的方式以及通過觀察這些異常來構建的應用場景。
舉個簡單的例子:
我們現在可以通過智能手錶和手環每幾分鐘檢測一次心率。檢測心率數據中的異常可以幫助預測心臟疾病。交通模式中的異常檢測可以幫助預測事故。異常檢測還可用於識別網絡基礎設施和服務器間通信的瓶頸。因此,基於異常檢測構建的使用場景和解決方案是無限的。
2.數據準備
由於此次的數據是敏感數據源,所以不能公開展示,這裏只是簡單的描述一下數據如何準備。
一般數據的準備主要有以下幾種方式:
- 數據庫數據
- 由統計、調查、報告獲得 CSV、Excel等文件型數據
- 網絡爬蟲數據
- 某些開放型平臺數據
3.數據分析處理
數據處理分析詳見前面寫的這兩篇文章:
數據分析處理沒有固定的方法,仁者見仁智者見智,根據自己數據的形式和存在問題進行分析處理。
4.模型算法(重點)
進行異常值檢測的方法有很多,主要的話有以下幾種大的分類:
- 傳統統計方法
- 機器學習方法
- 深度學習方法
- 其他方法
4.1 傳統統計方法
在統計學中,離羣點是並不屬於特定族羣的數據點,是與其它值相距甚遠的異常觀測。離羣點是一種與其它結構良好的數據不同的觀測值。
4.1.1 3σ準則
3σ準則是指先假設一組檢測數據只含有隨機誤差,對其進行計算處理得到標準偏差,按一定概率確定一個區間,認爲凡超過這個區間的誤差,就不屬於隨機誤差而是粗大誤差,含有該誤差的數據應予以剔除。
這種判別處理原理及方法僅侷限於對正態或近似正態分佈的樣本數據處理,它是以測量次數充分大爲前提(樣本>10),當測量次數少的情形用準則剔除粗大誤差是不夠可靠的。
3σ法則爲:
- 數值分佈在(μ-σ,μ+σ)中的概率爲0.6827
- 數值分佈在(μ-2σ,μ+2σ)中的概率爲0.9545
- 數值分佈在(μ-3σ,μ+3σ)中的概率爲0.9973
可以認爲,Y 的取值幾乎全部集中在(μ-3σ,μ+3σ)區間內,超出這個範圍的可能性僅佔不到0.3%
因此,如果你有任何數據點超過標準差的 3 倍,那麼這些點很有可能是異常值或離羣點。(正態分佈)
算法實現:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
anomalies = []
normal = []
# 生成一些數據
data = np.random.randn(50000) * 20 + 20
# 在一維數據集上檢測離羣點的函數
def find_anomalies(random_data):
# 將上、下限設爲3倍標準差
random_data_std = np.std(random_data)
random_data_mean = np.mean(random_data)
anomaly_cut_off = random_data_std * 3
lower_limit = random_data_mean - anomaly_cut_off
upper_limit = random_data_mean + anomaly_cut_off
print("下限: ",lower_limit)
print("上限: ",upper_limit)
# 異常
for outlier in random_data:
if outlier > upper_limit or outlier < lower_limit:
anomalies.append(outlier)
else:
normal.append(outlier)
return pd.DataFrame(anomalies,columns=["異常值"]),pd.DataFrame(normal,columns=["正常值"])
anomalies,normal = find_anomalies(data)
這段代碼的輸出是一組大於 80 或小於-40 的異常值和正常值。注意,輸入的數據集是正態分佈的並且是一維的。
4.1.2 四分位(箱線圖)
箱形圖是數字數據通過其四分位數形成的圖形化描述。這是一種非常簡單但有效的可視化離羣點的方法。考慮把上下觸鬚作爲數據分佈的邊界。任何高於上觸鬚或低於下觸鬚的數據點都可以認爲是離羣點或異常值
四分位間距 (IQR) 的概念被用於構建箱形圖。IQR 是統計學中的一個概念,通過將數據集分成四分位來衡量統計分散度和數據可變性。簡單來說,任何數據集或任意一組觀測值都可以根據數據的值以及它們與整個數據集的比較情況被劃分爲四個確定的間隔。四分位數會將數據分爲三個點和四個區間。
四分位間距對定義離羣點非常重要。它是第三個四分位數和第一個四分位數的差 (IQR = Q3 -Q1)。在這種情況下,離羣點被定義爲低於箱形圖下觸鬚(或 Q1 − 1.5x IQR)或高於箱形圖上觸鬚(或 Q3 + 1.5x IQR)的觀測值。
算法實現:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
anomalies = []
normal = []
# 生成一些數據
data = np.random.randn(50000) * 20 + 20
# 在一維數據集上檢測離羣點的函數
def find_anomalies(random_data):
# 將上、下限設爲3倍標準差
iqr_25 = np.percentile(random_data, [25])
iqr_75 = np.percentile(random_data, [75])
lower_limit = iqr_25 - 1.5 * (iqr_75 - iqr_25)
upper_limit = iqr_25 + 1.5 * (iqr_75 - iqr_25)
print("下限: ",lower_limit)
print("上限: ",upper_limit)
# 異常
for outlier in random_data:
if outlier > upper_limit or outlier < lower_limit:
anomalies.append(outlier)
else:
normal.append(outlier)
return pd.DataFrame(anomalies,columns=["異常值"]),pd.DataFrame(normal,columns=["正常值"])
anomalies,normal = find_anomalies(data)
優點:與方差和極差相比,更加不如意受極端值的影響,且處理大規模數據效果很好。
缺點:小規模處理略顯粗糙。而且只適合單個屬相的檢測。
除以上兩種簡單的基於統計學的異常值檢測方法之外,還有諸如:卡方檢驗、方差分析等方法,有興趣可以自己嘗試代碼。
4.2 機器學習方法(重點)
機器學習方法可以分爲以下幾類:
- 有標籤的監督學習
- 無標籤的無監督學習
4.2.1 監督學習算法
監督學習的算法適用於正常數據和異常數據都存在且有標籤的情況下。這種假設情況是很完美的,因爲他把異常值檢測就轉化成了分類算法,有衆多的機器學習算法可以使用。
或許你在思考這樣一個問題:如果異常值很少,正常值很多,樣本不平衡怎麼辦?
對於這樣一個問題,一般有兩種解決辦法:
- 算法層面:有些算法內部會自動的帶有使樣本平衡參數,例如SVM中的
class_weight = "balanced"
。 - 數據層面:從數據層面來說主要就是上採樣和下采樣,但一般推薦SMOTE算法生成樣本量較少的數據。
常見的分類算法效果較好的有:
- KNN
- RF
- GBDT
- SVM
- XGBoost
- ……
這些算法我就不去實現了,也沒啥必要去實現,都是基本的分類算法。
4.2.2 無監督學習算法
無監督學習的算法適用於正常數據和異常數據都存在且沒有標籤的情況下,這種異常值檢測也被稱作爲離羣值檢測。這類算法主要有:
- IsolationForest
- DBSCAN
- Local Outlier Factor(LOF)
IsolationForest
孤立森林(Isolation Forest)是一種高效的異常檢測算法,它和隨機森林類似,但每次選擇劃分屬性和劃分點(值)時都是隨機的,而不是根據信息增益或者基尼指數來選擇。在建樹過程中,如果一些樣本很快就到達了葉子節點(即葉子到根的距離d很短),那麼就被認爲很有可能是異常點。因爲那些路徑d比較短的樣本,都是因爲距離主要的樣本點分佈中心比較遠的。也就是說,可以通過計算樣本在所有樹中的平均路徑長度來尋找異常點。
sklearn提供了ensemble.IsolationForest模塊可用於Isolation Forest算法:
sklearn.ensemble.IsolationForest(n_estimators=100, max_samples='auto', contamination='auto', max_features=1.0, bootstrap=False, n_jobs=None, behaviour='deprecated', random_state=None, verbose=0, warm_start=False)
DBSCAN
DBSCAN 是一種用於把數據聚成組的聚類算法。它同樣也被用於單維或多維數據的基於密度的異常檢測。雖然其它聚類算法比如 k 均值和層次聚類也可用於檢測離羣點。但是DBSCAN效果較好,所以往往用它。
DBSCAN是基於密度的聚類算法,重點是發現鄰居的密度(MinPts)在n維球體的半徑ɛ。
DBSCAN定義不同類型的點:
- 核心點:A是一個核心的區域(ɛ所定義的)包含至少比參數MinPts同樣多或更多的點。
- 邊界點:C是一個位於集羣中的邊界點,它的鄰域並不包含比MinPts更多的點,但它仍然是集羣中其他點的“密度可達”。
- 離羣點:N是一個離羣點,在沒有集羣的情況下,它不是“密度可達”或“密度連接”到任何其他點。因此,這一點將有“他自己的集羣”。
DBSVAN對MinPts參數也很敏感,它將完全依賴於手動調整的問題,其複雜度爲O(n log n),它是一種具有中等大小的數據集的有效方法,我們可以使用Scikit-learn來實現:
sklearn.cluster.DBSCAN(eps=0.5, min_samples=5, metric='euclidean', metric_params=None, algorithm='auto', leaf_size=30, p=None, n_jobs=None)
DBSCAN 優點:
-
當特徵空間中的值分佈不是假設的時,這是一種非常有效的方法。
-
如果搜索異常值的特徵空間是多維的(比如:3或更多的維度),則可以很好地工作。
DBSCAN 缺點:
-
特徵空間中的值需要相應地伸縮。
-
選擇最優參數eps,MinPts和度規可能很困難,因爲它對任何三個參數都非常敏感。
-
它是一個無監督的模型,需要在每次分析新的數據時重新校準。
Local Outlier Factor(LOF)
局部異常因子(LOF)算法是一個很特殊的異常檢測算法,因爲它既可以對數據進行無監督學習,還可以進行半監督學習。
首先討論他的思想:每個樣本的異常分數稱爲局部異常因子。它測量給定樣本相對於其鄰居的密度的局部偏差。它是局部的,異常得分取決於物體相對於周圍鄰域的隔離程度。更確切地說,局部性由k近鄰給出,其距離用於估計局部密度。通過將樣本的局部密度與其鄰居的局部密度進行比較,可以識別密度明顯低於其鄰居的樣本,這些被認爲是異常值。
說白了就是,它計算給定數據點相對於其鄰居的局部密度偏差。它將密度大大低於鄰居的樣本視爲異常值。
之所以說LOF兩種方法都支持取決於該算法中的一個參數:novelty = True
則是半監督學習,novelty = False
則是無監督學習。
sklearn.neighbors.LocalOutlierFactor(n_neighbors=20, algorithm='auto', leaf_size=30, metric='minkowski', p=2, metric_params=None, contamination='auto', novelty=False, n_jobs=None)
方法 | 離羣點檢測novelty = False |
新奇點檢測novelty = True |
---|---|---|
fit_predict | 可用 | 不可用 |
predict | 不可用 | 只能用於新數據 |
decision_function | 不可用 | 只能用於新數據 |
score_samples | 用 negative_outlier_factor_ | 只能用於新數據 |
4.2.3 半監督學習算法
半監督學習的算法適用於只有正常數據,沒有異常數據的情況下,這種異常值檢測也被稱作爲新奇點檢測。這類算法主要有:
- Local Outlier Factor(LOF)
- One-Class SVM
Local Outlier Factor(LOF)
上面已經討論過,這裏不再討論。
One-Class SVM
在介紹One-Class SVM之前,你知道他代表什麼意思嗎?
如果將分類算法進行劃分,根據類別個數的不同可以分爲單分類,二分類,多分類。常見的分類算法主要解決二分類和多分類問題,預測一封郵件是否是垃圾郵件是一個典型的二分類問題,手寫體識別是一個典型的多分類問題,這些算法並不能很好的應用在單分類上。那麼爲什麼又要去研究單分類呢?
單分類問題在工業界廣泛存在,由於每個企業刻畫用戶的數據都是有限的,很多二分類問題很難找到負樣本,即使用一些排除法篩選出負樣本,負樣本也會不純,不能保證負樣本中沒有正樣本。所以在只能定義正樣本不能定義負樣本的場景中,使用單分類算法更合適。單分類算法只關注與樣本的相似或者匹配程度,對於未知的部分不妄下結論。
OneClassClassification中的訓練樣本只有一類,因此訓練出的分類器將不屬於該類的所有其他樣本判別爲“不是”即可,而不是由於屬於另一類才返回“不是”的結果。
One Class SVM也是屬於支持向量機大家族的,但是它和傳統的基於監督學習的分類迴歸支持向量機不同,它是無監督學習的方法,也就是說,它不需要我們標記訓練集的輸出標籤。那麼沒有類別標籤,我們如何尋找劃分的超平面以及尋找支持向量機呢?One Class SVM這個問題的解決思路有很多。這裏只講解一種特別的思想SVDD,對於SVDD來說,我們期望所有不是異常的樣本都是正類別,同時它採用一個超球體而不是一個超平面來做劃分,該算法在特徵空間中獲得數據周圍的球形邊界,期望最小化這個超球體的體積,從而最小化異常點數據的影響。
sklearn.svm.OneClassSVM(kernel='rbf', degree=3, gamma='scale', coef0=0.0, tol=0.001, nu=0.5, shrinking=True, cache_size=200, verbose=False, max_iter=-1)
4.3 深度學習方法
前面重點介紹了關於機器學習的異常檢測,其實深度學習裏面也有很多關於異常檢測的思想,但是實現起來就比使用sklearn難太多。不過說到這裏也簡單介紹幾個我使用Pytorch實現在異常值檢測吧。
- AE(AutoEncoder)
- VAE(Variational Autoencoder)
- GAN
4.3.1 AE(AutoEncoder)
Autoencoder,中文稱作自編碼器,是一種無監督式學習模型。本質上它使用了一個神經網絡來產生一個高維輸入的低維表示。Autoencoder與主成分分析PCA類似,但是Autoencoder在使用非線性激活函數時克服了PCA線性的限制。
Autoencoder包含兩個主要的部分,encoder(編碼器)和 decoder(解碼器)。Encoder的作用是用來發現給定數據的壓縮表示,decoder是用來重建原始輸入。在訓練時,decoder 強迫 autoencoder 選擇最有信息量的特徵,最終保存在壓縮表示中。最終壓縮後的表示就在中間的coder層當中。以下圖爲例,原始數據的維度是10,encoder和decoder分別有兩層,中間的coder共有3個節點,也就是說原始數據被降到了只有3維。Decoder根據降維後的數據再重建原始數據,重新得到10維的輸出。從Input到Ouptut的這個過程中,autoencoder實際上也起到了降噪的作用。
AutoEncoder無監督異常檢測
在無監督的情況下,我們沒有異常樣本用來學習,而算法的基本上假設是異常點服從不同的分佈。根據正常數據訓練出來的Autoencoder,能夠將正常樣本重建還原,但是卻無法將異於正常分佈的數據點較好地還原,基於AE的重構損失導致還原誤差較大。
如果樣本的特徵都是數值變量,我們可以用MSE或者MAE作爲還原誤差。
4.3.2 VAE(Variational AutoEncoder(VAE))
接下來介紹一些VAE模型,對於VAE模型的基本思想,下面內容主要引用自我覺得講得比較清楚的一篇知乎文章,並根據我的理解將文中一些地方進行修改,保留核心部分,這裏假設讀者知道判別模型與生成模型的相關概念。
原文地址:https://zhuanlan.zhihu.com/p/27865705
VAE 跟傳統 AutoEncoder關係並不大,只是思想及架構上也有 Encoder 和 Decoder 兩個結構而已。VAE 理論涉及到的主要背景知識包括:隱變量(Latent Variable Models)、變分推理(Variational Inference)、Reparameterization Trick 等等。
下圖表示了VAE整個過程。即首先通過Encoder 得到的隱變量分佈參數;然後採樣得到隱變量 。接下來按公式,應該是利用 Decoder 求得 的分佈參數,而實際中一般就直接利用隱變量恢復 。
VAE也實現了跟AutoEncoder類似的作用,輸入一個序列,得到一個隱變量(從隱變量的分佈中採樣得到),然後將隱變量重構成原始輸入。不同的是,VAE學習到的是隱變量的分佈(允許隱變量存在一定的噪聲和隨機性),因此可以具有類似正則化防止過擬合的作用。
基於VAE的異常檢測方法其實跟AutoEncoder基本一致,可以使用重構誤差來判斷異常。
缺陷
基於AutoEncoder和VAE模型在工業界上的使用面臨的最大問題是:
需要設置異常閾值。因爲我們檢測異常是通過對比重構後的結果與原始輸入的差距,而這個差距多少就算是異常需要人爲定義,然而對於大量的不同類型的數據,我們很難去統一設置閾值,這也是採用VAE模型比較大的一個缺陷。雖然在Dount論文中,採用的是重構概率而不是重構誤差來判斷異常,然而重構概率也需要設置閾值才能得到比較精確的結果。
4.3.3 GAN
4.4 其他方法
5.模型部署
這一部分是由flask來搭建平臺的,後面會更新