无监督算法与异常检测
一、整體概覽
? ? ? ?反欺詐往往看做是二分類問題,但是仔細想想是多分類問題,因為每種不同類型的欺詐都當做是一種單獨的類型。欺詐除了多樣并且不斷變化,欺詐檢測還面臨一下問題:
? ? ? 1). 由于大部分情況數據是沒有標簽的,各種成熟的監督學習是沒有辦法應用
? ? ? 2). 區分噪音和異常點時難度比較大,甚至需要一點點經驗
? ? ? 3). 當多種不同的欺詐結合在一起時,區分欺詐類型比較難,因為不了解每一種欺詐定義
? ? ? 4). 即使有真的欺詐數據,即在有標簽的情況下用監督學習,也存在很大的不確定性。用這種歷史數據學出的模型只能檢測當時存在以及比較相似的欺詐,而對于不同的詐騙和從未見過的詐騙,模型預測效果一般比較差。
? ? ? ?因此,在實際情況中,一般不直接用任何監督學習,或者說不能至少單獨依靠一個監督學習模型來奢求檢測到所有的欺詐。沒有歷史標簽和對詐騙的理解,無法做出對詐騙細分的模型。一般常見的做法是使用無監督模型,且需要不同專家根據經驗來驗證預測,提供反饋,便于及時調整模型。
? ? ? 拿到含有欺詐的數據之后,一般做法有通過關聯矩陣分析以及多維尺度變換。
?
二、無監督學習
? ? ? ? 當一個場景需要做預判的時候,有沒有標簽,往往能做的主要有遷移學習、專家模型、無監督算法。
? ?遷移學習
? ? 源域樣本和目標域樣本分布有比較大的區別,目標域樣本量不夠的話,通過算法縮小邊緣分布之間和條件分布之間的差異。
- 基于特征的遷移
- 基于模型的遷移
- 基于實例的遷移
? ?不足之處:需要擁有與當前目標場景相關的源域數據
? ?專家模型
? ? 主要是根據主觀經驗進行評判,而不是根據統計分析或者模型算法來進行客觀的計算。常規操作過程如下所示:
- ?根據相關經驗判斷特征重要性
- ?根據相關經驗進行變量加權
? ?不足之處:需要大量的行業經驗積累,有時候不太具有說服性
? ?無監督算法
? ? ? ?缺乏足夠的先驗知識,無法對數據進行標記時,使用的一種機器學習方法,代表聚類、降維等。在風控領域中主要使用的是聚類和無監督異常檢測。聚類是發現樣本之間的相似性,異常檢測是發現樣本之間的差異性。
? ? 聚類
- ?K-Means
- DBSCAN
- 層次聚類
- 社區發現
? ? ? ? 一般主要是對負樣本聚類,將有問題的用戶細分為幾類。社區發現算法一般是識別團伙欺詐的主要手段之一,主要方法是通過知識圖譜將小團體篩選出來。在知識圖譜中,聚集意味著風險。
? ? ?異常檢測
? ? ? ?異常點檢測,通常也被稱為離群點檢測,是找出與預期對象的行為差異較大的對象的一個檢測過程。檢測出來的數據被稱為異常點或者離群點。異常點在生產生活中有比較多的應用,例如廣告點擊反作弊、設備損壞等。異常點是一個數據對象,明顯不同于其他的數據對象。如下所示,N1,N2為區域內的正常數據,而離這兩個正常區域比較遠的地方的點為異常點。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? 異常檢測和不均衡學習的區別是,異常檢測一般是無監督的;與普通的二分類區別是異常檢測往往看作為是二分類,但是其實是多分類(由于造成異常的原因各不相同)
? ? ? ?異常檢測算法的前提假設:1) 異常數據跟樣本中大多數數據不太一樣? 2) 異常數據在整體數據樣本中占比相對比較小
? ? ? ?異常檢測的主要思想是基于樣本(小群體)之間的相似度: 距離、密度、簇
? ? ? ?異常檢測算法的意義:
? ? ? ? 1). 很多場景沒有標簽或者標簽比較少,不能訓練監督模型
? ? ? ? 2). 樣本總是在發生變換,只能從一個小群體內部發現異常
? ? ? ? 3). 異常檢測假設異常樣本數據量占比較少,并且在某種維度上遠離其他樣本,符合個體欺詐的先驗知識。在團體欺詐不太適用。
? ? ? ? 4). 樣本群體有異構成分,可以對樣本進行篩選
三、異常檢測的常用算法
? ? ? ? ?常見的異常檢測算法有Z-score算法、KNN算法、Local Outlier Factor、孤立森林等
? ? Z-score算法
? ? ? ? 假設樣本服從正態分布,用于描述樣本偏離正態分布的程度。通過計算μ和σ得到當前樣本所屬于的正態分布的表達式,然后分別計算每個樣本在這個概率密度函數下被生成的概率,當概率小于某一閾值我們認為這個樣本是不屬于這個分布的,因此定義為異常值。計算公式如下所示:
? ? ? ?
? 根據獲取平均值和方差的估計值,然后給定一個新的訓練實例,根據模型計算p(x):
? 當p(x) < ep(x) < e時候,數據未異常
? 缺點是需要假設樣本滿足正態分布,而大部分場景不滿足正態分布假設條件
? ? ? KNN異常檢測
? ? ? ?KNN算法專注于全局異常檢測,所以無法檢測到局部異常。
? ? ? ?首先,對于數據集中的每條記錄,必須找到k個最近的鄰居。然后使用這K個鄰居計算異常分數。
我們有三種方法
- 最大:使用到第k個鄰居的距離作為離群值得分
- 平均值:使用所有k個鄰居的平均值作為離群值得分
- 中位數:使用到k個鄰居的距離的中值作為離群值得分
? ? ? ?在實際方法中后兩種的應用度較高。然而,分數的絕對值在很大程度上取決于數據集本身、維度數和規范化。參數k的選擇當然對結果很重要。如果選擇過低,記錄的密度估計可能不可靠。(即過擬合)另一方面,如果它太大,密度估計可能太粗略。K值的選擇通常在10<k<50這個范圍內。所以在分類方法中,選擇一個合適的K值,可以用交叉驗證法。但是,事實上基于KNN的算法都是不適用于欺詐檢測的,因為他們本身就對噪聲比較敏感。
? ? ?Local Outlier Factor
? ? ? 基于密度的LOF算法相對比較更加簡單、直觀以及不需要對數據的分布有太多的要求,還能量化每個數據點的異常程度。該算法是基于密度的算法,主要核心的部分是關于數據點密度的刻畫。算法的整個流程涉及如下概念:
? ? ?1)k-近鄰距離(k-distance): 在距離數據點p最近的幾個點中,第k個最近的點跟點p之間的距離稱為點p的k-近鄰距離,記為k-distance(p).
? ? ?2)? 可達距離(rechability distance): 可達距離的定義跟k-近鄰距離是相關的,給定參數k時,數據點p到數據點o的可達距離reach-dist(p,o)為數據點o的K-近鄰距離和數據點p與點o之間的直接距離的最大值。即:
? ? ? ? ? ? ? ? ? ? reachdist-k(p,o) = max{k-distance(o),d(p,o)}
? ? ?3) 局部可達密度(local rechablity density):局部可達密度的定義是基于可達距離的,對于數據點p,那些跟點p的距離小于等于k-distance(p)的數據點稱為它的k-nearest-neighor,記為Nk(p),數據點p的局部可達密度為它與鄰近的數據點的平均可達距離的倒數,即:
?
? ? ?4) 局部異常因子:?根據局部可達密度的定義,如果一個數據點跟其他點比較疏遠的話,那么顯然它的局部可達密度就小。但LOF算法衡量一個數據點的異常程度,并不是看它的絕對局部密度,而是看它跟周圍鄰近的數據點的相對密度。這樣做的好處是可以允許數據分布不均勻、密度不同的情況。局部異常因子即是用局部相對密度來定義的。數據點 p 的局部相對密度(局部異常因子)為點p的鄰居們的平均局部可達密度跟數據點p的局部可達密度的比值,即:
? ? ??根據局部異常因子的定義,如果數據點 p 的 LOF 得分在1附近,表明數據點p的局部密度跟它的鄰居們差不多;如果數據點 p 的 LOF 得分小于1,表明數據點p處在一個相對密集的區域,不像是一個異常點;如果數據點 p 的 LOF 得分遠大于1,表明數據點p跟其他點比較疏遠,很有可能是一個異常點。
? ? ? ?小結:整個LOF算法,首先對于每個數據點,計算它與其它所有點的距離,并按從近到遠排序,然后對于每個數據點,找到它的k-nearest-neighbor,最后計算LOF得分。
/******** LOF算法 ********/from pyod.models.lof import LOF clf = LOF(n_neighbors=20, algorithm='auto', leaf_size=30, metric='minkowski', p=2, metric_params=None, contamination=0.1, n_jobs=1) clf.fit(x)? 計算出每一個數據點的LOF值,然后在二維空間中展示,如下圖所示,數據點的LOF值越大表示該點越異常
? ? ? ?
? ?Trick: LOF算法中關于局部可達密度的定義其實暗含了一個假設,即:不存在大于等于 k 個重復的點。當這樣的重復點存在的時候,這些點的平均可達距離為零,局部可達密度就變為無窮大,會給計算帶來一些麻煩。在實際應用時,為了避免這樣的情況出現,可以把 k-distance 改為 k-distinct-distance,不考慮重復的情況。或者,還可以考慮給可達距離都加一個很小的值,避免可達距離等于零。
? ? ? Isolation Forest
? ? ? ? 先用一個簡單的例子來說明 Isolation Forest 的基本想法。假設現在有一組一維數據(如下圖所示),我們要對這組數據進行隨機切分,希望可以把點 A 和點 B 單獨切分出來。具體的,我們先在最大值和最小值之間隨機選擇一個值 x,然后按照 =x 可以把數據分成左右兩組。然后,在這兩組數據中分別重復這個步驟,直到數據不可再分。顯然,點 B 跟其他數據比較疏離,可能用很少的次數就可以把它切分出來;點 A 跟其他數據點聚在一起,可能需要更多的次數才能把它切分出來。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ?我們把數據從一維擴展到兩維。同樣的,我們沿著兩個坐標軸進行隨機切分,嘗試把下圖中的點A'和點B'分別切分出來。我們先隨機選擇一個特征維度,在這個特征的最大值和最小值之間隨機選擇一個值,按照跟特征值的大小關系將數據進行左右切分。然后,在左右兩組數據中,我們重復上述步驟,再隨機的按某個特征維度的取值把數據進行細分,直到無法細分,即:只剩下一個數據點,或者剩下的數據全部相同。跟先前的例子類似,直觀上,點B'跟其他數據點比較疏離,可能只需要很少的幾次操作就可以將它細分出來;點A'需要的切分次數可能會更多一些。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ?按照先前提到的關于“異常”的兩個假設,一般情況下,在上面的例子中,點B和點B' 由于跟其他數據隔的比較遠,會被認為是異常數據,而點A和點A' 會被認為是正常數據。直觀上,異常數據由于跟其他數據點較為疏離,可能需要較少幾次切分就可以將它們單獨劃分出來,而正常數據恰恰相反。這其實正是Isolation Forest(IF)的核心概念。IF采用二叉樹去對數據進行切分,數據點在二叉樹中所處的深度反應了該條數據的“疏離”程度。整個算法大致可以分為兩步:
- 訓練:抽取多個樣本,構建多棵二叉樹(Isolation Tree,即 iTree);
- 預測:綜合多棵二叉樹的結果,計算每個數據點的異常分值。
? ? ? 訓練:構建一棵 iTree 時,先從全量數據中抽取一批樣本,然后隨機選擇一個特征作為起始節點,并在該特征的最大值和最小值之間隨機選擇一個值,將樣本中小于該取值的數據劃到左分支,大于等于該取值的劃到右分支。然后,在左右兩個分支數據中,重復上述步驟,直到滿足如下條件:
- 數據不可再分,即:只包含一條數據,或者全部數據相同。
- 二叉樹達到限定的最大深度。
? ? ? 預測:計算數據 x 的異常分值時,先要估算它在每棵 iTree 中的路徑長度(也可以叫深度)。具體的,先沿著一棵 iTree,從根節點開始按不同特征的取值從上往下,直到到達某葉子節點。假設 iTree 的訓練樣本中同樣落在 x 所在葉子節點的樣本數為 T.size,則數據 x 在這棵 iTree 上的路徑長度 h(x),可以用下面這個公式計算:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? h(x)=e+C(T.size)
公式中,e 表示數據 x 從 iTree 的根節點到葉節點過程中經過的邊的數目,C(T.size) 可以認為是一個修正值,它表示在一棵用 T.size 條樣本數據構建的二叉樹的平均路徑長度。一般的,C(n) 的計算公式如下:
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?C(n)=2H(n?1)?2(n?1)/n
其中,H(n-1) 可用 ln(n-1)+0.577 估算,這里的常數是歐拉常數。數據 x 最終的異常分值 Score(x) 綜合了多棵 iTree 的結果
公式中,E(h(x)) 表示數據 x 在多棵 iTree 的路徑長度的均值,φ表示單棵 iTree 的訓練樣本的樣本數,C(φ)表示用φ條數據構建的二叉樹的平均路徑長度,它在這里主要用來做歸一化。
從異常分值的公式看,如果數據 x 在多棵 iTree 中的平均路徑長度越短,得分越接近 1,表明數據 x 越異常;如果數據 x 在多棵 iTree 中的平均路徑長度越長,得分越接近 0,表示數據 x 越正常;如果數據 x 在多棵 iTree 中的平均路徑長度接近整體均值,則打分會在 0.5 附近。
四、應用案例
1、清洗建模數據集,將異常樣本通過無監督算法進行篩選
from pyod.models.iforest import IForest from matplotlib import pyplot as pltclf = IForest(behaviour='new', bootstrap=False, contamination=0.1, max_features=1.0,max_samples='auto', n_estimators=500, n_jobs=-1, random_state=None,verbose=0) clf.fit(x)out_pred = clf.predict_proba(x,method ='linear')[:,1] train['out_pred'] = out_predx = train[train.out_pred< 0.7][feature_lst] y = train[train.out_pred < 0.7]['bad_ind']val_x = val[feature_lst] val_y = val['bad_ind']lr_model = LogisticRegression(C=0.1,class_weight='balanced') lr_model.fit(x,y) y_pred = lr_model.predict_proba(x)[:,1] fpr_lr_train,tpr_lr_train,_ = roc_curve(y,y_pred) train_ks = abs(fpr_lr_train - tpr_lr_train).max() print('train_ks : ',train_ks)y_pred = lr_model.predict_proba(val_x)[:,1] fpr_lr,tpr_lr,_ = roc_curve(val_y,y_pred) val_ks = abs(fpr_lr - tpr_lr).max() print('val_ks : ',val_ks)plt.plot(fpr_lr_train,tpr_lr_train,label = 'train LR') plt.plot(fpr_lr,tpr_lr,label = 'evl LR') plt.plot([0,1],[0,1],'k--') plt.xlabel('False positive rate') plt.ylabel('True positive rate') plt.title('ROC Curve') plt.legend(loc = 'best') plt.show()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
2、通過樣本異常程度進行分析
train.out_pred.groupby(train.obs_mth).mean()train.out_pred.groupby(train.obs_mth).max()train.out_pred.groupby(train.obs_mth).var()train['for_pred'] = np.where(train.out_pred>0.7,1,0)train.for_pred.groupby(train.obs_mth).sum()/train.for_pred.groupby(train.obs_mth).count()#看一下badrate train.bad_ind.groupby(train.for_pred).sum()/train.bad_ind.groupby(train.for_pred).count()3、冷啟動,假設沒有標簽
y_pred = clf.predict_proba(x,method ='linear')[:,1] fpr_lr_train,tpr_lr_train,_ = roc_curve(y,y_pred) train_ks = abs(fpr_lr_train - tpr_lr_train).max() print('train_ks : ',train_ks)y_pred = clf.predict_proba(val_x,method ='linear')[:,1] fpr_lr,tpr_lr,_ = roc_curve(val_y,y_pred) val_ks = abs(fpr_lr - tpr_lr).max() print('val_ks : ',val_ks) from matplotlib import pyplot as plt plt.plot(fpr_lr_train,tpr_lr_train,label = 'train LR') plt.plot(fpr_lr,tpr_lr,label = 'evl LR') plt.plot([0,1],[0,1],'k--') plt.xlabel('False positive rate') plt.ylabel('True positive rate') plt.title('ROC Curve') plt.legend(loc = 'best') plt.show()參考文獻:https://pyod.readthedocs.io/en/latest/pyod.html
總結
以上是生活随笔為你收集整理的无监督算法与异常检测的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 社交网络分析与反欺诈
- 下一篇: 不均衡学习