【python實戰】使用第三方庫imblearn實現不平衡樣本的樣本均衡問題

摘自數據常青藤

樣本分佈不均衡將導致樣本量少的分類所包含的特徵過少,並很難從中提取規律;即使得到分類模型,也容易產生過度依賴於有限的數據樣本而導致過擬合的問題,當模型應用到新的數據上時,模型的準確性和魯棒性將很差。

樣本分佈不平衡主要在於不同類別間的樣本比例差異,以筆者的工作經驗看,如果不同分類間的樣本量差異達到超過10倍就需要引起警覺並考慮處理該問題,超過20倍就要一定要解決該問題。


哪些運營場景中容易出現樣本不均衡

在數據化運營過程中,以下場景會經常產生樣本分佈不均衡的問題:

  • 異常檢測場景。大多數企業中的異常個案都是少量的,比如惡意刷單、黃牛訂單、信用卡欺詐、電力竊電、設備故障等,這些數據樣本所佔的比例通常是整體樣本中很少的一部分,以信用卡欺詐爲例,刷實體信用卡的欺詐比例一般都在0.1%以內。
    客戶流失場景。大型企業的流失客戶相對於整體客戶通常是少量的,尤其對於具有壟斷地位的行業巨擘,例如電信、石油、網絡運營商等更是如此。
  • 罕見事件的分析。罕見事件與異常檢測類似,都屬於發生個案較少;但不同點在於異常檢測通常都有是預先定義好的規則和邏輯,並且大多數異常事件都對會企業運營造成負面影響,因此針對異常事件的檢測和預防非常重要;但罕見事件則無法預判,並且也沒有明顯的積極和消極影響傾向。例如由於某網絡大V無意中轉發了企業的一條趣味廣告導致用戶流量明顯提升便屬於此類。
  • 發生頻率低的事件。這種事件是預期或計劃性事件,但是發生頻率非常低。例如每年1次的雙11盛會一般都會產生較高的銷售額,但放到全年來看這一天的銷售額佔比很可能只有1%不到,尤其對於很少參與活動的公司而言,這種情況更加明顯。這種屬於典型的低頻事件。

解決思路

提示 :以下幾種方法的思路都是基於分類問題解決的。實際上,對於從大規模數據中尋找罕見數據的應用場景,亦可使用非監督式的學習方法,例如使用One-class SVM進行異常檢測。分類是監督式方法,前期是基於帶有標籤(Label)的數據進行分類預測;而採用非監督式方法,則是使用除了標籤以外的其他特徵進行模型擬合,這樣也能得到異常數據記錄。所以,要解決異常檢測類的問題,先是考慮整體思路,然後再考慮方法模型。

1.通過過抽樣和欠抽樣解決樣本不均衡

抽樣是解決樣本分佈不均衡相對簡單且常用的方法,包括過抽樣和欠抽樣兩種。

過抽樣

過抽樣(也叫上採樣、over-sampling)方法通過增加分類中少數類樣本的數量來實現樣本均衡,最直接的方法是簡單複製少數類樣本形成多條記錄,這種方法的缺點是如果樣本特徵少而可能導致過擬合的問題;經過改進的過抽樣方法通過在少數類中加入隨機噪聲、干擾數據或通過一定規則產生新的合成樣本,例如SMOTE算法。

欠抽樣

欠抽樣(也叫下采樣、under-sampling)方法通過減少分類中多數類樣本的樣本數量來實現樣本均衡,最直接的方法是隨機地去掉一些多數類樣本來減小多數類的規模,缺點是會丟失多數類樣本中的一些重要信息。

總體上,過抽樣和欠抽樣更適合大數據分佈不均衡的情況,尤其是第一種(過抽樣)方法應用更加廣泛。

2.通過組合/集成方法解決樣本不均衡

組合/集成方法指的是在每次生成訓練集時使用所有分類中的小樣本量,同時從分類中的大樣本量中隨機抽取數據來與小樣本量合併構成訓練集,這樣反覆多次會得到很多訓練集和訓練模型。最後在應用時,使用組合方法(例如投票、加權投票等)產生分類預測結果。

例如,在數據集中的正、負例的樣本分別爲100和10000條,比例爲1:100。此時可以將負例樣本(類別中的大量樣本集)隨機分爲100份(當然也可以分更多),每份100條數據;然後每次形成訓練集時使用所有的正樣本(100條)和隨機抽取的負樣本(100條)形成新的數據集。如此反覆可以得到100個訓練集和對應的訓練模型。

這種解決問題的思路類似於隨機森林。在隨機森林中,雖然每個小決策樹的分類能力很弱,但是通過大量的“小樹”組合形成的“森林”具有良好的模型預測能力。

