指南:不平衡分類的成本敏感決策樹(附代碼&鏈接)

指南:不平衡分類的成本敏感決策樹(附代碼&鏈接)

翻譯:陳超

校對:馮羽

本文約3500字,建議閱讀10+分鐘

本文介紹了不平衡分類中的成本敏感決策樹算法。

決策樹算法對平衡分類是有效的,但在不平衡數據集上卻表現不佳。

決策樹分裂點是為了能夠在最小混淆的情況下將所有實例分成兩組。當兩個組別分別都由其中一個類別的實例佔主導,那麼用於選擇分裂點設置的標準即為合理,而事實上,少數類中的實例將會被忽略。

通過修改評估分裂點的標準並將每一類別的重要性均納入考慮,即可解決這一問題,通常指的是加權的分裂點或者加權的決策樹。

在本指南中,你將看到的是不平衡分類的加權決策樹。

在學習完本指南之後,你將會了解:

  • 標準決策樹算法是怎樣不支持不平衡分類的。
  • 當選擇分裂點時,決策樹算法如何通過類權值對模型誤差進行加權。
  • 如何配置決策樹算法中類的權值以及如何對不同的類權值配置進行網格化搜索。

SMOTE算法,單類別分類,成本敏感學習,閾值移動,以及更多其他內容,請檢索我的新書,內含30個逐步教程以及完整的Python源代碼。

新書鏈接:

https://machinelearningmastery.com/cost-sensitive-decision-trees-for-imbalanced-classification/

好的,我們開始。

指南:不平衡分類的成本敏感決策樹(附代碼&鏈接)

如何對不平衡分類執行加權決策樹

Photo by Bonnie Moreland, some rights reserved.

指南概觀

本指南分為四部分,他們分別是:

一、不平衡分類數據集

二、不平衡分類決策樹

三、Scikit-Learn中使用加權決策樹

四、加權決策樹的網格化搜索

一、不平衡分類數據集

在開始深入到不平衡分類的決策修正之前,我們先定義一個不平衡數據集。

我們可以使用 make_classification()函數來定義一個合成的不平衡兩類別分類數據集。我們將生成10000個實例,其中少數類和多數類的比例為1:100。

make_classification()函數:

https://machinelearningmastery.com/cost-sensitive-decision-trees-for-imbalanced-classification/

<code>...# define datasetX, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,  n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=3)/<code>

一旦生成之後,我們可以總結類的分佈來驗證生成數據集是我們所期望的。

<code>...# summarize class distributioncounter = Counter(y)print(counter)/<code>

最後,我們可以創造一個實例的散點圖並依據類標籤進行著色,來幫助我們理解該數據集中實例分類所面臨的挑戰。

<code>...# scatter plot of examples by class labelfor label, _ in counter.items():  row_ix = where(y == label)[0]  pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))pyplot.legend()pyplot.show()/<code>

將這些代碼整合在一起,生成合成數據集和繪製實例的完整示例。

<code># Generate and plot a synthetic imbalanced classification datasetfrom collections import Counterfrom sklearn.datasets import make_classificationfrom matplotlib import pyplotfrom numpy import where# define datasetX, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,  n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=3)# summarize class distributioncounter = Counter(y)print(counter)# scatter plot of examples by class labelfor label, _ in counter.items():  row_ix = where(y == label)[0]  pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))pyplot.legend()pyplot.show()/<code>

運行這個示例將會先創造一個數據集,然後彙總類的分佈。

我們可以看到這個數據集接近1:100的類的分佈,有比10000個稍微少一些的實例在多數類當中,100個實例在少數類中。

<code>Counter({0: 9900, 1: 100})/<code>

接下來,是數據集的散點圖,該圖展示了大量多數類(藍色)的實例和少量少數類(橙色)的實例,其中有少許類的值重疊。

指南:不平衡分類的成本敏感決策樹(附代碼&鏈接)

1:100類別不平衡性的兩分類數據集散點圖

接下來,我們可以在此數據集上擬合一個標準決策樹模型。決策樹可以使用scikit-learn工具包中的決策樹分類器生成。

決策樹分類器:

https://machinelearningmastery.com/cost-sensitive-decision-trees-for-imbalanced-classification/

