[轉]Python機器學習筆記 異常點檢測算法——Isolation Forest


Isolation,意為孤立/隔離,是名詞,其動詞為isolate,forest是森林,合起來就是“孤立森林”了,也有叫“獨異森林”,好像並沒有統一的中文叫法。可能大家都習慣用其英文的名字isolation forest,簡稱iForest 。

  iForest適用於連續數據(Continuous numerical data)的異常檢測,將異常定義為“容易被孤立的離群點(more  likely to be separated)”——可以理解為分布稀疏且離密度高的群體較遠的點。用統計學來解釋,在數據空間里面,分布稀疏的區域表示數據發生在此區域的概率很低,因此可以認為落在這些區域里的數據是異常的。通常用於網絡安全中的攻擊檢測和流量異常等分析,金融機構則用於挖掘出欺詐行為。對於找出的異常數據,然后要么直接清除異常數據,如數據清理中的去噪數據,要么深入分析異常數據,比如分析攻擊,欺詐的行為特征。

Isolation Forest算法原理

  iForest 屬於Non-parametric和unsupervised的方法,即不用定義數學模型也不需要有標記的訓練。對於如何查找哪些點是否容易被孤立(isolated),iForest使用了一套非常高效的策略。假設我們用一個隨機超平面來切割(split)數據空間(data  space),切一次可以生成兩個子空間(詳細拿刀切蛋糕一分為二)。之后我們再繼續用一個隨機超平面來切割每個子空間,循環下去,直到每個子空間里面只有一個數據點為止。直觀上來講,我們可以發現那些密度很高的簇是被切分很多次才會停止切割,但是那些密度很低的點很容易很早就停到一個子空間看了。

 怎么來切這個數據空間是iForest的設計核心思想,本文僅學習最基本的方法,由於切割是隨機的,所以需要用ensemble的方法來得到一個收斂值(蒙特卡洛方法),即反復從頭開始切,然后平均每次切的結果。IForest由 t個iTree(Isolation Tree)孤立樹組成,每個iTree是一個二叉樹結構,所以下面我們先說一下iTree樹的構建,然后再看iForest樹的構建。

Isolation Forest算法步驟

1,iTree 的構建

  提到森林,自然少不了樹,畢竟森林都是樹構建的,看Isolation Forest(簡稱iForest)前,我們先來看看Isolation Tree(簡稱iTree)是怎么構成的。iTree是一種隨機二叉樹,每個節點要么有兩個女兒,要么就是葉子節點,一個孩子都沒有。給定一堆數據集D,這里D的所有屬性都是連續型的變量,iTree的構成過程如下:

1,隨機選擇一個屬性Attr

2,隨機選擇該屬性的一個值Value

3,根據Attr 對每條記錄進行分類,把Attr小於Value的記錄放在左女兒,把大於等於Value的記錄放在右孩子。

4,然后遞歸的構造左女兒和右女兒,直到滿足以下條件:

  • 1,傳入的數據集只有一條記錄或者多條一樣的記錄
  • 2,樹的高度達到了限定高度
 
  iTree構建好之后,就可以對數據進行預測了。預測的過程就是把測試記錄在ITree上走一下,看看測試記錄在哪個葉子節點。iTree能有效檢測異常的假設是:異常點一般都是非常稀有的,在iTree中會很快被划分到葉子節點。
(注意:異常點一般來說是稀疏的,因此可以用較小次划分把他們歸結到單獨的區域中,或者說只包含它的空間的面積較大)
  因此可以把葉子節點到根節點的路徑h(x)長度來判斷一條記錄x是否是異常點(也就是根據h(x)判斷x是否是異常點)。對於一個包含n條記錄的數據集,其構造的樹的高度最小值為log(n),最大值為n-1,論文中提到說用log(n)和 n-1 歸一化不能保證有界和不方便比較,所以下面用一個稍微復雜一點的歸一化公式:

  S(x,n) 就是記錄x在n個樣本的訓練數據構成的iTree的異常指數,S(x,n)取值范圍為[0,1]。

