【火爐煉AI】機器學習015-如何處理樣本數偏差較大的資料集
(本文所使用的Python庫和版本號: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )
我們得到的資料集在絕大多數情況下,都不是理想的資料集,都需要經過各種各樣的處理,其中的一個處理方式就是,如何處理樣本數偏差較大的資料集。比如對於某種疾病的發生概率是1%,即獲得的自然狀態下的資料集中大約99%的樣本都是正常的,那麼此時,通過模型進行訓練,得到的模型在對新樣本進行預測時,也往往偏向於樣本數較大的類別,此時或極大的降低小樣本類別的召回率。
1. 檢視資料集的特徵
此處所使用的是書本《Python機器學習經典例項》第三章的非平衡資料集,此處我用pandas讀取到記憶體中,通過info()來檢視該資料集的基本情況,程式碼如下:
# 準備資料集
data_path=`E:PyProjectsDataSetFireAI/data_multivar_imbalance.txt`
df=pd.read_csv(data_path,header=None)
# print(df.head()) # 沒有問題
print(df.info()) # 檢視資料資訊,確保沒有錯誤
dataset_X,dataset_y=df.iloc[:,:-1],df.iloc[:,-1]
# print(dataset_X.head())
# print(dataset_X.info())
# print(dataset_y.head()) # 檢查沒問題
dataset_X=dataset_X.values
dataset_y=dataset_y.values
複製程式碼
———————————-輸———出————————
<class `pandas.core.frame.DataFrame`>
RangeIndex: 1200 entries, 0 to 1199
Data columns (total 3 columns):
0 1200 non-null float64
1 1200 non-null float64
2 1200 non-null int64
dtypes: float64(2), int64(1)
memory usage: 28.2 KB
None
—————————————–完—————————–
可以看出,該資料集只有兩個features,一個label,且整個資料集有1200個樣本。可以通過檢視資料集的2D分佈來初步的瞭解該資料集的樣本偏差。如下圖所示:
########################小**********結########################
1. 資料集中不同類別之間樣本數偏差比較大,此時需要做進一步處理。
2. 資料集的載入和顯示等,在前面的文章中已經講爛了,此處無需贅言。
###########################################################
2. 用線性SVM分類器構建分類模型
從上面的資料集分佈圖中可以大致看出,這個模型不是簡單的線性模型,當然,為了對比效果,此處我仍然使用線性SVM分類器來構建分類模型,看一下效果。
程式碼如下:
# 將整個資料集劃分為train set和test set
from sklearn.model_selection import train_test_split
train_X, test_X, train_y, test_y=train_test_split(
dataset_X,dataset_y,test_size=0.25,random_state=42)
# 如果用線性SVM分類器來進行分類,看看是什麼結果
# 使用線性核函式初始化一個SVM物件。
from sklearn.svm import SVC
classifier=SVC(kernel=`linear`) # 構建線性分類器
classifier.fit(train_X,train_y)
複製程式碼
然後在通過plot_classifier()函式將這個模型的分類效果畫出來。
# 模型在訓練集上的效能報告:
from sklearn.metrics import classification_report
plot_classifier(classifier,train_X,train_y) # 分類器在訓練集上的分類效果
target_names = [`Class-0`, `Class-1`]
y_pred=classifier.predict(train_X)
print(classification_report(train_y, y_pred, target_names=target_names))
複製程式碼
—————————-輸———出———————–
precision | recall | f1-score | support |
---|---|---|---|
Class-0 | 0.00 | 0.00 | 0.00 |
Class-1 | 0.83 | 1.00 | 0.91 |
avg / total | 0.69 | 0.83 | 0.76 |
———————————–完—————————–
可以看出,線性SVM分類器完全沒有將class_0區分出來,得到的各種指標都是0,從分類效果圖中也可以看到,根本就沒有線性平面。
##################小**********結###############################
1. 由於本資料集存在樣本數量偏差,故而使用線性SVM分類器沒有任何效果。
############################################################
3. 解決樣本數量偏差的方法
從上面可以看出,由於樣本數量偏差的存在,使用線性SVM分類器沒有任何效果,那麼我們該怎麼處理這種資料集了?
SVM內部存在一個class_weight引數,我們可以設定該引數為”balanced”,來調節各種類別樣本數量的權重,使其達到平衡。如下程式碼:
# 看來直接使用簡單的線性SVM分類器難以將class_0區分出來,故而我們要調整資料集中樣本的數量權重
classifier2=SVC(kernel=`linear`,class_weight=`balanced`) # 比上面的分類器增加了 class_weight=‘balanced`引數
classifier2.fit(train_X,train_y)
# 模型在訓練集上的效能報告:
plot_classifier(classifier2,train_X,train_y) # 分類器在訓練集上的分類效果
target_names = [`Class-0`, `Class-1`]
y_pred2=classifier2.predict(train_X)
print(classification_report(train_y, y_pred2, target_names=target_names))
複製程式碼
——————————-輸———出—————————
precision | recall | f1-score | support |
---|---|---|---|
Class-0 | 0.35 | 0.86 | 0.50 |
Class-1 | 0.96 | 0.68 | 0.79 |
avg / total | 0.86 | 0.71 | 0.74 |
————————————-完——————————–
從分類效果圖中可以看出,此時可以使用線性SVM來對資料集進行訓練,並能得到效果還不錯的分類模型,從分類結果報告中可以看出,各種指標也還不錯,但也存在較大的提升空間。
#################小**********結###############################
1. 在定義SVM分類器時,只需要設定class_weight=balanced即可消除資料集中樣本數量偏差的問題。
2. 如果分類器的效果不理想,那麼需要考慮是否是資料集存在明顯的樣本數量偏差問題。
#########################################################
注:本部分程式碼已經全部上傳到(我的github)上,歡迎下載。
參考資料:
1, Python機器學習經典例項,Prateek Joshi著,陶俊傑,陳小莉譯