異常檢測——基於統計學方法(參數方法、非參數方法、HBOS、pyod庫)

異常檢測——基於統計學方法(參數方法、非參數方法、HBOS、pyod庫)

涉及知識點

  • 統計學異常檢測的思想
  • 基於參數方法的異常檢測
  • 基於非參數方法的異常檢測
  • HBOS
  • Python中PyOD庫生成toy example並調用HBOS實例

1、統計學中對異常檢測的思想

統計學方法對異常檢測的思想是在於假定和學習數據符合一個具體的模型或分佈,而當給定的具體數據在假設模型中出現概率較低的時候,就認爲是異常數據。  **其有效性高度依賴於對給定的模型所做的假定的統計模型是否成立**。在其中通過事先給定模型的方法稱爲參數方法,通過給定數據學習模型的方法稱爲非參數方法。

參數方法假定正常的數據對象被一個以 Θ \Theta Θ爲參數的參數分佈產生。該參數分佈的概率密度函數 f ( x , Θ ) f(x,\Theta) f(x,Θ)給出對象 x x x被該分佈產生的概率。該概率值越小, x x x越可能是異常點。

非參數方法並不假定先驗統計模型,而是試圖從輸入數據確定模型。非參數方法通常假定參數的個數和性質都是靈活的,不預先確定(所以非參數方法並不是說模型是完全無參的,完全無參的情況下從數據學習模型是不可能的)。

2 、基於參數方法的異常檢測

在樣本數據的均值十分貼近於分佈函數的中心且數據集足夠大的情況下,可以利用參數方法來識別異常值

2.1 一元正態假定下異常點的檢測

將只涉及一個屬性和變量的數據稱爲一元數據,我們假定數據樣本服從正態分佈,即 x ( i ) ∼ N ( μ , σ 2 ) x^{(i)}\sim N(\mu, \sigma^2) x(i)N(μ,σ2),我們可以根據樣本求出參數 μ \mu μ σ \sigma σ

μ = 1 m ∑ i = 1 m x ( i ) \mu=\frac 1m\sum_{i=1}^m x^{(i)} μ=m1i=1mx(i)

σ 2 = 1 m ∑ i = 1 m ( x ( i ) − μ ) 2 \sigma^2=\frac 1m\sum_{i=1}^m (x^{(i)}-\mu)^2 σ2=m1i=1m(x(i)μ)2
計算出正態分佈的均值和方差估計,即相當於知道了正態分佈的密度函數,然後就可以計算出出現樣本以及更極端情況下的概率,然後通過與設置的閾值進行比較,若低於閾值,則認爲是異常點。

閾值是個經驗值可多次選取,但通過選取驗證集上使得評估指標或評估效果最好的閾值作爲最終閾值

此外還可通過3sigma原則進行判斷,如果數據點超過範圍 ( μ − 3 σ , μ + 3 σ ) (\mu-3\sigma, \mu+3\sigma) (μ3σ,μ+3σ),那麼這些點很有可能是異常點。

2.2 多元異常點檢測
涉及兩個或多個屬性或變量的數據稱爲多元數據。
2.2.1 多元各維度之間相互獨立的情況
許多一元異常點檢測方法都可以擴充,用來處理多元各維度獨立的情況數據。其核心思想是把多元異常點檢測任務轉換成一元異常點檢測問題。如基於正態分佈的一元異常點檢測擴充到多元情形時,可以求出每一維度的均值和標準差。
對於第 j j j維:



μ j = 1 m ∑ i = 1 m x j ( i ) \mu_j=\frac 1m\sum_{i=1}^m x_j^{(i)} μj=m1i=1mxj(i)

σ j 2 = 1 m ∑ i = 1 m ( x j ( i ) − μ j ) 2 \sigma_j^2=\frac 1m\sum_{i=1}^m (x_j^{(i)}-\mu_j)^2 σj2=m1i=1m(xj(i)μj)2

計算概率時的概率密度函數爲