異常情況的判斷分以下幾種情況

  • 1,越接近1表示是異常點的可能性高
  • 2,越接近0表示是正常點的可能性高
  • 3,如果大部分的訓練樣本的S(x,n)都接近於0.5,說明整個數據集都沒有明顯的異常值
   如果是隨機選屬性,隨機選屬性值,一棵樹這么隨機選肯定不行,但是把多棵樹結合起來就變的強大了。

2,iForest的構建

   iTree明白了,下面我們看看IForest是怎么構造的,給定一個包含n條記錄的數據集D,如何構造一個iForest,iForest和Random Forest的方法有點類似,都是隨機采樣一部分數據集去構造一棵樹,保證不同樹之間的差異性,不過iForest與RF不同,采樣的數據量Psi不需要等於n,可以遠遠小於n,論文提到采樣大小超過256效果就提升不大了,並且越大還會造成計算時間上的浪費,為什么不像其他算法一樣,數據越多效果越好呢?可以看看下面這兩個圖:

  左邊是原始數據,右邊是采樣了數據,藍色是正常樣本,紅色是異常樣本。可以看到,在采樣之前,正常樣本和異常樣本出現重疊,因此很難分開,但我們采樣之和,異常樣本和正常樣本可以明顯的分開。

其構造 iForest 的步驟如下:

  • 1,從訓練數據中隨機選擇 n 個點樣本作為subsample,放入樹的根節點。
  • 2,隨機指定一個維度(attribute),在當前節點數據中隨機產生一個切割點p——切割點產生於當前節點數據中指定維度的最大值和最小值之間。
  • 3,以此切割點生成了一個超平面,然后將當前節點數據空間划分為2個子空間:把指定維度里面小於p的數據放在當前節點的左孩子,把大於等於p的數據放在當前節點的右孩子。
  • 4,在孩子節點中遞歸步驟2和3,不斷構造新的孩子節點,知道孩子節點中只有一個數據(無法再繼續切割)或者孩子節點已達限定高度。

  獲得 t個iTree之后,iForest訓練就結束,然后我們可以用生成的iForest來評估測試數據了。對於一個訓練數據X,我們令其遍歷每一顆iTree,然后計算X 最終落在每個樹第幾層(X在樹的高度)。然后我們可以得到X在每棵樹的高度平均值,即 the average path length over t iTrees。

 

Isolation Forest算法總結

1,異常點檢測算法小結

  IForest目前是異常點檢測最常用的算法之一,它的優點非常突出,他具有線性時間復雜度。因為是隨機森林的方法,所以可以用在含有海量數據的數據集上,通常樹的數量越多,算法越穩定。由於每棵樹都是互相獨立生成的,因此可以部署在大規模分布式系統上來加速運算。對於目前大數據分析的趨勢來說,它的好用是由原因的。

  但是IForest也有一些缺點,比如不適用於特別高維的數據。由於每次切數據空間都是隨機選取一個維度和該維度的隨機一個特征,建完樹后仍然有大量的維度沒有被使用,導致算法可靠性降低。此推薦降維后使用,或者考慮使用One Class SVM 。

  另外IForest僅對即全局稀疏點敏感,不擅長處理局部的相對稀疏點,這樣在某些局部的異常點較多的時候檢測可能不是很准。

  而One Class SVM對於中小型數據分析,尤其是訓練樣本不是特別海量的時候用起來經常會比IForest順手,因此比較適合做原型分析。

2,Isolation Forest算法小結

  • 1,iForest具有線性時間復雜度,因為是ensemble的方法,所以可以用在含有海量數據的數據集上面,通常樹的數量越多,算法越穩定。由於每棵樹都是相互獨立生成的,因此可以部署在大規模分布式系統上來加速運算。
  • 2,iForest不適用於特別高維的數據。由於每次切數據空間都是隨機選取一個維度,建完樹后仍然有大量的維度信息沒有被使用,導致算法可靠性降低。高維空間還可能存在大量噪音維度或者無關維度(irrelevant  attributes),影響樹的構建。對這類數據,建議使用子空間異常檢測(Subspace Anomaly  Detection)技術。此外,切割平面默認是axis-parallel的,也可以隨機生成各種角度的切割平面。
  • 3,IForest僅對Global Anomaly敏感,即全局稀疏點敏感,不擅長處理局部的相對稀疏點(Local Anomaly)。
  • 4,iForest推動了重心估計(Mass Estimation)理論,目前在分類聚類和異常檢測中都取得顯著效果。

 

