数据不平衡是机器学习中经常遇到的问题,其根本的解决方法就是收集或制造一些数据扩大数据集,从而提升模型效果。在样本不平衡问题中,经常要用 F-measure 来替代准确率进行评估,使得评估标准比较有公信力。如果数据集无法扩充,我们还可以考虑使用一些方法(可以参考 Learning from Imbalanced Data)来尝试减小样本不平衡对模型训练带来的影响。下面我们就结合 imbalanced-learn 这个工具来了解一下相关的方法。
Sampling
Over Sampling
Random Over Sampling
随机过采样即随机从少数类样本中抽取数据,使样本达到平衡,具体实现如下:
from imblearn.over_sampling import RandomOverSampler
# the seed used by the random number generator
ros = RandomOverSampler(random_state=42)
X_res, y_res = ros.fit_sample(X, y)
此方法简单易懂,但由于它是简单地复制样本来使样本达到平衡,所以容易产生过拟合现象。
SMOTE
SMOTE 算法(Synthetic Minority Oversampling Technique)是利用少数类样本在特征空间内的相似性来合成新样本。它利用 k 近邻算法来分析已有的少数类样本,从而合成在特征空间内的新少数类样本。具体实现如下:
from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=42)
X_res, y_res = sm.fit_sample(X, y)
SMOTE 算法的改进算法包括 Borderline-SMOTE、Safe-Level-SMOTE 等。
ADASYN
ADASYN 算法(Adaptive Synthetic)与 SMOTE 算法类似,其主要思路是根据数据集的总体样本分布情况来为不同的少数类样本生成不同数目的新样本。相对于 SMOTE 算法,其对每一个少数类样本的重视程度不同。具体实现如下:
from imblearn.over_sampling import ADASYN
ada = ADASYN(random_state=42)
X_res, y_res = ada.fit_sample(X, y)
Under Sampling
Prototype Generation
原型生成算法是根据多数类的特征生成多数类的子集,此子集并非直接来源于多数类原数据集,从而使样本达到平衡,具体实现如下:
from imblearn.under_sampling import ClusterCentroids
cc = ClusterCentroids(random_state=42)
X_res, y_res = cc.fit_sample(X, y)
Prototype Selection
此方法根据原型选择算法从多数类选择数据,从而使样本平衡。此类算法有 Controlled under-sampling techniques 和 Cleaning under-sampling techniques 两种。前者用户可以干预采样,代表算法有 NearMiss 和 RandomUnderSampler;后者则不可以,代表算法有 AllKNN 和 EditedNearestNeighbours 等等。具体实现如下:
from imblearn.under_sampling import NearMiss, RandomUnderSampler, AllKNN, EditedNearestNeighbours
nm = NearMiss(random_state=42)
X_res, y_res = nm.fit_sample(X, y)
rus = RandomUnderSampler(random_state=42)
X_res, y_res = rus.fit_sample(X, y)
allknn = AllKNN(random_state=42)
X_res, y_res = allknn.fit_sample(X, y)
enn = EditedNearestNeighbours(random_state=42)
X_res, y_res = enn.fit_sample(X, y)
Combination of Over- and Under-sampling Methods
过采样容易导致过拟合,欠采样又由于无法覆盖数据集,容易丢失大量有效信息,因此我们可以考虑将这两个方法进行结合。此类算法主要有 SMOTEENN 算法和 SMOTETomek 算法两种。
SMOTEENN 算法和 SMOTETomek 算法的具体操作步骤比较类似,都分为两个步骤,先是采用 SMOTE 算法进行过采样,再采用一定的欠采样方法保留能够体现各类别特征分布的样本。两者的主要区别是:SMOTEENN 算法采用 EditedNearestNeighbours 算法来进行欠采样,EditedNearestNeighbours 算法基于 k 近邻算法,它根据相邻样本的标签,预测过采样后得到的数据集中的每一个样本的标签,若预测错误则移除该样本;而 SMOTETomek 算法是通过去除 Tomek Link 对来得到最终的平衡数据集。具体实现如下:
from imblearn.combine import SMOTEENN, SMOTETomek
sme = SMOTEENN(random_state=42)
X_res, y_res = sme.fit_sample(X, y)
smt = SMOTETomek(random_state=42)
X_res, y_res = smt.fit_sample(X, y)
Loss Weighting
损失加权是机器学习和深度学习中解决样本不平衡的常用方法,其实际上有点类似随机过采样的思路,所以也容易导致过拟合,在 TensorFlow 下实现损失加权的方法(Stackoverflow 链接)如下:
# your class weights
class_weights = tf.constant([[1.0, 2.0, 3.0]])
# deduce weights for batch samples based on their true label
weights = tf.reduce_sum(class_weights * onehot_labels, axis=1)
# compute your (unweighted) softmax cross entropy loss
unweighted_losses = tf.nn.softmax_cross_entropy_with_logits(onehot_labels, logits)
# apply the weights, relying on broadcasting of the multiplication
weighted_losses = unweighted_losses * weights
# reduce the result to get your final loss
loss = tf.reduce_mean(weighted_losses)
Ensemble Learning
集成学习也是解决样本不平衡的方法之一,其核心思路就是训练多个模型,每个模型的输入是部分多数类样本和全部少数类样本,然后再利用组合方法(投票、加权投票等)将学习器的结果结合起来。