<code>...# define modelmodel = DecisionTreeClassifier()/<code>

我們將使用重複交叉驗證來評估此模型,共需三次重複的10層交叉驗證。模型的性能將通過曲線下ROC面積(ROC AUC)在所有重複次以及全部層的均值獲得。

10層交叉驗證:

https://machinelearningmastery.com/k-fold-cross-validation/

<code>...# define evaluation procedurecv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)# evaluate modelscores = cross_val_score(model, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)# summarize performanceprint('Mean ROC AUC: %.3f' % mean(scores))/<code>

在不平衡分類問題上定義和評估一個標準決策樹模型的完整實例如下。

決策樹對二分類任務的有效模型,雖然他們本身對不平衡分類問題並不高效。

<code># fit a decision tree on an imbalanced classification datasetfrom numpy import meanfrom sklearn.datasets import make_classificationfrom sklearn.model_selection import cross_val_scorefrom sklearn.model_selection import RepeatedStratifiedKFoldfrom sklearn.tree import DecisionTreeClassifier# generate datasetX, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,  n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=3)# define modelmodel = DecisionTreeClassifier()# define evaluation procedurecv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)# evaluate modelscores = cross_val_score(model, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)# summarize performanceprint('Mean ROC AUC: %.3f' % mean(scores)) /<code>

運行該實例可評估標準決策樹模型在不平衡數據集上的表現,並報告ROC AUC。

你的特定的結果可能會根據學習算法的固有隨機性而變化。試著多運行幾次。

我們可以看到這個模型能夠實現ROC AUC大於0.5,並實現均值得分為0.746。

<code>Mean ROC AUC: 0.746/<code> 

這為任何標準決策樹算法的改進提供了比較的基線。

二、不平衡分類決策樹

決策樹算法也被叫做分類和迴歸樹(CART),包括生成樹以及從訓練集中分類實例。

分類和迴歸樹:

https://machinelearningmastery.com/classification-and-regression-trees-for-machine-learning/

樹可用於分離訓練集,實例可以經由樹的決策點到達葉節點並且被附上類標籤。

樹可以通過使用數據集中變量的值來分離訓練集從而得到建構。在每一個點上,數據的分離以最貪心的方式使得最純淨的(最少混合的)實例組被選出來。

在這裡,純度意味著實例得到純淨地分離,由只包含0和只包含1的實例組成的類是最純淨的,50-50混合的類是最不純的。常見的純度通常由基尼不純度來計算,雖然也可以通過信息熵(entropy)來計算。

信息熵:

https://machinelearningmastery.com/information-gain-and-mutual-information/

純度測量包括計算一個給定類的實例被誤分類的可能性。計算這些概率包括將每個組中每個類的實例數求和。

分離標準可以被更新,不僅是為了考慮分離的純度,也是為了對每個類的重要性進行加權。

“我們導入成本敏感決策樹的目的是為了修正與某一實例誤分類的損失成比例的權重……”

-《一種導入損失敏感決策樹的實例加權方法》,2002

https://machinelearningmastery.com/cost-sensitive-decision-trees-for-imbalanced-classification/

這可以通過加權和代替每一組別的實例數實現,這裡係數被用於加權和。

更大的權重被分配給更重要的類,更小的權重則賦給不那麼重要的類。

  • 小權重:對節點純度不那麼重要,影響更低。
  • 大權重:對節點純度更重要,影響更高。

小權重可被分配給多數類,能夠提升(降低)節點的純度分數,否則這個節點

可能會看起來排序不那麼好。這可能會使得更多來自多數類的實例被分到少數類裡,並更好地適應少數類裡的實例。

“更高的權值被分配給來自更高誤分類成本的類當中的實例。”

-《從不平衡數據集中學習》,2018,第71頁

https://machinelearningmastery.com/cost-sensitive-decision-trees-for-imbalanced-classification/

正因為如此,對決策樹算法的這一修正被稱為加權決策樹,一個加權類的決策樹,或者是成本敏感決策樹。

分離點計算的修正是最常見的,雖然還有很多修正決策樹建構算法以更好地適應類的不平衡的研究。

三、Scikit-Learn中使用加權決策樹

