最近在進行一個產品推薦課題時,由於產品的特性導致正負樣本嚴重失衡,遠遠大於3:1的比例(個人認為3:1是建模時正負樣本的一個臨界點),這樣的樣本不適合直接用來建模,例如正負樣本的比例達到了50:1,就算算法全部預測為另一樣本,准確率也會達到51/50=98%.具有很大的局限性.
處理不平衡樣本的方法
解決方法主要分為兩個方面。
- 第一種方案主要從數據的角度出發,主要方法為抽樣,既然我們的樣本是不平衡的,那么可以通過某種策略進行抽樣,從而讓我們的數據相對均衡一些;
- 第二種方案從算法的角度出發, 考慮不同誤分類情況代價的差異性對算法進行優化,使得我們的算法在不平衡數據下也能有較好的效果。
這里我們主要從數據的角度進行討論--采樣技術
1.隨機采樣
隨機采樣技術是最直接,最簡單易理解的處理方式,顧名思義,就是從已有樣本中進行抽樣,隨機采樣主要分為兩種:(1)隨機欠采樣,(2)隨機過采樣.
隨機欠采樣就是從樣本數量的多的類別S1中選擇隨機少量樣本在和原有的少量樣本合成作為新的數量級,使得兩個樣本的比例大致相同;
類似的,過采樣就是從樣本少的類別中多次采樣少數類,采樣的數量要大於原來的少數類的數量.隨機過采樣又分為有放回過采樣和無放回過采樣,這個和概率學上抽樣是一個含義.
很明顯,隨機采樣通過隨機選取一些樣本來改變樣本分類分布的比例,這種方法比較簡單,但是也存在諸多問題.
(1).欠采樣技術:隨機選取一部分數據,會導致數據的信息缺失,無法保證未被采樣的數據不具有重要特征
(2).過采樣技術:隨機的擴大的了數據集,但是可能(極大的可能)會導致過擬合現象.
<<Python實現>>
Python有一個強大的處理不平衡數據的包--imblearn,該包依賴sklearn(>=0.19),numpy,six等相關包,可以通過pip install 進行安裝.
實現隨機欠采樣:imblearn.under_sampling.RandomUnderSampler(ratio='auto', return_indices=False, random_state=None, replacement=False)
隨機過采樣:imlearn.over_sampling.RandomOverSampler(ratio='auto',random_state=None)
例子:
from collections import Counter from sklearn.datasets import make_classification ###生成不平衡樣本,比例9:1 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 {}".format(Counter(y))) >>original dataset shape Counter({1: 900, 0: 100}) ###隨機欠采樣 from imblearn.under_sampling import RandomUnderSampler rus=RandomUnderSampler(random_state=42) X_res,y_res=rus.fit_sample(X,y) print('Under Resampled dataset shape {}'.format(Counter(y_res))) >>Under Resampled dataset shape Counter({0: 100, 1: 100}) ##隨機過采樣 from imblearn.over_sampling import RandomOverSampler ros=RandomOverSampler(random_state=42) X_res,y_res=ros.fit_sample(X,y) print('Over Resampled dataset shape {}'.format(Counter(y_res))) >>Over Resampled dataset shape Counter({0: 900, 1: 900})
2.SMOTE算法
SMOTE算法又稱為合成少數類過采樣方法,SMOTE算法的基本思想是對少數類樣本進行分 析並根據少數類樣本人工合成新樣本添加到數據集中,從而改進了隨機過采樣技術造成的過擬合問題.
算法流程:
- 對於少數類中每一個樣本x,以歐氏距離為標准計算它到少數類樣本集Sm中所有樣本的距離,得到其k近鄰。
- 根據樣本不平衡比例設置一個采樣比例以確定采樣倍率N,對於每一個少數類樣本x,從其k近鄰中隨機選擇若干個樣本,假設選擇的近鄰為x^。
- 對於每一個隨機選出的近鄰x^,分別與原樣本按照如下的公式構建新的樣本。

<<Python_實現>>
同樣我們可以利用Python的第三方包imbalanced_learn實現SMOTE算法;如其官網給出的例子所"""
@author:Dylan; @desc:imbalanced_learn 2018/5/21 """ #-*- encoding:utf-8 -*- import matplotlib.pyplot as plt from sklearn.datasets import make_classification from sklearn.decomposition import PCA from imblearn.over_sampling import SMOTE print(__doc__) def plot_resampling(ax,X,y,title): c0=ax.scatter(X[y==0,0],X[y==0,1],label="Class #0",alpha=0.5) c1=ax.scatter(X[y==1,0],X[y==1,1],label="Class #1",alpha=0.5) ax.set_title(title) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.get_xaxis().tick_bottom() ax.get_yaxis().tick_left() ax.spines['left'].set_position(('outward',10)) ax.spines['bottom'].set_position(('outward',10)) ax.set_xlim([-6,8]) ax.set_ylim([-6,6]) return c0,c1 if __name__=='__main__': X,y=make_classification(n_classes=2,class_sep=2,weights=[0.3,0.7], n_informative=3,n_redundant=1,flip_y=0, n_features=20,n_clusters_per_class=1,n_samples=80,random_state=10) ##使用PCA降維到兩維,方便進行可視化 pca=PCA(n_components=2) X_vis=pca.fit_transform(X) ###運用SMOTE算法 kind=['regular','borderline1','borderline2','svm'] sm=[SMOTE(kind=k) for k in kind] X_resampled=[] y_resampled=[] X_res_vis=[] for method in sm: X_res,y_res=method.fit_sample(X,y) X_resampled.append(X_res) y_resampled.append(y_res) X_res_vis.append(pca.fit_transform(X_res)) f,((ax1,ax2),(ax3,ax4),(ax5,ax6))=plt.subplots(3,2) ##展示結果 ax2.axis('off') ax_res=[ax3,ax4,ax5,ax6] c0,c1=plot_resampling(ax1,X_vis,y,'original_set') for i in range(len(kind)): plot_resampling(ax_res[i],X_res_vis[i],y_resampled[i],'smote{}'.format(kind[i])) ax2.legend((c0,c1),('Class #0','Class #1'),loc='center',ncol=1,labelspacing=0.) plt.tight_layout() plt.show()
這段代碼中,使用了sklearn簡單是生成了一個不平衡的樣本,使用了imblearn.over_sampling的SMOTE算法進行了過采樣處理.生成結果如下圖所示:

上圖中.圖1是原始數據的分布,圖3-6分別是采樣 'regular','borderline1','borderline2','svm'這四種類型處理方法的結果.個人傾向於使用svm.
使用SMOTE算法可以解決隨機復制樣本帶來的問題,但是也可能會存在重疊的問題,因此基於smote算法提出了Borderline算法.
2.Borderline-SMOTE算法
該算法對SMOTE算法中的少數類的最近鄰加以限制,在Borderline-SMOTE中,若少數類樣本的每個樣本xi求k近鄰,記作Si−knn,且Si−knn屬於整個樣本集合
S而不再是少數類樣本,若滿足 k/2<|si−knn∩smax|<k.即k近鄰中超過一般是多數樣本.那么就將xi加入到DANGER集合.顯然該集合代表了接近分類邊界的樣本.
將DANGER當作SMOTE種子樣本的輸入生成新樣本.特別地,當上述條件取右邊界,即k近鄰中全部樣本都是多數類時此樣本不會被選擇為種樣本生成新樣本,
此情況下的樣本為噪音。


當然還有一些其他的算法,例如ensemble,Informed InderSampling等,可以才有.Imblearn都對這些算法進行了實現.
參考自: https://blog.csdn.net/shine19930820/article/details/54143241;
http://contrib.scikit-learn.org/imbalanced-learn/stable/api.html