如果計算資源充足,並且對於模型的時效性要求不高的話,這種方法比較合適。

3.通過特徵選擇解決樣本不均衡

上述幾種方法都是基於數據行的操作,通過多種途徑來使得不同類別的樣本數據行記錄均衡。除此以外,還可以考慮使用或輔助於基於列的特徵選擇方法。

一般情況下,樣本不均衡也會導致特徵分佈不均衡,但如果小類別樣本量具有一定的規模,那麼意味着其特徵值的分佈較爲均勻,可通過選擇具有顯著型的特徵配合參與解決樣本不均衡問題,也能在一定程度上提高模型效果。


代碼實戰:Python處理樣本不均衡

示例中,我們主要使用一個新的專門用於不平衡數據處理的Python包imbalanced-learn,讀者需要先在系統終端的命令行使用pip install imbalanced-learn進行安裝;安裝成功後,在Python或IPython命令行窗口通過使用import imblearn(注意導入的庫名)檢查安裝是否正確,示例代碼包版本爲0.2.1。除此以外,我們還會使用sklearn的SVM在算法中通過調整類別權重來處理樣本不均衡問題。本示例使用的數據源文件data2.txt位於“附件-chapter3”中,默認工作目錄爲“附件-chapter3”(如果不是,請cd切換到該目錄下,否則會報“IOError: File data2.txt does not exist”)。完整代碼如下:

import pandas as pd
from imblearn.over_sampling import SMOTE # 過抽樣處理庫SMOTE
from imblearn.under_sampling import RandomUnderSampler # 欠抽樣處理庫RandomUnderSampler
from sklearn.svm import SVC #SVM中的分類算法SVC
from imblearn.ensemble import EasyEnsemble # 簡單集成方法EasyEnsemble

# 導入數據文件
df = pd.read_table('data2.txt', sep=' ', names=['col1', 'col2','col3', 'col4', 'col5', 'label']) # 讀取數據文件
x = df.iloc[:, :-1] # 切片,得到輸入x
y = df.iloc[:, -1] # 切片,得到標籤y
groupby_data_orgianl = df.groupby('label').count() # 對label做分類彙總
print (groupby_data_orgianl) # 打印輸出原始數據集樣本分類分佈

# 使用SMOTE方法進行過抽樣處理
model_smote = SMOTE() # 建立SMOTE模型對象
x_smote_resampled, y_smote_resampled = model_smote.fit_sample(x,y) # 輸入數據並作過抽樣處理
x_smote_resampled = pd.DataFrame(x_smote_resampled, columns=['col1','col2', 'col3', 'col4', 'col5']) # 將數據轉換爲數據框並命名列名
y_smote_resampled = pd.DataFrame(y_smote_resampled,columns=['label']) # 將數據轉換爲數據框並命名列名
smote_resampled = pd.concat([x_smote_resampled, y_smote_resampled],axis=1) # 按列合併數據框
groupby_data_smote = smote_resampled.groupby('label').count() # 對label做分類彙總
print (groupby_data_smote) # 打印輸出經過SMOTE處理後的數據集樣本分類分佈

# 使用RandomUnderSampler方法進行欠抽樣處理
model_RandomUnderSampler = RandomUnderSampler() # 建立RandomUnderSampler模型對象
x_RandomUnderSampler_resampled, y_RandomUnderSampler_resampled =model_RandomUnderSampler.fit_sample(x,y) # 輸入數據並作欠抽樣處理
x_RandomUnderSampler_resampled =pd.DataFrame(x_RandomUnderSampler_resampled,columns=['col1','col2','col3','col4','col5'])
# 將數據轉換爲數據框並命名列名
y_RandomUnderSampler_resampled =pd.DataFrame(y_RandomUnderSampler_resampled,columns=['label']) # 將數據轉換爲數據框並命名列名
RandomUnderSampler_resampled =pd.concat([x_RandomUnderSampler_resampled, y_RandomUnderSampler_resampled], axis= 1) # 按列合併數據框
groupby_data_RandomUnderSampler =RandomUnderSampler_resampled.groupby('label').count() # 對label做分類彙總
print (groupby_data_RandomUnderSampler) # 打印輸出經過RandomUnderSampler處理後的數據集樣本分類分佈

# 使用SVM的權重調節處理不均衡樣本
model_svm = SVC(class_weight='balanced') # 創建SVC模型對象並指定類別權重
model_svm.fit(x, y) # 輸入x和y並訓練模型

