在开发分类机器学习模型时遇到的挑战之一是类别不平衡。大多数用于分类的机器学习算法都是在假设平衡类的情况下开发的,然而,在现实生活中,拥有适当平衡的数据并不常见。因此,人们提出了各种方案来解决这个问题,以及一些应用这些解决方案的工具或者类库。例如,imbalanced-learn 这个python库,它实现了最相关的算法来解决类不平衡的问题。
在这篇文章中,我们将了解什么是类别不平衡、将准确性作为不平衡类别的度量标准的问题是什么、什么是随机欠采样和随机过采样,以及imbalanced-learn如何作为解决类别不平衡问题的替代工具。文章将分为以下几个部分:
- 什么是类别不平衡?
- 准确率悖论
- 欠采样和过采样
- Imbalanced-learn使用实践
什么是类别不平衡
当每个类别的样本不平衡时,即在类别分布之间没有平衡比率时,会出现类别不平衡的问题。这种失衡可能是轻微的,也可能是严重的。取决于样本量,比率从1:2到1:10可以理解为轻微的不平衡,比率大于1:10可以理解为强烈的不平衡。在这两种情况下,都必须使用特殊技术(例如欠采样,过采样,cost-sensitive代价敏感等)处理具有类不平衡问题的数据。稍后,我们将用imblearn [1]介绍欠采样和过采样以及它们的实现。
准确率悖论
在分类问题中处理不平衡数据时要考虑的基本问题之一是使用的度量。准确率Accuracy 常用作事实度量标准,但是对于类不平衡问题,由于准确率可能会产生误导,因此不是一个好的选择,该问题被称为准确率悖论。让我们看一下图2,以更好地理解准确率悖论。
当使用准确率 accuracy作为评估使用类不平衡问题数据集训练的机器学习模型的指标时,结果可能会产生误导。如我们所见,准确度为92%,这使我们假设该模型足够好。但是,如果我们仔细观察,就会发现该模型学会了将所有事物分类为0类,从而产生了具有足够好的准确性的效果。在这些情况下,除了应用某种方法来解决类不平衡问题外,建议引入其他评估指标,例如精度precision,召回率和F1-Score。让我们看一下图3,以更好地了解精度precision,召回率和F1-Score指标如何帮助我们更好地了解结果。
准确率Accuracy 是一种度量标准,用于衡量真实肯定和真实否定之间的平衡,但是,当数据集出现类不平衡问题时,模型很可能会学习将所有内容归类为优势类,在这种情况下归类为类0。,即使该模型已将100%的数据分类为0类,但鉴于TN的数量占主导地位,其准确率也足够好。这就是为什么当存在类不平衡问题(准确性悖论)时,准确率Accuracy 度量常常会误导人们的原因。
精度precision度量标准是:“在所有模型列为正数的元素中,有多少是正确的。”“我们观察到的精度是完美的,它会使我们认为“好,准确率和精度都足够好”,然而它并不完全正确,因为10类1的元素,只有2个分类正确,也就是说,8个分类不正确,对比分类不正确可以在召回指标中观察到。
召回率recall度量标准是:“按模型分类为阳性类别的人与y类别但实际上为正的人之间的平衡”。如锅召回率非常低就表明某些事情是不正确的。也就是说,一些确实为阳性的样本被归类为阴性。在实际情况下,让我们假设阳性类别是指“患有癌症”,而阴性类别是指“未患有癌症”,在这种情况下,我们会将许多真正患有癌症的人分类为没有癌症的人这肯定是致命性的错误。
最后,为了概括精度和召回率指标,我们实现了F1-Score指标,该指标被理解为精度和召回率之间的“谐波平均值”,换句话说,它提供了两个指标之间的比率。如我们所见,F1-Score值很低,这是另一个不正确的指标(在我们的示例中,精度是完美的,但召回率很差)。
到目前为止,我们已经看到了类不平衡问题,使用不平衡类的一些后果,以及评估存在类不平衡问题的模型时需要考虑的一些指标。现在,我们来看一些可以用来调整类不平衡的方法,特别是看看应用基于欠采样和过采样的技术的效果。
欠采样和过采样
当类别分布之间没有平衡时,就会出现类别不平衡问题,也就是说相对于一个或多个类别过多导致数据的失衡。直观上说可以通过将样本添加到少数类别或从多数类别中删除样本或两者结合来解决此问题。从多数类中删除样本的过程称为欠采样,而将样本添加到少数类中的过程称为过采样。
随机欠采样是指多数类别的随机采样。进行该过程,直到达到少数群体的平衡为止。尽管此技术有助于在多数和少数类别之间建立平衡,但是从多数类中删除样本时可能会丢失重要信息。
随机过采样是指少数群体样本的随机重复。进行添加过程直到相对于多数类达到平衡为止,但是,此技术可能导致训练模型过度适应少数类。
随机欠采样和随机过采样可以理解为解决类不平衡问题的基本技术。如今,有更多有希望的技术试图改善基于随机方法的弊端,例如合成数据增强(SMOTE [2],ADASYN [3])或基于聚类的欠采样技术(ENN [4])。
我们已经知道基于欠采样和过采样的技术是什么,让我们看看如何在实践中使用它们!
Imbalanced-learn使用实践
Imbalanced-learn是一个开源Python库[5],由Guillaume Lemaître等人开发。[6]提供了一套处理类不平衡问题的算法。这一套算法分为四类:欠采样、过采样、过/欠采样结合和集成学习方法。出于我们的目的,在这种情况下,我们将只使用欠采样和过采样扩展。
下面的示例将使用不平衡数据集。我们将训练机器学习模型(决策树),并评估其准确率、精度、召回率和f1-score。随后,我们将使用欠采样和过采样算法,并再次评估上述指标,将未解决不平衡问题的模型训练结果与使用欠采样和过采样的结果进行比较。
所以让我们首先生成一个不平衡的数据集:
fromsklearn.datasetsimportmake_classification#Generatestoydatasetforbinaryclassificationwithshapex= [5000, 20] defgenerate_data(): x, y=make_classification(n_samples=5000, n_features=20, n_classes=2, weights=[0.95, 0.05]) returnx, y
生成的不平衡数据集看起来如图4所示:
如我们所见,生成的数据集存在类不平衡的问题,比率为1:10。在应用欠采样和过采样算法之前,我们将定义一个函数,该函数能够使用固定的数据集训练决策树。
#Metricsfromsklearn.metricsimportrecall_scorefromsklearn.metricsimportaccuracy_scorefromsklearn.metricsimportprecision_scorefromsklearn.metricsimportf1_scorefromsklearn.treeimportDecisionTreeClassifierfromsklearn.model_selectionimportStratifiedKFolddefclassify(x, y): print(f"Samples of class 0: {y.shape[0] - np.sum(y)}") print(f"Samples of class 1: {np.sum(y)}") #Definesthemodeltobeusedmodel=DecisionTreeClassifier(max_depth=3) avg_accuracy= [] avg_precision= [] avg_recall= [] avg_f1score= [] #DefinesStratifiedK-foldinordertokeep#theclassbalanceforeachfoldst_k_fold=StratifiedKFold(n_splits=10) fortrain_idx, test_idxinst_k_fold.split(x, y): #Trainingfoldx_train=x[train_idx] y_train=y[train_idx] #Testingfoldx_test=x[test_idx] y_test=y[test_idx] #Trainmodel.fit(x_train, y_train) #Getmetricsaccuracy=accuracy_score(y_test, model.predict(x_test)) precision=precision_score(y_test, model.predict(x_test)) recall=recall_score(y_test, model.predict(x_test)) f1score=f1_score(y_test, model.predict(x_test)) #Savemetricsavg_accuracy.append(accuracy) avg_precision.append(precision) avg_recall.append(recall) avg_f1score.append(f1score) print(f"Avg accuracy: {np.mean(avg_accuracy)}") print(f"Avg precision: {np.mean(avg_precision)}") print(f"Avg recall: {np.mean(avg_recall)}") print(f"Avg f1-score: {np.mean(avg_f1score)}")
正如我们已经观察到的,该函数实现了分层K折交叉验证技术,以便在每个折的类之间保持相同的平衡。
为了进行说明性比较,我们将定义一组函数,这些函数应用每种采样算法(随机采样和上下采样),SMOTE以及一个虚拟版本(用于训练决策树而不考虑类不平衡问题)。
fromimblearn.under_samplingimportRandomUnderSamplerfromimblearn.over_samplingimportRandomOverSamplerfromimblearn.over_samplingimportSMOTE#AppliesDTwithoutfixingtheclassimbalanceproblem. defdummy_decision_tree(): classify(x, y) #AppliesRandomUndersamplingdefunder_sampler(): rus=RandomUnderSampler() x, y=rus.fit_resample(x, y) classify(x, y) #AppliesRandomUndersamplingdefover_sampler(): ros=RandomOverSampler() x, y=ros.fit_resample(x, y) classify(x, y) #AppliesSyntheticDataAugmentationthroughSMOTEdefsmote(): smote=SMOTE() x, y=smote.fit_resample(x, y) classify(x, y)
函数(第6行)使用代码段1中生成的数据训练决策树,而无需考虑类不平衡问题。在第10行应用随机欠采样,在第17行应用随机过采样,在第25行应用SMOTE。在图5中,我们可以看到在应用每种算法时如何转换类平衡。
如我们所见,欠采样算法从多数类中删除了样本,使其与少数类保持一致。另一方面,过采样算法会复制少数类的元素(如果您看到的话,该图看起来类似于图4中的图)。最后,SMOTE(一种数据增强技术)增加了少数派的样本,直到与多数派达到平衡为止。结果如图6所示。
我们可以看到,在应用技术来纠正类平衡问题时,模型的有效性得到了提高。对于此特定示例,基于合成数据扩充(SMOTE)的技术显示出更好的结果。归根结底,实施技术将完全取决于您使用的数据。值得一提的是,imbalanced-learn提供了各种各样的算法来解决不平衡类的问题,值得一看其文档[1]。
总结
在此文章中,我们看到了类不平衡的问题以及使用不平衡数据集时必须考虑的指标。我们还看到了一个示例,该示例如何使用基于采样和数据扩充的算法解决类不平衡问题。我们还利用了不平衡学习库来扩展示例中使用的算法。