p ( x ) = ∏ j = 1 n p ( x j ; μ j , σ j 2 ) = ∏ j = 1 n 1 2 π σ j e x p ( − ( x j − μ j ) 2 2 σ j 2 ) p(x)=\prod_{j=1}^n p(x_j;\mu_j,\sigma_j^2)=\prod_{j=1}^n\frac 1{\sqrt{2\pi}\sigma_j}exp(-\frac{(x_j-\mu_j)^2}{2\sigma_j^2}) p(x)=j=1np(xj;μj,σj2)=j=1n2π σj1exp(2σj2(xjμj)2)
最後再利用p值與閾值對比、3sigma原則等方法進行檢驗

2.2.2 多元多個特徵相關,且符合多元高斯分佈的情況

μ = 1 m ∑ i = 1 m x ( i ) \mu=\frac{1}{m}\sum^m_{i=1}x^{(i)} μ=m1i=1mx(i)

∑ = 1 m ∑ i = 1 m ( x ( i ) − μ ) ( x ( i ) − μ ) T \sum=\frac{1}{m}\sum^m_{i=1}(x^{(i)}-\mu)(x^{(i)}-\mu)^T =m1i=1m(x(i)μ)(x(i)μ)T

p ( x ) = 1 ( 2 π ) n 2 ∣ Σ ∣ 1 2 exp ⁡ ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) p(x)=\frac{1}{(2 \pi)^{\frac{n}{2}}|\Sigma|^{\frac{1}{2}}} \exp \left(-\frac{1}{2}(x-\mu)^{T} \Sigma^{-1}(x-\mu)\right) p(x)=(2π)2nΣ211exp(21(xμ)TΣ1(xμ))
用訓練集來擬合參數u和Σ,從而擬合模型p(x)
在這裏插入圖片描述
使用p(x)的計算公式計算出p(x)的值,如果p(x)<ε就將它標記爲一個異常點


當我們對上圖中那個綠色的點進行異常檢測時,這些紅色的點服從多元高斯正態分佈(x1與x2正相關),算法會將綠色的判斷爲異常點,因爲它遠離這個高斯分佈中心點。

2.2.3 使用混合參數分佈
許多情況下假定數據是由正態分佈產生的。當實際數據很複雜時,這種假定過於簡單,可以假定數據是被混合參數分佈產生的。

3、基於非參數方法的異常檢測

在異常檢測的非參數方法中,“正常數據”的模型從輸入數據學習,而不是假定一個先驗。通常,非參數方法對數據做較少假定,因而在更多情況下都可以使用。

可以通過箱線圖的形式進行判斷,異常點常被定義爲小於Q1-1.5IQR或大於Q3+1.5IQR的那些數據(Q1、Q3分別爲1/4和3/4分位數,QR爲Q3-QQ1四分位距):

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

data = np.random.randn(50000) * 20 + 20
sns.boxplot(data=data)

在這裏插入圖片描述

這裏要注意,如果數據集中存在分類數據,則要採用多變量的分析方法,按照各類別分別繪製箱線圖檢測異常點,而不能單純利用單變量分析方法,否則會錯誤的識別出異常值。

相對於參數方法,如果數據的中位數比均值更貼近於數據的分佈中心,則應利用箱線圖等非參數方法來識別異常值

numpy.random用法

np.random.seed()
#當我們設置相同的seed,每次生成的隨機數相同。如果不設置seed,則每次會生成不同的隨機數
numpy.random.rand(4,2)
#根據給定維度生成[0,1)之間的數據,包含0,不包含1,返回值爲指定維度的array
numpy.random.randn(d0,d1,,dn)
#randn函數根據維度返回一個具有標準正態分佈的數據,返回值爲指定維度的array
numpy.random.randint(low, high=None, size=None, dtype=’l’)
#返回隨機整數,範圍區間爲[low,high),包含low,不包含high,size爲數組維度大小,dtype爲數據類型,默認的數據類型是np.int。

numpy.random.choice(a, size=None, replace=True, p=None)
#從給定的一維數組中生成隨機數
# a爲一維數組類似數據或整數;size爲數組維度;p爲數組中的數據出現的概率,a爲整數時,對應的一維數組爲np.arange(a)
#參數p的長度與參數a的長度需要一致;參數p爲概率,p裏的數據之和應爲1
#demo_list = ['lenovo', 'sansumg','moto','xiaomi', 'iphone']
#np.random.choice(demo_list,size=(3,3), p=[0.1,0.6,0.1,0.1,0.1])

4、HBOS

全名爲:Histogram-based Outlier Score。它是一種單變量方法的組合,不能對特徵之間的依賴關係進行建模,但是計算速度較快,對大數據集友好。其基本假設是數據集的每個維度相互獨立。然後對每個維度進行區間(bin)劃分,區間的密度越高,異常評分越低。

HBOS在全局異常檢測問題上表現良好,但不能檢測局部異常值。但是HBOS比標準算法快得多,尤其是在大數據集上。

HBOS算法流程:

1.爲每個數據維度做出數據直方圖。對分類數據統計每個值的頻數並計算相對頻率。對數值數據根據分佈的不同採用以下兩種方法:

  • 靜態寬度直方圖:標準的直方圖構建方法,在值範圍內使用k個等寬箱。樣本落入每個箱的頻率(相對數量)作爲密度(箱子高度)的估計。時間複雜度: O ( n ) O(n) O(n)
  • 動態寬度直方圖:首先對所有值進行排序,然後固定數量的 N k \frac{N}{k} kN個連續值裝進一個箱裏,其 中N是總實例數,k是箱個數;直方圖中的箱面積表示實例數。因爲箱的寬度是由箱中第一個值和最後一個值決定的,所有箱的面積都一樣,因此每一個箱的高度都是可計算的。這意味着跨度大的箱的高度低,即密度小,只有一種情況例外,超過k個數相等,此時允許在同一個箱裏超過 N k \frac{N}{k} kN值。
    時間複雜度: O ( n × l o g ( n ) ) O(n\times log(n)) O(n×log(n))

2.對每個維度都計算了一個獨立的直方圖,其中每個箱子的高度表示密度的估計。然後爲了使得最大高度爲1(確保了每個特徵與異常值得分的權重相等),對直方圖進行歸一化處理。最後,每一個實例的HBOS值由以下公式計算:

H B O S ( p ) = ∑ i = 0 d log ⁡ ( 1 hist i ( p ) ) H B O S(p)=\sum_{i=0}^{d} \log \left(\frac{1}{\text {hist}_{i}(p)}\right) HBOS(p)=i=0dlog(histi(p)1)

推導過程:

假設樣本p第 i 個特徵的概率密度爲 p i ( p ) p_i(p) pi(p) ,則p的概率密度可以計算爲: P ( p ) = P 1 ( p ) P 2 ( p ) ⋯ P d ( p ) P(p)=P_{1}(p) P_{2}(p) \cdots P_{d}(p) P(p)=P1(p)P2(p)Pd(p) 兩邊取對數: log ⁡ ( P ( p ) ) = log ⁡ ( P 1 ( p ) P 2 ( p ) ⋯ P d ( p ) ) = ∑ i = 1 d log ⁡ ( P i ( p ) ) \begin{aligned} \log (P(p)) &=\log \left(P_{1}(p) P_{2}(p) \cdots P_{d}(p)\right) =\sum_{i=1}^{d} \log \left(P_{i}(p)\right) \end{aligned} log(P(p))=log(P1(p)P2(p)Pd(p))=i=1dlog(Pi(p)) 概率密度越大,異常評分越小,爲了方便評分,兩邊乘以“-1”: − log ⁡ ( P ( p ) ) = − 1 ∑ i = 1 d log ⁡ ( P t ( p ) ) = ∑ i = 1 d 1 log ⁡ ( P i ( p ) ) -\log (P(p))=-1 \sum_{i=1}^{d} \log \left(P_{t}(p)\right)=\sum_{i=1}^{d} \frac{1}{\log \left(P_{i}(p)\right)} log(P(p))=1i=1dlog(Pt(p))=i=1dlog(Pi(p))1 最後可得: H B O S ( p ) = − log ⁡ ( P ( p ) ) = ∑ i = 1 d 1 log ⁡ ( P i ( p ) ) H B O S(p)=-\log (P(p))=\sum_{i=1}^{d} \frac{1}{\log \left(P_{i}(p)\right)} HBOS(p)=log(P(p))=i=1dlog(Pi(p))1

5、Python中PyOD庫生成toy example並調用HBOS實例

我們傾向於使用簡單的方法,如箱形圖,直方圖和散點圖來檢測異常值。 但是,專用異常值檢測算法在處理大量數據並需要在較大數據集中執行模式識別的方法中非常有價值,如金融中的欺詐檢測和網絡安全中的入侵檢測等應用

PyOD是一個可擴展的Python工具包,用於檢測多變量數據中的異常值。 它可以在一個詳細記錄API下訪問大約20個離羣值檢測算法。
對pyod的介紹

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
%matplotlib inline#%matplotlib具體作用是當你調用matplotlib.pyplot的繪圖函數plot()進行繪圖的時候,或者生成一個figure畫布的時候,可以直接在你的python console裏面生成圖像。
import matplotlib.font_manager
from pyod.models.hbos import HBOS
#創建一個帶有異常值的隨機數據集並繪製它。
from pyod.utils.data import generate_data, get_outliers_inliers

#generate random data with two features
X_train, Y_train = generate_data(n_train=200,train_only=True, n_features=2)

# by default the outlier fraction is 0.1 in generate data function 
outlier_fraction = 0.1

# store outliers and inliers in different numpy arrays
x_outliers, x_inliers = get_outliers_inliers(X_train,Y_train)

n_inliers = len(x_inliers)
n_outliers = len(x_outliers)

#separate the two features and use it to plot the data 
F1 = X_train[:,[0]].reshape(-1,1)
F2 = X_train[:,[1]].reshape(-1,1)

# create a meshgrid 
xx , yy = np.meshgrid(np.linspace(-10, 10, 200), np.linspace(-10, 10, 200))

# scatter plot 
plt.scatter(F1,F2)
plt.xlabel('F1')
plt.ylabel('F2') 

在這裏插入圖片描述

#將數據擬合到我們在字典中添加的模型,然後,查看模型如何檢測異常值:
#set the figure size
plt.figure(figsize=(10, 10))

for i, (clf_name,clf) in enumerate(classifiers.items()) :
    # fit the dataset to the model
    clf.fit(X_train)

    # predict raw anomaly score
    scores_pred = clf.decision_function(X_train)*-1

    # prediction of a datapoint category outlier or inlier
    y_pred = clf.predict(X_train)

    # no of errors in prediction
    n_errors = (y_pred != Y_train).sum()
    print('No of Errors : ',clf_name, n_errors)

    # rest of the code is to create the visualization

    # threshold value to consider a datapoint inlier or outlier
    threshold = stats.scoreatpercentile(scores_pred,100 *outlier_fraction)

    # decision function calculates the raw anomaly score for every point
    Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) * -1
    Z = Z.reshape(xx.shape)

    subplot = plt.subplot(1, 2, i + 1)

    # fill blue colormap from minimum anomaly score to threshold value
    subplot.contourf(xx, yy, Z, levels = np.linspace(Z.min(), threshold, 10),cmap=plt.cm.Blues_r)

    # draw red contour line where anomaly score is equal to threshold
    a = subplot.contour(xx, yy, Z, levels=[threshold],linewidths=2, colors='red')

    # fill orange contour lines where range of anomaly score is from threshold to maximum anomaly score
    subplot.contourf(xx, yy, Z, levels=[threshold, Z.max()],colors='orange')

    # scatter plot of inliers with white dots
    b = subplot.scatter(X_train[:-n_outliers, 0], X_train[:-n_outliers, 1], c='white',s=20, edgecolor='k') 
    # scatter plot of outliers with black dots
    c = subplot.scatter(X_train[-n_outliers:, 0], X_train[-n_outliers:, 1], c='black',s=20, edgecolor='k')
    subplot.axis('tight')

    subplot.legend(
        [a.collections[0], b, c],
        ['learned decision function', 'true inliers', 'true outliers'],
        prop=matplotlib.font_manager.FontProperties(size=10),
        loc='lower right')

    subplot.set_title(clf_name)
    subplot.set_xlim((-10, 10))
    subplot.set_ylim((-10, 10))
plt.show() 

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章