Scikit-Learn Python 機器學習工具包提供了支持類加權的決策樹算法的實現方法。

決策樹算法提供了可被指定為模型超參數的class_weight參數。class_weight是一個定義每個類標籤(例如,0和1)和應用到擬合模型時,決策樹中分離組純度計算權值的字典。

例如,一個對每個0和1類的1比1的權重可以作如下定義:

<code>...# define modelweights = {0:1.0, 1:1.0}model = DecisionTreeClassifier(class_weight=weights)/<code>

類權值可有多種定義方式,例如:

  • 領域專長:通過與學科專家交談確定;
  • 調參:通過例如網格化搜索的超參數搜索確定;
  • 啟發式:使用一般最佳實踐確定。

使用類加權最好的實踐是使用與訓練集中的類分佈的倒數。

例如,測試集類分佈為少數類:多數類1:100的比例。該比例的倒數是1個多數類和100個少數類。例如:

<code>...# define modelweights = {0:1.0, 1:100.0}model = DecisionTreeClassifier(class_weight=weights)/<code>

我們也可以使用分數定義同樣的比例,並獲得相同的結果。例如:

<code>...# define modelweights = {0:0.01, 1:1.0}model = DecisionTreeClassifier(class_weight=weights)/<code>

啟發式可以通過直接設置class_weight為'balanced'。例如:

<code>...# define modelmodel = DecisionTreeClassifier(class_weight='balanced')/<code>

我們可以通過使用在之前的部分定義的評估程序來對類加權的決策樹算法進行評估。

我們期待類加權決策樹的版本比沒有類加權的標準決策樹算法表現得更好。

完整的實例如下:

<code># decision tree with class weight on an imbalanced classification datasetfrom numpy import meanfrom sklearn.datasets import make_classificationfrom sklearn.model_selection import cross_val_scorefrom sklearn.model_selection import RepeatedStratifiedKFoldfrom sklearn.tree import DecisionTreeClassifier# generate datasetX, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,  n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=3)# define modelmodel = DecisionTreeClassifier(class_weight='balanced')# define evaluation procedurecv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)# evaluate modelscores = cross_val_score(model, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)# summarize performanceprint('Mean ROC AUC: %.3f' % mean(scores))/<code>

運行這一實例可以準備好合成的不平衡分類數據集,然後使用重複交叉驗證評估類加權版的決策樹算法。

你的結果可能會受到算法隨機性的影響,嘗試多運行幾次。

ROC AUC的均值得分被報告,得到比未加權版本的決策樹算法更好的得分:0.759比0.746。

<code>Mean ROC AUC: 0.759/<code>

四、加權決策樹的網格化搜索

使用訓練集的倒數比的類加權是啟發式的一種。

使用不同的類加權可能得到更好的表現,這也過分依賴於評估模型性能度量的選擇。

在這一部分,我們將為加權決策樹進行一系列不同類權重的網格化搜索並探索可得到最佳ROC AUC的結果。

我們將嘗試下述對0類和1類的權重:

  • 類0:100,類1:1;
  • 類0:10,類1:1;
  • 類0:1,類1:1;
  • 類0:1,類1:100。

這些可被定義為GridSearchCV類的網格化搜索參數如下:

GridSearchCV類:

https://machinelearningmastery.com/cost-sensitive-decision-trees-for-imbalanced-classification/

<code>...# define gridbalance = [{0:100,1:1}, {0:10,1:1}, {0:1,1:1}, {0:1,1:10}, {0:1,1:100}]param_grid = dict(class_weight=balance)/<code>

我們可以使用重複交叉驗證對這些參數進行網格化搜索,並使用ROC AUC估計模型的表現:

<code>...# define evaluation procedurecv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)# define grid searchgrid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=cv, scoring='roc_auc')/<code>

一旦執行後,我們可以總結最佳配置,以及所有的結果如下:‍

<code>...# report the best configurationprint("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))# report all configurationsmeans = grid_result.cv_results_['mean_test_score']stds = grid_result.cv_results_['std_test_score']params = grid_result.cv_results_['params']for mean, stdev, param in zip(means, stds, params):    print("%f (%f) with: %r" % (mean, stdev, param))/<code>

以下實例為不平衡數據集上的決策樹算法,對五種不同的類權重進行網格化搜索。

我們可能會期待啟發式類權重是最好的配置。

<code># grid search class weights with decision tree for imbalance classificationfrom numpy import meanfrom sklearn.datasets import make_classificationfrom sklearn.model_selection import GridSearchCVfrom sklearn.model_selection import RepeatedStratifiedKFoldfrom sklearn.tree import DecisionTreeClassifier# generate datasetX, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,  n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=3)# define modelmodel = DecisionTreeClassifier()# define gridbalance = [{0:100,1:1}, {0:10,1:1}, {0:1,1:1}, {0:1,1:10}, {0:1,1:100}]param_grid = dict(class_weight=balance)# define evaluation procedurecv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)# define grid searchgrid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=cv, scoring='roc_auc')# execute the grid searchgrid_result = grid.fit(X, y)# report the best configurationprint("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))# report all configurationsmeans = grid_result.cv_results_['mean_test_score']stds = grid_result.cv_results_['std_test_score']params = grid_result.cv_results_['params']for mean, stdev, param in zip(means, stds, params):    print("%f (%f) with: %r" % (mean, stdev, param))/<code>

運行該實例使用重複k層交叉驗證來評估每一個類權重,並報告最佳配置以及相關的平均ROC AUC得分。

你的結果可能會隨著學習算法的隨機性而變化,嘗試多運行幾次。

在這種情況下,我們可以看到1:100的多數:少數類比加權可以實現最佳的均值ROC得分。這與一般啟發式的配置相匹配。

探索更嚴格的類權值來看其對ROC AUC均值得分的影響可能會很有趣。

<code>Best: 0.752643 using {'class_weight': {0: 1, 1: 100}}0.737306 (0.080007) with: {'class_weight': {0: 100, 1: 1}}0.747306 (0.075298) with: {'class_weight': {0: 10, 1: 1}}0.740606 (0.074948) with: {'class_weight': {0: 1, 1: 1}}0.747407 (0.068104) with: {'class_weight': {0: 1, 1: 10}}0.752643 (0.073195) with: {'class_weight': {0: 1, 1: 100}}/<code>

更多閱讀

如果你想更深入瞭解,本部分提供了更多相關資源。

  • 論文
  • 《一種導入成本敏感決策樹的實例加權方法》,2002.https://machinelearningmastery.com/cost-sensitive-decision-trees-for-imbalanced-classification/
  • 書籍
  • 《從不平衡數據中學習》,2018https://amzn.to/307Xlva
  • 《不平衡學習:基礎,算法和應用》,2013https://amzn.to/32K9K6d
  • API
  • sklearn.utils.class_weight.compute_class_weight API:https://scikit-learn.org/stable/modules/generated/sklearn.utils.class_weight.compute_class_weight.html
  • sklearn.tree.DecisionTreeClassifier API:https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
  • sklearn.model_selection.GridSearchCV API:https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html

總結

在本指南中,你探索了不平衡分類的加權決策樹。特別地,你學到了:

  • 標準決策樹算法怎樣不支持不平衡分類;
  • 當選擇分裂點時,決策樹算法如何通過類權值對模型誤差進行加權;
  • 如何配置決策樹算法中類的權值以及如何對不同的類權值配置進行網格化搜索。

原文標題:

Cost-Sensitive Decision Trees for Imbalanced Classification

原文鏈接:

https://machinelearningmastery.com/cost-sensitive-decision-trees-for-imbalanced-classification

校對:楊學俊

譯者簡介

指南:不平衡分類的成本敏感決策樹(附代碼&鏈接)

陳超,北京大學應用心理碩士在讀。本科曾混跡於計算機專業,後又在心理學的道路上不懈求索。越來越發現數據分析和編程已然成為了兩門必修的生存技能,因此在日常生活中盡一切努力更好地去接觸和了解相關知識,但前路漫漫,我仍在路上。

—完—

關注清華-青島數據科學研究院官方微信公眾平臺“ THU數據派 ”及姊妹號“ 數據派THU ”獲取更多講座福利及優質內容。


分享到:


相關文章: