減少信用卡欺詐識別誤殺:基於代價敏感的AdaCost演算法(改寫skle
我們平時訓練一個辨別好壞的分類模型,會遇到兩個棘手的問題:
1、類別不平衡,壞的樣本量往往遠遠小於好的;
2、錯分代價不均等,漏殺和誤殺帶來的影響視具體問題完全不同。
本文改寫了sklearn中的AdaBoost的原始碼,使大家可以自由決定漏殺和誤殺對分類器的影響。採用的樣例資料是kaggle信用卡欺詐資料集。
代價矩陣
——讓我們一起復習一下西瓜書第35-36頁的內容
在一些場景下,當分類器將一個樣本錯分時,造成的後果是不同的,
有的時候需要保證正確:醫生把患者誤診為健康 比 把健康人誤診為患者後果更嚴重;
有的時候需要保證全面:門禁系統寧可冤枉好人也不能漏掉壞人;
所以可以根據分類任務的領域知識設定一個代價矩陣:
預測0類 | 預測1類 | |
---|---|---|
真實0類 | 0 | cost_01 |
真實1類 | cost_10 | 0 |
若預測=真實,無代價,即cost_11 = cost_00 = 0,
若將0判為1的損失更大,則 cost_01 > cost_10, 反之亦然,
損失程度相差越大,cost_01和 cost_10值的差別就要越大。
AdaBoost 和 AdaCost演算法原理比較
AdaBoost是基於boost方法的樹整合演算法,核心策略是每一輪迭代完成,更新樣本的權重和基分類器權重,這兩個權重是理解演算法以及看懂原始碼的關鍵,先回顧下AdaBoost的訓練過程:
AdaBoost的訓練過程.JPG
從Adaboost步驟7的公式可以看到:
對正確分類的例項,樣本權重調整係數為exp(-αt),都以相同的比例降低權重,
對所有的誤分類例項,樣本權重調整係數為exp(αt),都以相同的比例增加權重。
但是在AdaCost中,對於代價高的誤分類樣本,我們應該大大提高其權重。
實現方法是在調整係數的基礎上再乘以一個代價係數βi,所以AdaCost的樣本權重按照如下公式進行更新:
AdaCost樣本權重更新公式.png
原始碼改寫
看了上面的公式比較,改寫的方法也就明晰了,只需要在調節樣本權重的公式中,乘以代價係數βi,βi應該是一個代價調整函式,根據每次迭代每個樣本的誤判情況調整。
我的改寫方法也是非常簡單粗暴了,為了方便起見,令代價小的誤判和正確的判斷調整係數都為1,直接對代價高的誤判賦一個大於1的值,起到調高係數的作用。(見下面的程式碼)
定義AdaCostClassifier類,要做的三個工作:
1、繼承AdaBoostClassifier
2、改寫類中的self._boost_real 方法,因為權重更新的公式在這裡
3、在類中增加定義代價函式,返回的結果即使代價因子,供2中的更新公式使用
#!/usr/bin/env python3# -*- coding:utf-8 -*-import numpy as npfrom numpy.core.umath_tests import inner1dfrom sklearn.ensemble import AdaBoostClassifierclass AdaCostClassifier(AdaBoostClassifier): def _boost_real(self, iboost, X, y, sample_weight, random_state): """Implement a single boost using the SAMME.R real algorithm.""" estimator = self._make_estimator(random_state=random_state) estimator.fit(X, y, sample_weight=sample_weight) y_predict_proba = estimator.predict_proba(X) if iboost == 0: self.classes_ = getattr(estimator, 'classes_', None) self.n_classes_ = len(self.classes_) y_predict = self.classes_.take(np.argmax(y_predict_proba, axis=1), axis=0) incorrect = y_predict != y estimator_error = np.mean( np.average(incorrect, weights=sample_weight, axis=0)) if estimator_error <= 0: return sample_weight, 1., 0. n_classes = self.n_classes_ classes = self.classes_ y_codes = np.array([-1. / (n_classes - 1), 1.]) y_coding = y_codes.take(classes == y[:, np.newaxis]) proba = y_predict_proba # alias for readability proba[proba < np.finfo(proba.dtype).eps] = np.finfo(proba.dtype).eps estimator_weight = (-1. * self.learning_rate * (((n_classes - 1.) / n_classes) * inner1d(y_coding, np.log(y_predict_proba)))) # 樣本更新的公式,只需要改寫這裡 if not iboost == self.n_estimators - 1: sample_weight *= np.exp(estimator_weight * ((sample_weight > 0) | (estimator_weight < 0)) * self._beta(y, y_predict)) # 在原來的基礎上乘以self._beta(y, y_predict),即代價調整函式 return sample_weight, 1., estimator_error # 新定義的代價調整函式 def _beta(self, y, y_hat): res = [] for i in zip(y, y_hat): if i[0] == i[1]: res.append(1) # 正確分類,係數保持不變,按原來的比例減少 elif i[0] == 1 and i[1] == -1: res.append(1.25) # 在信用卡的情景下,將好人誤殺代價應該更大一些,比原來的增加比例要高 elif i[0] == -1 and i[1] == 1: res.append(1) # 將負例誤判為正例,代價不變,按原來的比例增加 else: print(i[0], i[1]) return np.array(res)
信用卡資料實戰
資料集地址:
資料量284807,31個特徵
284315個正例,492個負例,嚴重不平衡,
控制相同的訓練集和測試集,相同的引數(基分類器的個數n_estimators=100),訓練原始的AdaBoost 和改寫後的AdaCoost並比較兩者的結果:
#!/usr/bin/env python3# -*- coding:utf-8 -*-import pandas as pdfrom adacost import AdaCostClassifier # 上節定義好的類,我把它單獨放在了adacost.py 檔案中from sklearn.ensemble import AdaBoostClassifierfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import recall_score, precision_score, f1_scoredef load_creditcard_data(): # 將資料集讀進來,注意將正例標記為1,負例標記為-1 df = pd.read_csv('creditcard.csv') df.loc[df.Class == 1, 'Class'] = -1 df.loc[df.Class == 0, 'Class'] = 1 print(df.shape) print(df.Class.value_counts()) return df.drop('Class', axis=1), df['Class']def compare(clfs): # 比較不同分類器的結果 for clf in clfs: y_pred = clf.predict(X_test) print(pd.Series(y_pred).value_counts()) print(recall_score(y_test, y_pred, pos_label=-1), precision_score(y_test, y_pred, pos_label=-1), f1_score(y_test, y_pred, pos_label=-1), 'n') returnif __name__ == '__main__': X, y = load_creditcard_data() X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0) print(pd.Series(y_test).value_counts()) clf1 = AdaBoostClassifier(n_estimators=100) clf1.fit(X_train, y_train) clf2 = AdaCostClassifier(n_estimators=100) clf2.fit(X_train, y_train) compare([clf1, clf2])
模型評估
採用三個評價指標來評估模型:
1、召回率 recall,
2、準確率 precision,本案例假設我們想盡量減少模型誤判,而對漏判比較
寬容,所以對precision的要求更高
3、f1score
不加代價的AdaBoost:
整體效果是可以的,但是真實情況下91%的準確率,即好人誤殺率達到了9%,不能算作一個好的欺詐檢測模型。
AdaBoost | recall | precision | f1score |
---|---|---|---|
0.74 | 0.91 | 0.81 |
AdaCost我試了三個代價係數值,得到的結果如下:
AdaCost | recall | precision | f1score |
---|---|---|---|
β=1.25 | 0.56 | 0.95 | 0.71 |
β=1.45 | 0.44 | 0.98 | 0.54 |
β=1.8 | 0.37 | 1.0 | 0.60 |
比較上面兩個表可以看出:
隨著代價係數的提高,精確率可以一直提升到1,但同時也犧牲掉了一部分的召回率,我們要根據自己的業務目的,權衡好兩個指標,選擇一個合理的代價係數。
結語
其實這不是一個完美的最佳化,畢竟最佳化完以後f1score還下降了,可以完善的地方還有:
1、對於正判的樣本,樣本權重可以降低的少一點
2、模型還可以進行細緻的調參
並且,同樣的演算法對不同的資料集的影響是有很大差異的,我們要適應這一點,大家可以試試在這份資料的基礎上改一下正負樣本比例或者是特徵的個數,看一下資料集對結果的影響。
以上就是這次的簡單實驗<(‵^′)>
作者:雙er
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1868/viewspace-2815975/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Stripe如何解決信用卡欺詐? - Patrick
- 如何使用六西格瑪識別欺詐行為?
- 基於DNN的人臉識別中的反欺騙機制DNN
- 資料探勘—邏輯迴歸分類—信用卡欺詐分析邏輯迴歸
- MATLAB——基於影像相減的紙牌識別系統Matlab
- 機器學習專案實戰----信用卡欺詐檢測(二)機器學習
- 機器學習專案實戰----信用卡欺詐檢測(一)機器學習
- opencv python 基於KNN的手寫體識別OpenCVPythonKNN
- opencv python 基於SVM的手寫體識別OpenCVPython
- 金融反欺詐-交易基礎介紹
- 泰國銀行考慮使用區塊鏈技術進行跨境支付並減少欺詐行為區塊鏈
- 金融風控反欺詐之圖演算法演算法
- 知物由學 | 基於DNN的人臉識別中的反欺騙機制DNN
- 基於精益管理減少手術室耗材
- 信用卡數字識別
- 面部識別必看!5篇頂級論文了解如何實現人臉反欺詐、跨姿勢識別
- TrOCR:基於Transformer的新一代光學字元識別ORM字元
- 基於圖資料庫 NebulaGraph 實現的欺詐檢測方案及程式碼示例資料庫
- 基於OCaml的識別程式
- 演算法識別(一)--TEA及其魔改演算法
- MySQL的SQL等價改寫MySql
- 機器學習演算法(九): 基於線性判別模型的LDA手寫數字分類識別機器學習演算法模型LDA
- 關於洗牌演算法的錯誤認識演算法
- 金融欺詐資料分析
- 基於MATLAB的指紋識別演算法模擬實現Matlab演算法
- 基於Vue2和Node.js的反欺詐系統設計與實現VueNode.js
- DataFun Talk演算法架構系列活動——智慧時代:風控及反欺詐體系搭建演算法架構
- 基於MATLAB公式識別Matlab公式
- 基於Flink的超大規模線上實時反欺詐系統的建設與實踐
- YouGov:1/5的千禧一代為減少對地球的影響改變了飲食Go
- 基於PHP + TRIE樹實現敏感詞過濾演算法PHP演算法
- TRIZ在減少人為誤差原理上的應用
- 深度學習例項之基於mnist的手寫數字識別深度學習
- 主動學習入門篇:如何能夠顯著地減少標註代價
- 基於滴滴雲 GPU 實現簡單 MINIST 手寫識別GPU
- 基於 Tire 樹的敏感詞檢測
- 信用卡欺詐行為邏輯迴歸資料分析-大資料ML樣本集案例實戰邏輯迴歸大資料
- 遊戲畫面如何去減少廉價感遊戲