異常點檢測算法使用場景

  什么時候我們需要異常點檢測算法呢?常用的有三種情況。

  • 1.做數據預處理的時候需要對異常的數據做過濾,防止對歸一化等處理的結果。
  • 2.對沒有標記輸出的特征數據做篩選,找出異常的數據。
  • 3.對有標記輸出的特征數據做二分類時,由於某些類別的訓練樣本非常少,類別嚴重不平衡,此時也可以考慮用非監督的異常點檢測算法來做。

  在以上場景中,異常的數據量都是很少的一部分,因此諸如:SVM,邏輯回歸等分類算法,都不適用,因為監督學習算法適用於有大量的正向樣本,也有大量的負向樣本,有足夠的樣本讓算法去學習其特征,且未來新出現的樣本與訓練樣本分布一致。

  下面是異常檢測和監督學習相關算法的適用范圍:

  • 異常檢測:信用卡詐騙,制造業產品異常檢測,數據中心機器異常檢測,入侵檢測
  • 監督學習:垃圾郵件識別,新聞分類

異常點檢測算法常見類別

  異常點檢測的目的是找到數據集中和大多數數據不同的數據,常用的異常點檢測算法一般分為三類。

  第一類是基於統計學的方法來處理異常數據,這種方法一般會構建一個概率分布模型,並計算對象符合該模型的概率,把具有低概率的對象視為異常點。比如特征工程中的RobustScaler方法,在做數據特征值縮放的時候,它會利用數據特征的分位數分布,將數據根據分位數划分為多段,只取中間段來做縮放,比如只取25%分位數到75%分位數的數據做縮放,這樣減少了異常數據的影響。

  第二類是基於聚類的方法來做異常點檢測。這個很好理解,由於大部分聚類算法是基於數據特征的分布來做的,通常我們聚類后發現某些聚類簇的數據樣本量比其他簇少很多,而且這個簇里的數據特征均值分布之類的值和其他簇也差異很大,這些簇里的樣本點大部分時候都是異常點。比如BIRCH聚類算法原理和DBSCAN密度聚類算法都可以在聚類的同時做異常點的檢測。

  第三類是基於專門的異常點檢測算法來做。這些算法不像聚類算法,檢測異常點只是一個贈品,他們的目的就是專門檢測異常點的,這類算法的代表是One Class SVM 和Isolation Forest。

 

scikit-learn   Isolation Forest算法庫概述

 在sklearn中,我們可以用ensemble包里面的IsolationForest來做異常點檢測

1,知識儲備(np.random.RandomState的用法)

   numpy.random.RandomState():獲取隨機數生成器

   是計算機實現的隨機數生成通常為偽隨機數生成器,為了使得具備隨機性的代碼最終的結果可復現,需要設置相同的種子值。

1
2
3
rng = numpy.random.RandomState(123465)
 
arrayA = rng.uniform(0,1,(2,3))

  該段代碼的目的是產生一個2行3列的assarray,其中的每個元素都是[0,1]區間的均勻分布的隨機數。

  這里可以看到123456這個數字,其實,他是偽隨機數產生器的種子。也就是“the starting point for a sequence of pseudorandom number”

  對於某一個偽隨機數發生器,只要該種子(seed)相同,產生的隨機數序列就是相同的。

 

2,iForest常用參數解釋

  • n_estimators:構建多少個itree
  • max_samples:采樣數,自動是256
  • contamination:c(n)默認是0.1
  • max_features:最大特征數,默認為1
  • bootstrap:構建Tree時,下次是否替換采樣,為True為替換,為False為不替換
  • n_jobs:fit和prdict執行時的並行數  

  完整的參數,請參考scikit-learn官網文檔,這里方便自己學習,就復制到這里。

 

