日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度學習實戰(不定時更新)
分類中解決類別不平衡問題
前面我們已經初步認識了,什麼是類別不平衡問題。其實,在現實環境中,採集的數據(建模樣本)往往是比例失衡的。比如網貸數據,逾期人數的比例是極低的(千分之幾的比例);奢侈品消費人羣鑑定等。
1 類別不平衡數據集基本介紹
在這一節中,我們一起看一下,當遇到數據類別不平衡的時候,我們該如何處理。在Python中,有Imblearn包,它就是爲處理數據比例失衡而生的。
- 安裝Imblearn包
pip3 install imbalanced-learn
第三方包鏈接:https://pypi.org/project/imbalanced-learn/
- 創造數據集
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
#使用make_classification生成樣本數據
X, y = make_classification(n_samples=5000,
n_features=2, # 特徵個數= n_informative() + n_redundant + n_repeated
n_informative=2, # 多信息特徵的個數
n_redundant=0, # 冗餘信息,informative特徵的隨機線性組合
n_repeated=0, # 重複信息,隨機提取n_informative和n_redundant 特徵
n_classes=3, # 分類類別
n_clusters_per_class=1, # 某一個類別是由幾個cluster構成的
weights=[0.01, 0.05, 0.94], # 列表類型,權重比
random_state=0)
- 查看各個標籤的樣本
#查看各個標籤的樣本量
from collections import Counter
Counter(y)
# Counter({2: 4674, 1: 262, 0: 64})
- 數據集可視化
# 數據集可視化
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()
可以看出樣本的三個標籤中,1,2的樣本量極少,樣本失衡。下面使用imblearn進行過採樣。
接下來,我們就要基於以上數據,進行相應的處理。
關於類別不平衡的問題,主要有兩種處理方式:
- 過採樣方法
- 增加數量較少那一類樣本的數量,使得正負樣本比例均衡。
- 欠採樣方法
- 減少數量較多那一類樣本的數量,使得正負樣本比例均衡。
2 解決類別不平衡數據方法介紹
2.1 過採樣方法
2.1.1 什麼是過採樣方法
對訓練集裏的少數類進行“過採樣”(oversampling),即增加一些少數類樣本使得正、反例數目接近,然後再進行學習。
- 通過代碼實現隨機過採樣方法:
# 使用imblearn進行隨機過採樣
from imblearn.over_sampling import RandomOverSampler
ros = RandomOverSampler(random_state=0)
X_resampled, y_resampled = ros.fit_resample(X, y)
#查看結果
Counter(y_resampled)
#過採樣後樣本結果
# Counter({2: 4674, 1: 4674, 0: 4674})
# 數據集可視化
plt.scatter(X_resampled[:, 0], X_resampled[:, 1], c=y_resampled)
plt.show()
- 缺點:
- 對於隨機過採樣,由於需要對少數類樣本進行復制來擴大數據集,造成模型訓練複雜度加大。
- 另一方面也容易造成模型的過擬合問題,因爲隨機過採樣是簡單的對初始樣本進行復制採樣,這就使得學習器學得的規則過於具體化,不利於學習器的泛化性能,造成過擬合問題。
爲了解決隨機過採樣中造成模型過擬合問題,又能保證實現數據集均衡的目的,出現了過採樣法代表性的算法SMOTE算法。
2.1.3 過採樣代表性算法-SMOTE
SMOTE全稱是Synthetic Minority Oversampling即合成少數類過採樣技術。
SMOTE算法摒棄了隨機過採樣複製樣本的做法,可以防止隨機過採樣中容易過擬合的問題,實踐證明此方法可以提高分類器的性能。
- 代碼實現:
# SMOTE過採樣
from imblearn.over_sampling import SMOTE
X_resampled, y_resampled = SMOTE().fit_resample(X, y)
Counter(y_resampled)
# 採樣後樣本結果
# [(0, 4674), (1, 4674), (2, 4674)]
# 數據集可視化
plt.scatter(X_resampled[:, 0], X_resampled[:, 1], c=y_resampled)
plt.show()
2.2 欠採樣方法
2.2.1 什麼是欠採樣方法
直接對訓練集中多數類樣本進行“欠採樣”(undersampling),即去除一些多數類中的樣本使得正例、反例數目接近,然後再進行學習。
2.2.2 隨機欠採樣方法
- 代碼實現:
# 隨機欠採樣
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=0)
X_resampled, y_resampled = rus.fit_resample(X, y)
Counter(y_resampled)
# 採樣後結果
[(0, 64), (1, 64), (2, 64)]
# 數據集可視化
plt.scatter(X_resampled[:, 0], X_resampled[:, 1], c=y_resampled)
plt.show()
缺點:
- 隨機欠採樣方法通過改變多數類樣本比例以達到修改樣本分佈的目的,從而使樣本分佈較爲均衡,但是這也存在一些問題。對於隨機欠採樣,由於採樣的樣本集合要少於原來的樣本集合,因此會造成一些信息缺失,即將多數類樣本刪除有可能會導致分類器丟失有關多數類的重要信息。
In [1]:
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
from collections import Counter
準備類別不平衡數據
In [2]:
X,y = make_classification(n_samples=5000, n_features=2,
n_informative=2, n_redundant=0,
n_repeated=0, n_classes=3,
n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94], random_state=0)
In [3]:
X
Out[3]:
array([[ 8.62420206e-01, -9.63476905e-01],
[-1.38080465e-03, -2.66979396e+00],
[ 1.40804486e+00, -5.32895046e-01],
...,
[ 1.09447133e+00, -6.99569620e-01],
[ 1.60312887e+00, -8.26180435e-01],
[ 1.99589648e+00, 5.42836944e-01]])
In [4]:
X.shape
Out[4]:
(5000, 2)
In [5]:
y, y.shape
Out[5]:
(array([2, 2, 2, ..., 2, 2, 2]), (5000,))
In [6]:
Counter(y)
Out[6]:
Counter({2: 4674, 1: 262, 0: 64})
In [7]:
# 數據可視化
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()
過採樣
隨機過採樣
In [13]:
from imblearn.over_sampling import RandomOverSampler
ros = RandomOverSampler(random_state=0)
X_resampled, y_resampled = ros.fit_resample(X, y)
In [14]:
Counter(y_resampled)
Out[14]:
Counter({2: 4674, 1: 4674, 0: 4674})
In [17]:
# 數據可視化
plt.scatter(X_resampled[:, 0], X_resampled[:, 1], c=y_resampled)
plt.show()
SMOTE過採樣
In [18]:
from imblearn.over_sampling import SMOTE
X_resampled, y_resampled = SMOTE().fit_resample(X, y)
In [19]:
Counter(y_resampled)
Out[19]:
Counter({2: 4674, 1: 4674, 0: 4674})
In [20]:
# 數據可視化
plt.scatter(X_resampled[:, 0], X_resampled[:, 1], c=y_resampled)
plt.show()
欠採樣方法
In [22]:
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=0)
X_resampled, y_resampled = rus.fit_resample(X, y)
In [23]:
Counter(y_resampled)
Out[23]:
Counter({0: 64, 1: 64, 2: 64})
In [24]:
# 數據可視化
plt.scatter(X_resampled[:, 0], X_resampled[:, 1], c=y_resampled)
plt.show()