機器學(xué)習(xí)中樣本不平衡,怎么辦?
在銀行要判斷一個"新客戶是否會違約",通常不違約的人VS違約的人會是99:1的比例,真正違約的人 其實是非常少的。這種分類狀況下,即便模型什么也不做,全把所有人都當(dāng)成不會違約的人,正確率也能有99%, 這使得模型評估指標(biāo)變得毫無意義,根本無法達(dá)到我們的"要識別出會違約的人"的建模目的。
像這樣樣本不均衡等例子在生活中隨處可見。通常出現(xiàn)在異常檢測、客戶流失、罕見時間分析、發(fā)生低頻率事件等場景,具體如垃圾郵件等識別,信用卡征信問題、欺詐交易檢測、工廠中不良品檢測等。
在處理諸如此類的樣本不均衡的任務(wù)中,使用常規(guī)方法并不能達(dá)到實際業(yè)務(wù)需求,正確且盡可能多捕獲少數(shù)類樣本。因為樣本不均衡會使得分類模型存在很嚴(yán)重的偏向性。
本文中,介紹了在機器學(xué)習(xí)中樣本不平衡處理策略及常用方法和工具。
樣本不平衡分類
數(shù)據(jù)集中各個類別的樣本數(shù)量極不均衡,從數(shù)據(jù)規(guī)模上可分為:
- 大數(shù)據(jù)分布不均衡。整體數(shù)據(jù)規(guī)模大,小樣本類的占比較少,但小樣本也覆蓋了大部分或全部特征。
- 小數(shù)據(jù)分布不均衡。整體數(shù)據(jù)規(guī)模小,少數(shù)樣本比例的分類數(shù)量也少,導(dǎo)致特征分布嚴(yán)重不均衡。
樣本分布不均衡在于不同類別間的樣本比例差異,導(dǎo)致很難從樣本中提取規(guī)律。一般超過10倍就需要引起注意,20倍就一定要處理了。
樣本不平衡處理策略
擴大數(shù)據(jù)集
樣本不平衡時,可以增加包含一定比例小類樣本數(shù)據(jù)以擴大數(shù)據(jù)集,更多的數(shù)據(jù)往往戰(zhàn)勝更好的算法。因為機器學(xué)習(xí)是使用現(xiàn)有的數(shù)據(jù)多整個數(shù)據(jù)的分布進行估計,因此更多的數(shù)據(jù)往往能夠得到更多的分布信息,以及更好分布估計。
但有時在增加小類樣本數(shù)據(jù)的同時,也增加了大類數(shù)據(jù),并不能顯著解決樣本不平衡問題。此時可以通過對大類樣本數(shù)據(jù)進行欠采樣,以放棄部分大類數(shù)據(jù)來解決。
重新選擇評價指標(biāo)
準(zhǔn)確度在類別均衡的分類任務(wù)中并不能有效地評價分類器模型,造成模型失效,甚至?xí)`導(dǎo)業(yè)務(wù),造成較大損失。
最典型的評價指標(biāo)即混淆矩陣Confusion Matrix:使用一個表格對分類器所預(yù)測的類別與其真實的類別的樣本統(tǒng)計,分別為:TP、FN、FP、TN。包括精確度Precision、召回率Recall、F1得分F1-Score等。
重采樣數(shù)據(jù)集
使用采樣sampling策略該減輕數(shù)據(jù)的不平衡程度。主要有兩種方法
- 對小類的數(shù)據(jù)樣本進行采樣來增加小類的數(shù)據(jù)樣本個數(shù),即過采樣over-sampling
- 對大類的數(shù)據(jù)樣本進行采樣來減少該類數(shù)據(jù)樣本的個數(shù),即欠采樣under-sampling
采樣算法往往很容易實現(xiàn),并且其運行速度快,并且效果也不錯。在使用采樣策略時,可以考慮:
- 對大類下的樣本 (超過1萬, 十萬甚至更多) 進行欠采樣,即刪除部分樣本
- 對小類下的樣本 (不足1為甚至更少) 進行過采樣,即添加部分樣本的副本
- 嘗試隨機采樣與非隨機采樣兩種采樣方法
- 對各類別嘗試不同的采樣比例
- 同時使用過采樣與欠采樣
產(chǎn)生人工數(shù)據(jù)樣本
一種簡單的方法,對該類下的所有樣本的每個屬性特征的取值空間中隨機選取一個值以組成新的樣本,即屬性值隨機采樣。可以使用基于經(jīng)驗對屬性值進行隨機采樣而構(gòu)造新的人工樣本,或使用類似樸素貝葉斯方法假設(shè)各屬性之間互相獨立進行采樣,這樣便可得到更多的數(shù)據(jù),但是無法保證屬性之前的線性關(guān)系(如果本身是存在的)。
有一個系統(tǒng)的構(gòu)造人工數(shù)據(jù)樣本的方法SMOTE (Synthetic Minority Over-sampling Technique)。SMOTE是一種過采樣算法,它構(gòu)造新的小類樣本而不是產(chǎn)生小類中已有的樣本的副本,即該算法構(gòu)造的數(shù)據(jù)是新樣本,原數(shù)據(jù)集中不存在的。
該基于距離度量選擇小類別下兩個或者更多的相似樣本,然后選擇其中一個樣本,并隨機選擇一定數(shù)量的鄰居樣本對選擇的那個樣本的一個屬性增加噪聲,每次處理一個屬性。這樣就構(gòu)造了更多的新生數(shù)據(jù)。
嘗試不同的分類算法
對待每一個機器學(xué)習(xí)任務(wù)都使用自己喜歡而熟悉的算法,相信很多人都會感同身受。但對待不同任務(wù)需要根據(jù)任務(wù)本身特點選用不同等算法,尤其對樣本不均衡等分類任務(wù)。應(yīng)該使用不同的算法對其進行比較,因為不同的算法使用于不同的任務(wù)與數(shù)據(jù)。
決策樹往往在類別不均衡數(shù)據(jù)上表現(xiàn)不錯。它使用基于類變量的劃分規(guī)則去創(chuàng)建分類樹,因此可以強制地將不同類別的樣本分開。
對模型進行懲罰
你可以使用相同的分類算法,但是使用一個不同的角度,比如你的分類任務(wù)是識別那些小類,那么可以對分類器的小類樣本數(shù)據(jù)增加權(quán)值,降低大類樣本的權(quán)值,從而使得分類器將重點集中在小類樣本身上。
一個具體做法就是,在訓(xùn)練分類器時,若分類器將小類樣本分錯時額外增加分類器一個小類樣本分錯代價,這個額外的代價可以使得分類器更加"關(guān)心"小類樣本。如penalized-SVM和penalized-LDA算法。
嘗試一個新的角度理解問題
我們可以從不同于分類的角度去解決數(shù)據(jù)不均衡性問題,我們可以把那些小類的樣本作為異常點outliers,因此該問題便轉(zhuǎn)化為異常點檢測anomaly detection與變化趨勢檢測問題change detection。
異常點檢測即是對那些罕見事件進行識別。如通過機器的部件的振動識別機器故障,又如通過系統(tǒng)調(diào)用序列識別惡意程序。這些事件相對于正常情況是很少見的。
變化趨勢檢測類似于異常點檢測,不同在于其通過檢測不尋常的變化趨勢來識別。如通過觀察用戶模式或銀行交易來檢測用戶行為的不尋常改變。
將小類樣本作為異常點這種思維的轉(zhuǎn)變,可以幫助考慮新的方法去分離或分類樣本。這兩種方法從不同的角度去思考,讓你嘗試新的方法去解決問題。
嘗試創(chuàng)新
仔細(xì)對你的問題進行分析與挖掘,是否可以將你的問題劃分成多個更小的問題,而這些小問題更容易解決。
處理樣本不平衡方法
通過抽樣
過采樣
又稱上采樣(over-sampling)通過增加分類中少數(shù)類樣本的數(shù)量來實現(xiàn)樣本不均衡。比較流行的算法有
The Synthetic Minority OverSampling Technique (SMOTE) 算法。
SMOTE: 對于少數(shù)類樣本a, 隨機選擇一個最近鄰的樣本b, 然后從a與b的連線上隨機選取一個點c作為新的少數(shù)類樣本。
語法:
imblearn.over_sampling.SMOTE(
sampling_strategy='auto',
random_state=None,
k_neighbors=5,
n_jobs=1)
舉例:
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE
# doctest: +NORMALIZE_WHITESPACE
X, y = make_classification(
n_classes=2,
class_sep=2,
weights=[0.1, 0.9],
n_informative=3,
n_redundant=1, flip_y=0,
n_features=20,
n_clusters_per_class=1,
n_samples=1000,
random_state=10)
print('Original dataset shape %s'
% Counter(y))
Original dataset shape Counter
({1: 900, 0: 100})
smote = SMOTE(random_state=42)
X_res, y_res = smote.fit_resample(X, y)
print('Resampled dataset shape %s'
% Counter(y_res))
Resampled dataset shape Counter
({0: 900, 1: 900})
SMOTE 變體 borderlineSMOTE、SVMSMOTE
相對于基本的SMOTE算法, 關(guān)注的是所有的少數(shù)類樣本, 這些情況可能會導(dǎo)致產(chǎn)生次優(yōu)的決策函數(shù), 因此SMOTE就產(chǎn)生了一些變體: 這些方法關(guān)注在最優(yōu)化決策函數(shù)邊界的一些少數(shù)類樣本, 然后在最近鄰類的相反方向生成樣本。
這兩種類型的SMOTE使用的是危險樣本來生成新的樣本數(shù)據(jù)。
- borderlineSMOTE(kind='borderline-1')最近鄰中的隨機樣本b與該少數(shù)類樣本a來自于不同的類。
- borderlineSMOTE(kind='borderline-2')隨機樣本b可以是屬于任何一個類的樣本。
- SVMSMOTE()使用支持向量機分類器產(chǎn)生支持向量然后再生成新的少數(shù)類樣本。
少數(shù)類的樣本分為三類:
- 噪音樣本noise, 該少數(shù)類的所有最近鄰樣本都來自于不同于樣本a的其他類別。
- 危險樣本in danger, 至少一半的最近鄰樣本來自于同一類(不同于a的類別)。
- 安全樣本safe, 所有的最近鄰樣本都來自于同一個類。
語法:
imblearn.over_sampling.BorderlineSMOTE(sampling_strategy='auto',
random_state=None,
k_neighbors=5,
n_jobs=1, m_neighbors=10,
kind='borderline-1')
imblearn.over_sampling.SVMSMOTE(
sampling_strategy='auto',
random_state=None,
k_neighbors=5, n_jobs=1,
m_neighbors=10,
svm_estimator=None,
out_step=0.5)
Adaptive Synthetic (ADASYN)自適應(yīng)合成上采樣
ADASYN: 關(guān)注的是在那些基于K最近鄰分類器被錯誤分類的原始樣本附近生成新的少數(shù)類樣本。
語法:
imblearn.over_sampling.ADASYN(
sampling_strategy='auto',
random_state=None,
n_neighbors=5, n_jobs=1,
ratio=None)
舉例:
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.over_sampling import ADASYN
# doctest: +NORMALIZE_WHITESPACE
X, y = make_classification(
n_classes=2,
class_sep=2,
weights=[0.1, 0.9],
n_informative=3,
n_redundant=1,
flip_y=0,
n_features=20,
n_clusters_per_class=1,
n_samples=1000,
random_state=10)
print('Original dataset shape %s'
% Counter(y))
Original dataset shape Counter
({1: 900, 0: 100})
ada = ADASYN(random_state=42)
X_res, y_res = ada.fit_resample(X, y)
print('Resampled dataset shape %s'
% Counter(y_res))
Resampled dataset shape Counter
({0: 904, 1: 900})
RandomOverSampler隨機采樣增加新樣本
例:跟之前類似,此處及后面均簡化列出。
from imblearn.over_sampling import RandomOverSampler
ros = RandomOverSampler(andom_state=0)
X_resampled, y_resampled = ros.fit_resample(X, y)
隨機對欠表達(dá)樣本進行采樣,該算法允許對heterogeneous data(異構(gòu)數(shù)據(jù))進行采樣(例如含有一些字符串)。通過對原少數(shù)樣本的重復(fù)取樣進行上采樣。
欠采樣
又稱下采樣(under-sampling)通過減少分類中多數(shù)類樣本的數(shù)量來實現(xiàn)樣本不均衡。
RandomUnderSampler直接隨機選取刪除法
RandomUnderSampler函數(shù)是一種快速并十分簡單的方式來平衡各個類別的數(shù)據(jù)----隨機選取數(shù)據(jù)的子集。
語法:
from imblearn.under_sampling import RandomUnderSample
model_undersample = RandomUnderSample()
x_undersample_resampled, y_undersample_resampled = model_undersample.fit_sample(X,y)
- 注意1: 當(dāng)設(shè)置replacement=True時, 采用bootstrap。
- 注意2: 允許非結(jié)構(gòu)化數(shù)據(jù),例如數(shù)據(jù)中含字符串。
- 注意3: 默認(rèn)參數(shù)的時候, 采用的是不重復(fù)采樣。
NearMiss 基于NN啟發(fā)式算法
NearMiss函數(shù)則添加了一些啟發(fā)式heuristic的規(guī)則來選擇樣本, 通過設(shè)定version參數(shù)來實現(xiàn)三種啟發(fā)式的規(guī)則。
from imblearn.under_sampling import NearMiss
nm1 = NearMiss(version=1)
X_resampled_num1, y_resampled = nm1.fit_resample(X, y)
- version=1:選取正例樣本中與N個最近鄰負(fù)樣本平均距離最小的樣本。
- version=2:選取正例樣本中與N個最遠(yuǎn)鄰負(fù)樣本平均距離最小的樣本。
- version=3:2-steps 算法----首先對于每個負(fù)類樣本, 保留它們的M近鄰正樣本。然后那些到N個近鄰樣本平均距離最大的正樣本將被選擇。