3,iForest常用屬性說明

 

4,iForest常用方法介紹

 

5,實例一(iForest算法檢驗數據)

  isolation Forest 通過隨機選擇一個特征然后隨機選擇所選特征的最大值和最小值之間的分割值來“隔離”觀察。

  代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#_*_coding:utf-8_*_
import numpy  as  np
import matplotlib.pyplot  as  plt
from  sklearn.ensemble import IsolationForest
 
rng = np.random.RandomState(42)
 
# Generate  train data
X = 0.3 * rng.randn(100, 2)
X_train = np.r_[X + 2, X - 2]
X = 0.3 * rng.randn(20, 2)
X_test = np.r_[X + 2, X - 2]
X_outliers = rng.uniform(low=-4, high=4, size=(20, 2))
 
# fit the model
clf = IsolationForest(behaviour= 'new' , max_samples=100,
                       random_state=rng, contamination= 'auto' )
clf.fit(X_train)
y_pred_train = clf.predict(X_train)
y_pred_test = clf.predict(X_outliers)
 
xx, yy = np.meshgrid(np.linspace(-5, 5, 50), np.linspace(-5, 5, 50))
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
 
plt.title( "IsolationForest" )
plt.contourf(xx, yy, Z, camp=plt.cm.Blues_r)
b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c= 'white' ,
                  s=20, edgecolor= 'k' )
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c= 'green' ,
                  s=20, edgecolor= 'k' )
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c= 'red' ,
                 s=20, edgecolor= 'k' )
plt.axis( 'tight' )
plt.xlim((-5, 5))
plt.ylim((-5, 5))
plt.legend([b1, b2, c],
            [ "training observations" ,
             "new regular observations" "new abnormal observations" ],
            loc= "upper left" )
plt.show()

  

  結果展示:

 

6,實例二(多種異常檢測算法比較)

  此示例顯示了2D數據集上不同異常檢測算法的特征。數據集包含一種或兩種模式(高密度區域),以說明算法處理多模態數據的能力。

   對於每個數據集,15%的樣本被生成為隨機均勻噪聲。該比例是給予OneClassSVM的nu參數的值和其他異常值檢測算法的污染參數。除了局部異常因子(LOF)之外,內部和異常值之間的決策邊界以黑色顯示,因為當用於異常值檢測時,它沒有預測方法應用於新數據。

  svm.OneClassSVM被稱為是對異常值敏感,並因此對異常值檢測不執行的非常好。當訓練集未被異常值污染時,該估計器最適合於新穎性檢測。也就是說,高維中的離群檢測,或者對上層數據的分布沒有任何假設是非常具有挑戰性的,並且單類SVM可能在這些情況下根據其超參數的值給出有用的結果。

  covariance.EllipticEnvelope假設數據是高斯數據並學習橢圓。因此,當數據不是單峰時,它會降級。但請注意,此估算器對異常值很穩健。

  ensemble.IsolationForest並且neighbors.LocalOutlierFactor 似乎對多模態數據集表現得相當好。neighbors.LocalOutlierFactor對於第三數據集示出了優於其他估計器的優點 ,其中兩種模式具有不同的密度。這一優勢可以通過LOF的局部方面來解釋,這意味着它只將一個樣本的異常得分與其鄰居的得分進行比較。

  最后,對於最后一個數據集,很難說一個樣本比另一個樣本更異常,因為它們均勻分布在超立方體中。除了svm.OneClassSVM稍微過度擬合之外,所有估算者都為這種情況提供了不錯的解決方案。在這種情況下,更仔細地觀察樣本的異常分數是明智的,因為良好的估計器應該為所有樣本分配相似的分數。

  雖然這些例子給出了一些關於算法的直覺,但這種直覺可能不適用於非常高維的數據。

  最后,請注意模型的參數已經在這里精心挑選,但實際上它們需要進行調整。在沒有標記數據的情況下,問題完全沒有監督,因此模型選擇可能是一個挑戰。

  代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import time
 