# 使用集成方法EasyEnsemble處理不均衡樣本
model_EasyEnsemble = EasyEnsemble() # 建立EasyEnsemble模型對象
x_EasyEnsemble_resampled, y_EasyEnsemble_resampled =
model_EasyEnsemble.fit_sample(x, y) # 輸入數據並應用集成方法處理
print (x_EasyEnsemble_resampled.shape) # 打印輸出集成方法處理後的x樣本集概況
print (y_EasyEnsemble_resampled.shape) # 打印輸出集成方法處理後的y標籤集概況

# 抽取其中一份數據做審查
index_num = 1 # 設置抽樣樣本集索引
x_EasyEnsemble_resampled_t =pd.DataFrame(x_EasyEnsemble_resampled[index_num],columns=['col1','col2','col3','col4','col5'])
# 將數據轉換爲數據框並命名列名
y_EasyEnsemble_resampled_t =pd.DataFrame(y_EasyEnsemble_resampled[index_num],columns=['label']) # 將數據轉換爲數據框並命名列名
EasyEnsemble_resampled = pd.concat([x_EasyEnsemble_resampled_t,
y_EasyEnsemble_resampled_t], axis = 1) # 按列合併數據框
groupby_data_EasyEnsemble =EasyEnsemble_resampled.groupby('label').count() # 對label做分類彙總
print (groupby_data_EasyEnsemble) # 打印輸出經過EasyEnsemble處理後的數據集樣本分類分佈

示例代碼以空行分爲6部分。

第一部分導入庫。本示例中用到了第三方庫imbalanced-learn實現主要的樣本不均衡處理,而pandas的引入主要用於解釋和說明不同處理方法得到的結果集樣本的分佈情況,sklearn.svm中的SVC主要用於說明SVM如何在算法中自動調整分類權重。

第二部分導入數據文件。該過程中使用pandas的read_table讀取本地文件,爲了更好的區別不同的列,通過names指定列名;對數據框做切片分割得到輸入的x和目標變量y;通過pandas的groupby()方法按照label類做分類彙總,彙總方式是使用count()函數計數。輸入原始數據集樣本分類分佈如下:

第三部分使用SMOTE方法進行過抽樣處理。該過程中首先建立SMOTE模型對象,並直接應用fit_sample對數據進行過抽樣處理,如果要獲得有關smote的具體參數信息,可先使用fit(x,y)方法獲得模型信息,並得到模型不同參數和屬性;從fit_sample方法分別得到對x和y過抽樣處理後的數據集,將兩份數據集轉換爲數據框然後合併爲一個整體數據框;最後通過pandas提供的groupby()方法按照label類做分類彙總,彙總方式是使用count()函數計數。

第四部分使用RandomUnderSampler方法進行欠抽樣處理。該過程與第三部分步驟完全相同,在此略過各模塊介紹,用途都已在代碼備註中註明。

第五部分使用SVM的權重調節處理不均衡樣本。該過程主要通過配置SVC中的class_weight參數和值的設置來處理樣本權重,該參數可設置爲字典、None或字符串balanced三種模式:

  • 字典:通過手動指定的不同類別的權重,例如{1:10,0:1}
  • None:代表類別的權重相同
  • balanced:代表算法將自動調整與輸入數據中的類頻率成反比的權重,具體公式爲n_samples /(n_classes * np.bincount(y)),程序示例中使用了該方法

經過設置後,算法自動處理樣本分類權重,無需用戶做其他處理。要對新的數據集做預測,只需要調用model_svm模型對象的predict方法即可。

第六部分使用集成方法EasyEnsemble處理不均衡樣本。該方法的主要過程與其他imblearn方法過程類似,不同點在於集成方法返回的數據爲三維數據,即將數據在原來的基礎上新增了一個維度——“份數”,集成方法返回的數據x和y的形狀爲(10, 116, 5)和(10, 116)。

上述過程中,主要需要考慮的關鍵點是:

如何針對不同的具體場景選擇最合適的樣本均衡解決方案,選擇過程中既要考慮到每個類別樣本的分佈情況以及總樣本情況,又要考慮後續數據建模算法的適應性,以及整個數據模型計算的數據時效性。
代碼實操小結:本小節示例中,主要用了幾個知識點:


  • 通過pandas的read_table方法讀取文本數據文件,並指定列名
  • 對數據框做切片處理
  • 通過pandas提供的groupby()方法配合count()做分類彙總
  • 使用imblearn.over_sampling中的SMOTE做過抽樣處理
  • 使用imblearn.under_sampling中的RandomUnderSampler做欠抽樣處理
  • 使用imblearn.ensemble中的EasyEnsemble做集成處理
  • 使用sklearn.svm 中的SVC自動調整算法對不同類別的權重設置

提示 第三方庫imblearn提供了非常多的樣本不均衡處理方法,限於篇幅無法做一一介紹,建議讀者自行安裝並學習和了解不同的用法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章