import numpy  as  np
import matplotlib
import matplotlib.pyplot  as  plt
 
from  sklearn import svm
from  sklearn.datasets import make_blobs, make_moons
from  sklearn.covariance import EllipticEnvelope
from  sklearn.ensemble import IsolationForest
from  sklearn.neighbors import LocalOutlierFactor
 
matplotlib.rcParams[ 'contour.negative_linestyle' ] =  'solid'
 
# Example settings
n_samples = 300
outliers_fraction = 0.15
n_outliers =  int (outliers_fraction * n_samples)
n_inliers = n_samples - n_outliers
 
# define outlier/ anomaly detection methods to be compared
anomaly_algorithms = [
     ( "Robust covariance" , EllipticEnvelope(contamination=outliers_fraction)),
     ( "One-Class SVM" , svm.OneClassSVM(nu=outliers_fraction, kernel= 'rbf' ,gamma=0.1)),
     ( "Isolation Forest" , IsolationForest(behaviour= 'new' , contamination=outliers_fraction, random_state=42)),
     ( "Local Outlier Factor" , LocalOutlierFactor(n_neighbors=35, contamination=outliers_fraction))
]
 
# define datasets
blobs_params = dict(random_state=0, n_samples=n_inliers, n_features=2)
datasets = [
     make_blobs(centers=[[0, 0], [0, 0]], cluster_std=0.5, **blobs_params)[0],
     make_blobs(centers=[[2, 2], [-2, -2]], cluster_std=[0.5, 0.5], **blobs_params)[0],
     make_blobs(centers=[[2, 2], [-2, -2]], cluster_std=[1.5, 0.3], **blobs_params)[0],
     4. * (make_moons(n_samples=n_samples, noise=0.05, random_state=0)[0] - np.array([0.5, 0.25])),
     14. * (np.random.RandomState(42).rand(n_samples, 2) - 0.5)
]
 
# Compare given classifiers under given settings
xx, yy = np.meshgrid(np.linspace(-7, 7, 150), np.linspace(-7, 7, 150))
 
plt.figure(figsize=(len(anomaly_algorithms) * 2 + 3, 12.5))
plt.subplots_adjust(left=0.02, right=0.98, bottom=0.001, top=0.96, wspace=0.05, hspace=0.01)
 
plot_num = 1
rng = np.random.RandomState(42)
 
 
for  i_dataset, X  in  enumerate(datasets):
     # add outliers
     X = np.concatenate([X, rng.uniform(low=-6, high=6, size=(n_outliers, 2))], axis=0)
     for  name, algorithm  in  anomaly_algorithms:
         print(name , algorithm)
         t0 = time.time()
         algorithm.fit(X)
         t1 = time.time()
         plt.subplot(len(datasets), len(anomaly_algorithms), plot_num)
         if  i_dataset == 0:
             plt.title(name, size=18)
 
         # fit the data and tag outliers
         if  name ==  'Local Outlier Factor' :
             y_pred = algorithm.fit_predict(X)
         else :
             y_pred = algorithm.fit(X).predict(X)
 
         # plot the levels lines and the points
         if  name !=  "Local Outlier Factor" :
             Z = algorithm.predict(np.c_[xx.ravel(), yy.ravel()])
             Z = Z.reshape(xx.shape)
             plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors= 'black' )
 
         colors = np.array([ "#377eb8" '#ff7f00' ])
         plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[(y_pred + 1)  // 2])
 
         plt.xlim(-7, 7)
         plt.ylim(-7, 7)
         plt.xticks(())
         plt.yticks(())
         plt.text(0.99, 0.01, ( '%.2fs'  % (t1 - t0)).lstrip( '0' ),
                  transform=plt.gca().transAxes, size=15,
                  horizontalalignment= 'right' )
         plot_num += 1
 
plt.show()

  結果

 

 

 

參考文獻:https://www.cnblogs.com/pinard/p/9314198.html

 https://www.jianshu.com/p/5af3c66e0410

https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM