Machine Learning Mastery 不平衡数据教程(八)
用于不平衡分类的阈值移动的温和介绍
最后更新于 2021 年 1 月 5 日
分类预测建模通常包括预测类别标签。
然而,许多机器学习算法能够预测类成员的概率或得分,这必须在映射到清晰的类标签之前进行解释。这是通过使用阈值(如 0.5)来实现的,其中所有等于或大于阈值的值都映射到一个类,而所有其他值都映射到另一个类。
对于那些类别严重失衡的分类问题,默认阈值可能会导致表现不佳。因此,提高预测不平衡分类问题上的概率的分类器的表现的简单和直接的方法是调整用于将概率映射到类别标签的阈值。
在某些情况下,例如当使用 ROC 曲线和准确率-召回曲线时,可以直接计算分类器的最佳或最优阈值。在其他情况下,可以使用网格搜索来调整阈值并定位最佳值。
在本教程中,您将发现如何在将概率转换为清晰的类标签进行不平衡分类时调整最佳阈值。
完成本教程后,您将知道:
- 将概率解释为类标签的默认阈值是 0.5,调整这个超参数称为阈值移动。
- 如何直接计算 ROC 曲线和准确率-召回曲线的最佳阈值。
- 如何手动搜索所选模型和模型评估指标的阈值。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2020 年 2 月更新:修正了特异性方程的错别字。
- 2021 年 1 月更新:更新了 API 文档的链接。
不平衡分类阈值移动介绍 图片由布鲁纳 cs 提供,保留部分权利。
教程概述
本教程分为五个部分;它们是:
- 将概率转换为类别标签
- 不平衡分类的阈值移动
- ROC 曲线的最佳阈值
- 精确-召回曲线的最佳阈值
- 最佳阈值调整
将概率转换为类别标签
许多机器学习算法能够预测类成员的概率或得分。
这通常是有用的,因为它提供了预测的确定性或不确定性的度量。它还提供了额外的粒度,而不仅仅是预测可以解释的类标签。
一些分类任务需要清晰的类别标签预测。这意味着,即使预测了类成员的概率或得分,也必须将其转换为清晰的类标签。
用于将预测概率或得分转换成类别标签的决策由被称为“决策阈值”、“判别阈值或简称为“阈值的参数控制对于 0 或 1 范围内的归一化预测概率或分数,阈值的默认值为 0.5。
例如,在类别标签为 0 和 1、归一化预测概率和阈值为 0.5 的二进制分类问题上,小于阈值 0.5 的值被分配给类别 0,大于或等于 0.5 的值被分配给类别 1。
- 预测< 0.5 = 0 级
- 预测> = 0.5 = 1 级
问题是默认阈值可能不代表预测概率的最佳解释。
这可能有许多原因,例如:
- 预测的概率没有被校准,例如由 SVM 或决策树预测的概率。
- 用于训练模型的度量不同于用于评估最终模型的度量。
- 阶级分布严重失衡。
- 一种错误分类的代价比另一种错误分类更重要。
更糟糕的是,这些原因中的一些或全部可能同时发生,例如在不平衡分类问题上使用具有未校准预测概率的神经网络模型。
因此,在解释模型预测时,通常需要更改默认决策阈值。
……几乎所有分类器都通过对分数应用阈值来生成正面或负面预测。这个阈值的选择将对正负误差的权衡产生影响。
—第 53 页,从不平衡数据集中学习,2018。
不平衡分类的阈值移动
有许多技术可以用来解决不平衡的分类问题,例如重新采样训练数据集和开发定制版本的机器学习算法。
然而,也许处理严重的阶级不平衡的最简单的方法是改变决策阈值。尽管简单且非常有效,但这种技术经常被实践者和研究学者所忽视,正如福斯特·普罗沃斯特在他 2000 年的文章《不平衡数据集的机器学习》中所指出的那样
底线是,当研究数据不平衡的问题时,使用标准机器学习算法产生的分类器而不调整输出阈值很可能是一个严重的错误。
——来自不平衡数据集的机器学习 101 ,2000。
选择默认决策阈值的替代方案有很多原因。
例如,您可以使用 ROC 曲线来分析模型的预测概率,并使用 ROC AUC 分数来比较和选择模型,尽管您需要模型中清晰的类别标签。如何在 ROC 曲线上选择阈值,使真阳性率和假阳性率达到最佳平衡?
或者,您可以使用准确率-召回曲线来分析模型的预测概率,准确率-召回 AUC 来比较和选择模型,并需要清晰的类标签作为预测。您如何选择准确率-召回率曲线上的阈值,以实现准确率和召回率之间的最佳平衡?
您可以使用基于概率的度量来训练、评估和比较像对数损失(交叉熵)这样的模型,但是需要清晰的类标签来进行预测。如何更一般地从预测概率中选择最佳阈值?
最后,您可能会有与假阳性和假阴性错误分类相关的不同成本,即所谓的成本矩阵,但希望使用和评估对成本不敏感的模型,然后使用对成本敏感的度量来评估它们的预测。如何选择一个阈值,利用成本矩阵找到预测的最佳平衡点?
在没有已知成本矩阵的情况下,训练对成本敏感的分类器的流行方法是,当对新数据进行预测时,强调修改分类输出。这通常是通过在正类上设置一个阈值来实现的,低于该阈值,负类将被预测。使用验证集优化该阈值的值,因此可以从训练数据中学习成本矩阵。
—第 67 页,从不平衡数据集中学习,2018。
这些问题的答案是搜索一系列阈值,以便找到最佳阈值。在某些情况下,可以直接计算最佳阈值。
为了适应分类问题的更广泛要求而调整或移动决策阈值通常被称为“阈值移动”、“阈值调整”或简称为“阈值设定”
有人指出,尝试其他方法,如取样,而不仅仅通过设定阈值来尝试,可能会产生误导。阈值移动方法使用原始训练集来训练[模型],然后移动决策阈值,使得少数类示例更容易被正确预测。
—第 72 页,不平衡学习:基础、算法和应用,2013。
该过程包括首先在训练数据集上拟合模型,然后在测试数据集上进行预测。预测是以归一化概率或分数的形式,这些概率或分数被转换成归一化概率。然后尝试不同的阈值,并使用所选的评估度量来评估结果清晰的标签。然后,当对未来的新数据进行预测时,模型采用达到最佳评估指标的阈值。
我们可以在下面总结这个过程。
- 1.在训练数据集上拟合模型。
- 2.预测测试数据集中的概率。
- 3.对于阈值中的每个阈值:
- 3a .使用阈值将概率转换为类别标签。
- 3b。评估类别标签。
- 3c。如果分数优于最佳分数。
- 3ci。采用阈值。
- 4.对新数据进行类别预测时,使用采用的阈值。
虽然简单,但根据您的情况,有几种不同的方法来实现阈值移动。我们将在下面几节中看一些最常见的例子。
ROC 曲线的最佳阈值
ROC 曲线是一种诊断图,用于评估模型在测试数据集上做出的一组概率预测。
一组不同的阈值用于解释阳性(少数)类预测的真阳性率和假阳性率,分数绘制在一条阈值递增的线上,以创建一条曲线。
假阳性率标绘在 x 轴上,真阳性率标绘在 y 轴上,该标绘称为接收器工作特性曲线或 ROC 曲线。图中从左下角到右上角的对角线表示无技能分类器的“曲线”(预测所有情况下的多数类),图左上角的点表示技能完美的模型。
该曲线有助于理解不同阈值下的真阳性率和假阳性率之间的权衡。ROC 曲线下的区域,即所谓的 ROC AUC,提供了一个单一的数字来总结模型在其 ROC 曲线方面的表现,其值介于 0.5(无技能)和 1.0(完美技能)之间。
ROC 曲线是一个有用的诊断工具,用于了解不同阈值之间的权衡,ROC AUC 提供了一个有用的数字,用于根据模型的一般能力进行比较。
如果在这种分析下,模型需要清晰的类标签,那么就需要一个最佳阈值。这将是曲线上最靠近图左上角的一个阈值。
谢天谢地,找到这一点有原则的方法。
首先,让我们拟合一个模型,计算一个 ROC 曲线。
我们可以使用 make_classification()函数创建一个包含 10,000 个示例(行)的合成二进制分类问题,其中 99%属于多数类,1%属于少数类。
...
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=4)
然后,我们可以使用 train_test_split()函数分割数据集,并将一半用于训练集,另一半用于测试集。
...
# split into train/test sets
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2, stratify=y)
然后,我们可以拟合一个逻辑推理模型,并使用它对测试集进行概率预测,只保留少数类的概率预测。
...
# fit a model
model = LogisticRegression(solver='lbfgs')
model.fit(trainX, trainy)
# predict probabilities
lr_probs = model.predict_proba(testX)
# keep probabilities for the positive outcome only
lr_probs = lr_probs[:, 1]
然后,我们可以使用 roc_auc_score()函数使用一组阈值计算预测的真阳性率和假阳性率,然后使用这些阈值创建 roc 曲线图。
...
# calculate scores
lr_auc = roc_auc_score(testy, lr_probs)
我们可以将这些联系在一起,定义数据集,拟合模型,并创建 ROC 曲线图。下面列出了完整的示例。
# roc curve for logistic regression model
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve
from matplotlib import pyplot
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=4)
# split into train/test sets
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2, stratify=y)
# fit a model
model = LogisticRegression(solver='lbfgs')
model.fit(trainX, trainy)
# predict probabilities
yhat = model.predict_proba(testX)
# keep probabilities for the positive outcome only
yhat = yhat[:, 1]
# calculate roc curves
fpr, tpr, thresholds = roc_curve(testy, yhat)
# plot the roc curve for the model
pyplot.plot([0,1], [0,1], linestyle='--', label='No Skill')
pyplot.plot(fpr, tpr, marker='.', label='Logistic')
# axis labels
pyplot.xlabel('False Positive Rate')
pyplot.ylabel('True Positive Rate')
pyplot.legend()
# show the plot
pyplot.show()
运行该示例使逻辑回归模型适合训练数据集,然后使用测试集上的一系列阈值对其进行评估,从而创建 ROC 曲线
我们可以看到,在靠近图的左上角有许多点或阈值。
哪个是最佳阈值?
不平衡分类逻辑回归模型的 ROC 曲线
有许多方法可以在假阳性率和真阳性率之间找到最佳平衡点。
首先,真正的阳性率被称为敏感度。假阳性率的倒数称为特异性。
- 灵敏度=真正/(真正+假负)
- 特异性=真阴性/(假阳性+真阴性)
其中:
- 灵敏度=真阳性率
- 特异性= 1–假阳性率
几何平均或 G-均值是不平衡分类的一种度量,如果优化,它将寻求灵敏度和特异性之间的平衡。
- g-均值= sqrt(灵敏度*特异性)
一种方法是用呼叫返回的每个阈值来测试模型 roc_auc_score() 并选择具有最大 G 均值的阈值。
假设我们在计算 ROC 曲线时已经计算了敏感性(TPR)和特异性的补充,我们可以直接计算每个阈值的 G 均值。
...
# calculate the g-mean for each threshold
gmeans = sqrt(tpr * (1-fpr))
一旦计算出来,我们就可以找到最大 G 均值分数的指数,并使用该指数来确定使用哪个阈值。
...
# locate the index of the largest g-mean
ix = argmax(gmeans)
print('Best Threshold=%f, G-Mean=%.3f' % (thresholds[ix], gmeans[ix]))
我们也可以重新绘制 ROC 曲线,突出这一点。
下面列出了完整的示例。
# roc curve for logistic regression model with optimal threshold
from numpy import sqrt
from numpy import argmax
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve
from matplotlib import pyplot
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=4)
# split into train/test sets
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2, stratify=y)
# fit a model
model = LogisticRegression(solver='lbfgs')
model.fit(trainX, trainy)
# predict probabilities
yhat = model.predict_proba(testX)
# keep probabilities for the positive outcome only
yhat = yhat[:, 1]
# calculate roc curves
fpr, tpr, thresholds = roc_curve(testy, yhat)
# calculate the g-mean for each threshold
gmeans = sqrt(tpr * (1-fpr))
# locate the index of the largest g-mean
ix = argmax(gmeans)
print('Best Threshold=%f, G-Mean=%.3f' % (thresholds[ix], gmeans[ix]))
# plot the roc curve for the model
pyplot.plot([0,1], [0,1], linestyle='--', label='No Skill')
pyplot.plot(fpr, tpr, marker='.', label='Logistic')
pyplot.scatter(fpr[ix], tpr[ix], marker='o', color='black', label='Best')
# axis labels
pyplot.xlabel('False Positive Rate')
pyplot.ylabel('True Positive Rate')
pyplot.legend()
# show the plot
pyplot.show()
运行该示例首先定位最佳阈值,并报告该阈值和平均得分。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到最佳阈值约为 0.016153。
Best Threshold=0.016153, G-Mean=0.933
然后使用阈值来定位真阳性率和假阳性率,然后在 ROC 曲线上画出该点。
我们可以看到,最佳阈值的点是一个大黑点,它似乎最接近图的左上角。
具有最优阈值的不平衡分类逻辑回归模型的 ROC 曲线
事实证明,有一种更快的方法可以得到同样的结果,叫做尤登的 J 统计。
统计计算如下:
- J =灵敏度+特异性–1
假设我们有灵敏度(TPR)和特异性的补充(FPR),我们可以将其计算为:
- J =灵敏度+(1–假阳性平均值)-1
我们可以重申为:
- J =真正平均值–假正平均值
然后我们可以选择具有最大 J 统计值的阈值。例如:
...
# calculate roc curves
fpr, tpr, thresholds = roc_curve(testy, yhat)
# get the best threshold
J = tpr - fpr
ix = argmax(J)
best_thresh = thresholds[ix]
print('Best Threshold=%f' % (best_thresh))
插上这个,完整的例子如下。
# roc curve for logistic regression model with optimal threshold
from numpy import argmax
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=4)
# split into train/test sets
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2, stratify=y)
# fit a model
model = LogisticRegression(solver='lbfgs')
model.fit(trainX, trainy)
# predict probabilities
yhat = model.predict_proba(testX)
# keep probabilities for the positive outcome only
yhat = yhat[:, 1]
# calculate roc curves
fpr, tpr, thresholds = roc_curve(testy, yhat)
# get the best threshold
J = tpr - fpr
ix = argmax(J)
best_thresh = thresholds[ix]
print('Best Threshold=%f' % (best_thresh))
我们可以看到,这种更简单的方法直接计算最优统计量。
Best Threshold=0.016153
精确-召回曲线的最佳阈值
与 ROC 曲线不同的是,准确率-召回率曲线只关注正类(少数类)分类器的表现。
准确率是真阳性数除以真阳性和假阳性之和的比率。它描述了一个模型在预测正类方面有多好。回忆的计算方法是真阳性数除以真阳性和假阴性之和。回忆和敏感是一样的。
通过在一组阈值上为概率预测创建清晰的类标签,并计算每个阈值的准确率和召回率,来计算准确率-召回率曲线。将为阈值创建一个折线图,以升序排列,x 轴表示召回率,y 轴表示准确率。
无技能模型由一条水平线表示,其准确率是数据集中正面示例的比率(例如 TP / (TP + TN)),或者在我们的合成数据集中为 0.01。完美技能分类器具有完全的准确率和召回率,右上角有一个点。
我们可以使用上一节中的相同模型和数据集,并使用准确率-召回曲线评估逻辑回归模型的概率预测。准确率 _ 召回 _ 曲线()函数可用于计算曲线,返回每个阈值的准确率和召回分数以及使用的阈值。
...
# calculate pr-curve
precision, recall, thresholds = precision_recall_curve(testy, yhat)
将这些联系在一起,下面列出了为不平衡分类问题上的逻辑回归计算准确率-召回率曲线的完整示例。
# pr curve for logistic regression model
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import precision_recall_curve
from matplotlib import pyplot
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=4)
# split into train/test sets
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2, stratify=y)
# fit a model
model = LogisticRegression(solver='lbfgs')
model.fit(trainX, trainy)
# predict probabilities
yhat = model.predict_proba(testX)
# keep probabilities for the positive outcome only
yhat = yhat[:, 1]
# calculate pr-curve
precision, recall, thresholds = precision_recall_curve(testy, yhat)
# plot the roc curve for the model
no_skill = len(testy[testy==1]) / len(testy)
pyplot.plot([0,1], [no_skill,no_skill], linestyle='--', label='No Skill')
pyplot.plot(recall, precision, marker='.', label='Logistic')
# axis labels
pyplot.xlabel('Recall')
pyplot.ylabel('Precision')
pyplot.legend()
# show the plot
pyplot.show()
运行该示例会计算每个阈值的准确率和召回率,并创建一个准确率-召回率图,显示模型在该数据集的一系列阈值上具有一定的技能。
如果我们要求这个模型有清晰的类标签,哪个阈值会达到最好的结果?
不平衡分类逻辑回归模型的准确率-召回曲线
如果我们对一个能在准确率和召回率之间取得最佳平衡的阈值感兴趣,那么这就和优化总结两种度量的调和平均值的 F 度量一样。
- F-Measure = (2 准确率召回)/(准确率+召回)
如前一节所述,寻找最佳阈值的简单方法是计算每个阈值的 F 测度。我们可以通过将准确率和召回率直接转换为 F-measure 来达到同样的效果;例如:
...
# convert to f score
fscore = (2 * precision * recall) / (precision + recall)
# locate the index of the largest f score
ix = argmax(fscore)
print('Best Threshold=%f, F-Score=%.3f' % (thresholds[ix], fscore[ix]))
然后,我们可以在准确率-召回曲线上绘制该点。
下面列出了完整的示例。
# optimal threshold for precision-recall curve with logistic regression model
from numpy import argmax
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import precision_recall_curve
from matplotlib import pyplot
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=4)
# split into train/test sets
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2, stratify=y)
# fit a model
model = LogisticRegression(solver='lbfgs')
model.fit(trainX, trainy)
# predict probabilities
yhat = model.predict_proba(testX)
# keep probabilities for the positive outcome only
yhat = yhat[:, 1]
# calculate roc curves
precision, recall, thresholds = precision_recall_curve(testy, yhat)
# convert to f score
fscore = (2 * precision * recall) / (precision + recall)
# locate the index of the largest f score
ix = argmax(fscore)
print('Best Threshold=%f, F-Score=%.3f' % (thresholds[ix], fscore[ix]))
# plot the roc curve for the model
no_skill = len(testy[testy==1]) / len(testy)
pyplot.plot([0,1], [no_skill,no_skill], linestyle='--', label='No Skill')
pyplot.plot(recall, precision, marker='.', label='Logistic')
pyplot.scatter(recall[ix], precision[ix], marker='o', color='black', label='Best')
# axis labels
pyplot.xlabel('Recall')
pyplot.ylabel('Precision')
pyplot.legend()
# show the plot
pyplot.show()
运行该示例首先计算每个阈值的 F 度量,然后定位具有最大值的分数和阈值。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到最佳的 F 值是 0.756,阈值约为 0.25。
Best Threshold=0.256036, F-Score=0.756
绘制了准确率-召回率曲线,这次用较大的黑点绘制了具有最佳 F 度量的阈值。
然后,当在未来进行概率预测时,必须将概率转换为清晰的类别标签时,可以使用该阈值。
具有最优阈值的逻辑回归模型的准确率-召回曲线
最佳阈值调整
有时,我们只是有一个模型,我们希望直接知道最佳阈值。
在这种情况下,我们可以定义一组阈值,然后评估每个阈值下的预测概率,以便找到并选择最佳阈值。
我们可以用一个成功的例子来证明这一点。
首先,我们可以在我们的综合分类问题上拟合一个逻辑回归模型,然后预测类标签并使用 F-Measure 对它们进行评估,F-Measure 是准确率和召回率的调和平均值。
在解释逻辑回归模型预测的概率时,这将使用默认阈值 0.5。
下面列出了完整的示例。
# logistic regression for imbalanced classification
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=4)
# split into train/test sets
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2, stratify=y)
# fit a model
model = LogisticRegression(solver='lbfgs')
model.fit(trainX, trainy)
# predict labels
yhat = model.predict(testX)
# evaluate the model
score = f1_score(testy, yhat)
print('F-Score: %.5f' % score)
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
运行该示例,我们可以看到该模型在测试数据集上实现了大约 0.70 的 F-Measure。
F-Score: 0.70130
现在我们可以在相同的数据集上使用相同的模型,而不是直接预测类标签,我们可以预测概率。
...
# predict probabilities
yhat = model.predict_proba(testX)
我们只需要正类的概率。
...
# keep probabilities for the positive outcome only
probs = yhat[:, 1]
接下来,我们可以定义一组阈值来评估概率。在这种情况下,我们将测试 0.0 到 1.0 之间的所有阈值,步长为 0.001,也就是说,我们将测试 0.0、0.001、0.002、0.003,以此类推到 0.999。
...
# define thresholds
thresholds = arange(0, 1, 0.001)
接下来,我们需要一种使用单一阈值来解释预测概率的方法。
这可以通过将等于或大于阈值的所有值映射为 1 并将小于阈值的所有值映射为 0 来实现。我们将定义一个到 _labels() 函数来实现这一点,该函数将概率和阈值作为参数,并返回{0,1}中的整数数组。
# apply threshold to positive probabilities to create labels
def to_labels(pos_probs, threshold):
return (pos_probs >= threshold).astype('int')
然后,我们可以为每个阈值调用该函数,并使用 f1_score() 评估结果标签。
我们可以在一行中完成,如下所示:
...
# evaluate each threshold
scores = [f1_score(testy, to_labels(probs, t)) for t in thresholds]
我们现在有一系列的分数来评估我们的阈值阵列中的每个阈值。
我们现在需要做的就是找到得分最大的数组索引(最好的 F-Measure),我们将得到最佳阈值及其评估。
...
# get best threshold
ix = argmax(scores)
print('Threshold=%.3f, F-Score=%.5f' % (thresholds[ix], scores[ix]))
将所有这些结合起来,下面列出了在综合不平衡类别数据集上调整逻辑回归模型阈值的完整示例。
# search thresholds for imbalanced classification
from numpy import arange
from numpy import argmax
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
# apply threshold to positive probabilities to create labels
def to_labels(pos_probs, threshold):
return (pos_probs >= threshold).astype('int')
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=4)
# split into train/test sets
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2, stratify=y)
# fit a model
model = LogisticRegression(solver='lbfgs')
model.fit(trainX, trainy)
# predict probabilities
yhat = model.predict_proba(testX)
# keep probabilities for the positive outcome only
probs = yhat[:, 1]
# define thresholds
thresholds = arange(0, 1, 0.001)
# evaluate each threshold
scores = [f1_score(testy, to_labels(probs, t)) for t in thresholds]
# get best threshold
ix = argmax(scores)
print('Threshold=%.3f, F-Score=%.5f' % (thresholds[ix], scores[ix]))
运行该示例报告的最佳阈值为 0.251(默认值为 0.5),其 F-Measure 值约为 0.75(默认值为 0.70)。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
当您根据自己的问题调整阈值时,可以使用此示例作为模板,允许您替换自己的模型、度量,甚至是要评估的阈值的分辨率。
Threshold=0.251, F-Score=0.75556
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 不平衡数据集的机器学习 101 ,2000。
- 用解决类不平衡问题的方法训练成本敏感的神经网络,2005。
书
- 从不平衡数据集中学习,2018。
- 不平衡学习:基础、算法和应用,2013。
蜜蜂
- 硬化. metrics.roc_curve API 。
- imb learn . metrics . geometry _ mean _ score API。
- sklearn . metrics . precision _ recall _ curve API。
文章
摘要
在本教程中,您发现了如何在将概率转换为清晰的类标签以进行不平衡分类时调整最佳阈值。
具体来说,您了解到:
- 将概率解释为类标签的默认阈值是 0.5,调整这个超参数称为阈值移动。
- 如何直接计算 ROC 曲线和准确率-召回曲线的最佳阈值。
- 如何手动搜索所选模型和模型评估指标的阈值。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
不平衡分类的评估指标之旅
最后更新于 2021 年 5 月 1 日
一个分类器只和用来评估它的度量一样好。
如果您选择了错误的指标来评估您的模型,您很可能会选择一个糟糕的模型,或者在最坏的情况下,在模型的预期表现方面被误导。
在应用机器学习中,选择合适的度量标准通常具有挑战性,但对于不平衡的分类问题尤其困难。首先,因为大多数广泛使用的标准度量假设了平衡的类分布,并且因为通常不是所有的类,因此不是所有的预测误差,对于不平衡的分类是相等的。
在本教程中,您将发现可用于不平衡分类的指标。
完成本教程后,您将知道:
- 关于选择用于分类的度量的挑战,以及当存在偏斜的类分布时如何特别困难。
- 如何评估分类器模型有三种主要的度量,称为等级、阈值和概率。
- 如果你不知道从哪里开始,如何选择不平衡分类的度量。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
不平衡分类评估指标之旅 图片由特拉维斯·怀斯提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 评估指标的挑战
- 分类器评估度量的分类
- 如何选择评估指标
评估指标的挑战
评估指标量化了预测模型的表现。
这通常涉及在数据集上训练模型,使用该模型对训练期间未使用的保持数据集进行预测,然后将预测与保持数据集中的期望值进行比较。
对于分类问题,度量包括将预期的类标签与预测的类标签进行比较,或者解释问题的类标签的预测概率。
选择模型,甚至数据准备方法都是一个由评估标准指导的搜索问题。用不同的模型进行实验,每个实验的结果用一个度量来量化。
评估措施在评估分类表现和指导分类器建模方面都起着至关重要的作用。
——不平衡数据的分类:综述,2009。
有标准的度量标准被广泛用于评估分类预测模型,例如分类准确率或分类误差。
标准度量在大多数问题上运行良好,这就是为什么它们被广泛采用的原因。但是所有的度量都是对问题或者问题中什么是重要的做出假设。因此,必须选择一个最能抓住您或您的项目涉众认为模型或预测的重要之处的评估指标,这使得选择模型评估指标具有挑战性。
当班级分布出现偏差时,这一挑战变得更加困难。其原因是,当类别不平衡或严重不平衡时,许多标准指标变得不可靠甚至误导,例如少数和多数类别之间的比例为 1:100 或 1:1000。
在阶级不平衡的情况下,这个问题甚至更加尖锐,因为当数据倾斜时,用于未类别数据的默认的、相对健壮的过程会崩溃。
—第 187 页,不平衡学习:基础、算法和应用,2013。
例如,报告严重不平衡分类问题的分类准确性可能会产生危险的误导。如果项目涉众利用结果得出结论或计划新项目,就会出现这种情况。
事实上,在不平衡的领域中使用通用的度量会导致次优的分类模型,并且可能产生误导性的结论,因为这些度量对倾斜的领域不敏感。
——不平衡分布下的预测建模综述,2015 年。
重要的是,在处理不平衡分类时,通常需要不同的评估指标。
与将所有类别视为同等重要的标准评估指标不同,不平衡分类问题通常将少数类别的分类错误评定为比多数类别的分类错误更重要。因此,可能需要关注少数群体的表现指标,这很有挑战性,因为少数群体缺乏训练有效模型所需的观察。
不平衡数据集的主要问题在于,它们通常与用户偏好倾向于在可用数据样本中表现不佳的情况下的表现有关。
——不平衡分布下的预测建模综述,2015 年。
现在我们已经熟悉了选择模型评估指标的挑战,让我们来看一些我们可以从中选择的不同指标的例子。
分类器评估度量的分类
当评估分类器模型时,有几十个度量可供选择,如果你考虑学术界提出的度量的所有宠物版本,可能有几百个。
为了掌握可供选择的指标,我们将使用塞萨尔·费里等人在 2008 年发表的题为“T2:分类表现指标的实验比较”的论文中提出的分类法 2013 年的《T4》不平衡学习也采用了这个方法,我认为证明是有用的。
我们可以将评估指标分为三个有用的组;它们是:
- 阈值度量
- 排名指标
- 概率度量。
这种划分是有用的,因为从业者通常用于分类器的顶级度量,特别是不平衡的分类,完全符合分类法。
一些机器学习研究人员已经确定了在分类环境中使用的三类评估指标。这些是阈值度量(例如,准确度和 f 测度)、排名方法和度量(例如,接收器操作特性(ROC)分析和 AUC)以及概率度量(例如,均方根误差)。
—第 189 页,不平衡学习:基础、算法和应用,2013。
让我们依次仔细看看每一组。
不平衡分类的阈值度量
阈值度量是量化分类预测误差的度量。
也就是说,它们旨在总结预测类与保持数据集中的预期类不匹配时的分数、比率或比率。
基于阈值的度量和对错误的定性理解……当我们想要一个模型来最小化错误的数量时,使用这些度量。
——分类表现指标的实验比较,2008 年。
也许最广泛使用的阈值度量是分类准确率。
- 准确性 =正确预测/总预测
而分类准确率的补充称为分类误差。
- 误差 =不正确的预测/总预测
尽管分类准确率被广泛使用,但它几乎普遍不适用于不平衡分类。原因是,高准确率(或低误差)可以通过只预测多数类的无技能模型来实现。
有关分类准确性失败的更多信息,请参见教程:
对于不平衡分类问题,多数类通常称为阴性结果(如“无变化”或“阴性检测结果”),少数类通常称为阳性结果(如“变化”或“阳性检测结果”)。
- 多数类:否定结果,0 类。
- 小众类:正面结局,1 类。
大多数阈值度量可以通过二进制(两类)分类问题的混淆矩阵中使用的术语来最好地理解。这并不意味着度量被限制用于二进制分类;这只是一种快速理解被测量内容的简单方法。
混淆矩阵不仅能更深入地了解预测模型的表现,还能更深入地了解哪些类被正确预测,哪些被错误预测,以及出现了什么类型的错误。在这种类型的混淆矩阵中,表中的每个单元格都有一个具体且易于理解的名称,总结如下:
| Positive Prediction | Negative Prediction
Positive Class | True Positive (TP) | False Negative (FN)
Negative Class | False Positive (FP) | True Negative (TN)
有两组度量可能对不平衡分类有用,因为它们集中在一个类上;它们是敏感性-特异性和精确性-回忆。
灵敏度-特异性指标
敏感度指的是真实的阳性率,并总结了阳性等级的预测情况。
- 灵敏度 =真正/(真正+假负)
特异性是敏感性的补充,或者说是真正的阴性率,总结了阴性等级的预测情况。
- 特异性 =真阴性/(假阳性+真阴性)
对于不平衡分类,敏感性可能比特异性更有趣。
敏感性和特异性可以结合成一个单一的分数来平衡这两个问题,称为几何平均值或 G 均值。
- G 均值 = sqrt(灵敏度*特异性)
准确率-召回度量
Precision 汇总了分配给正类的属于正类的示例的比例。
- 准确率 =真正/(真正+假正)
回忆总结了正类的预测效果,与敏感度的计算是一样的。
- 回忆 =真阳性/(真阳性+假阴性)
精确度和召回率可以合并成一个分数,寻求平衡这两个问题,称为 F 分数或 F 度量。
- F-Measure = (2 准确率召回)/(准确率+召回)
F-Measure 是一种流行的不平衡分类度量。
Fbeta 测度是 F 测度的抽象,其中谐波均值计算中的准确率和召回率的平衡由一个称为β的系数控制。
- fbeta-measure=((1+beta²)准确率召回)/ (beta² *准确率+召回)
有关不平衡分类的准确率、召回率和 F-measure 的更多信息,请参见教程:
附加阈值指标
这些可能是最受欢迎的度量标准,尽管还有很多其他的存在。为了让您品尝一下,这些包括卡帕,宏观平均准确率,平均类加权准确率,优化准确率,调整几何平均,平衡准确率,等等。
阈值指标易于计算和理解。
这些度量的一个限制是,当使用模型进行预测时,它们假设在训练数据集中观察到的类分布将匹配测试集中和真实数据中的分布。这是常有的事,但如果不是这样,表现可能会相当误导。
上一节中讨论的所有阈值度量的一个重要缺点是,它们假设完全了解部署分类器的条件。特别是,他们假设训练集中存在的类别不平衡是在分类器的整个运行寿命中会遇到的
—第 196 页,不平衡学习:基础、算法和应用,2013。
排名指标不会对类别分布做出任何假设。
不平衡分类的排序度量
等级度量更关心的是基于分类器在分类方面的有效性来评估分类器。
基于模型如何对示例进行排序的度量标准……这些对于许多应用程序……非常重要,在这些应用程序中,分类器用于选择数据集的最佳 n 个实例,或者当良好的类分离至关重要时。
——分类表现指标的实验比较,2008 年。
这些度量要求分类器预测类别成员的分数或概率。
根据这个分数,可以应用不同的阈值来测试分类器的有效性。那些在一系列阈值上保持良好分数的模型将具有良好的类分离,并且排名会更高。
…考虑一个分类器,它给出了一个实例的数值分数,该实例被分类为正类。因此,分数引入了一个粒度级别,而不是简单的正或负预测
–第 53 页,从不平衡数据集中学习,2018。
最常用的排名指标是 ROC 曲线或 ROC 分析。
ROC 是一个首字母缩略词,意思是接收器操作特性,总结了一个基于二进制分类器的分类能力来分析二进制分类器的研究领域。
ROC 曲线是一种诊断图,用于通过计算模型在不同阈值下对一组预测的假阳性率和真阳性率来总结模型的行为。
真正的阳性率是召回率或敏感度。
- 真阳性 =真阳性/(真阳性+假阴性)
假阳性率计算如下:
- 假阳性 =假阳性/(假阳性+真阴性)
每个阈值都是图上的一个点,这些点连接起来形成一条曲线。没有技能的分类器(例如,预测所有阈值下的多数类)将由从左下角到右上角的对角线表示。
这条线以下的任何点都比没有技能差。一个完美的模型将是剧情左上角的一个点。
ROC 曲线的描绘
ROC 曲线对一个模型是一个有用的诊断。
可以计算 ROC 曲线下的面积,并提供单个分数来总结可用于比较模型的图。
无技能分类器的得分为 0.5,而完美分类器的得分为 1.0。
- ROC AUC =曲线下的 ROC 面积
虽然一般有效,但 ROC 曲线和 ROC AUC 在严重的阶级不平衡下可以乐观,尤其是当少数阶级的例子数量很少时。
ROC 曲线的另一种选择是准确率-召回率曲线,它可以以类似的方式使用,尽管侧重于少数类分类器的表现。
同样,模型对一组预测使用不同的阈值,在这种情况下,计算准确率和召回率。这些点形成一条曲线,在一系列不同阈值下表现更好的分类器将被排列得更高。
无技能分类器将是图上的一条水平线,其准确率与数据集中的正例数成正比。对于平衡数据集,这将是 0.5。一个完美的分类器由右上角的一个点表示。
精确-召回曲线的描绘
像 ROC 曲线一样,准确率-召回曲线是评估单个分类器的有用诊断工具,但对比较分类器具有挑战性。
像 ROC AUC 一样,我们可以计算曲线下的面积作为分数,并使用该分数来比较分类器。在这种情况下,对少数类的关注使得精确-召回 AUC 对不平衡分类问题更有用。
- PR AUC =曲线下准确率-召回区域
还有其他不太广泛使用的排名指标,例如针对不平衡分类和成本曲线修改 ROC 曲线。
有关不平衡分类的 ROC 曲线和准确率-召回曲线的更多信息,请参见教程:
不平衡分类的概率度量
概率度量是专门为量化分类器预测的不确定性而设计的。
对于我们对不正确和正确的班级预测不太感兴趣,而对模型在预测中的不确定性和惩罚那些错误但高度自信的预测更感兴趣的问题,这些是有用的。
基于对错误的概率理解的度量,即测量与真实概率的偏差[……]当我们想要评估分类器的可靠性时,这些度量特别有用,不仅测量它们何时失败,而且测量它们是否以高或低的概率选择了错误的类别。
——分类表现指标的实验比较,2008 年。
基于预测概率评估模型需要校准概率。
一些分类器使用概率框架来训练,例如最大似然估计,这意味着它们的概率已经被校准。逻辑回归就是一个例子。
许多非线性分类器不是在概率框架下训练的,因此在通过概率度量评估之前,需要对照数据集校准它们的概率。例子可能包括支持向量机和 k 近邻。
评估预测概率最常用的度量标准可能是二进制分类的对数损失(或负对数似然),或者更一般地称为交叉熵。
对于预期值为 y 而预测值为 yhat 的二进制类别数据集,可以通过以下方式计算:
- log loss=(1–y)* log(1–y hat)+y * log(y hat))
分数可以通过简单地添加术语来推广到多个类别;例如:
- log loss=-(C y _ C * log(yhat _ C)中的和 C)
分数总结了两个概率分布之间的平均差异。一个完美的分类器的对数损失为 0.0,更差的值为正直到无穷大。
预测概率的另一个流行分数是布瑞尔分数。
布瑞尔分数的好处是它集中在正类上,对于不平衡分类来说,正类就是少数类。这使得它比关注整个概率分布的对数损失更可取。
Brier 分数计算为正类的预期概率(例如 1.0)和预测概率之间的均方误差。回想一下,均方误差是值之间的平方差的平均值。
- brierscore= 1/n * I 与 n 之和(yhat _ I–y_i)²
完美的分类器的 Brier 评分为 0.0。尽管典型地用二进制分类任务来描述,布瑞尔分数也可以被计算用于多类分类问题。
不同分类器的 Brier 评分差异可能非常小。为了解决这个问题,可以对照参考分数来缩放分数,例如来自无技能分类器的分数(例如,预测训练数据集中正类的概率分布)。
使用参考分数,可以计算布瑞尔技能分数,即 BSS,其中 0.0 表示没有技能,比没有技能更差的结果为负,完美技能由值 1.0 表示。
- BrierSkillScore= 1 –( BrierScore/BrierScore _ ref)
尽管概率评分方法在平衡分类问题中很受欢迎,但在具有倾斜类分布的分类问题中使用得不太广泛。
有关不平衡分类的概率度量的更多信息,请参见教程:
如何选择评估指标
有大量的模型评估指标可供选择。
考虑到选择评估指标非常重要,并且有几十个甚至上百个指标可供选择,你应该怎么做?
学习模型的正确评估是模式识别中最重要的问题之一。
——分类表现指标的实验比较,2008 年。
也许最好的方法是与项目涉众交谈,弄清楚一个模型或一组预测的重要之处。然后选择几个看起来能抓住重要点的指标,然后用不同的场景测试这个指标。
一个场景可能是一个测试数据集的模拟预测集,它具有与您的问题域相匹配的倾斜类分布。如果一个模型预测了所有的多数类、所有的少数类、做得好、做得差等等,你可以测试这个度量发生了什么。一些小的测试可以快速帮助你了解这个指标的表现。
另一种方法可能是进行文献综述,并发现从事相同类型问题的其他从业者或学者最常用的度量标准。这通常很有见地,但要注意的是,一些研究领域可能会陷入群体思维,并采用一种可能非常适合大规模比较大量模型,但在实践中对模型选择来说很糟糕的度量标准。
还不知道?
以下是一些首要建议:
- 你在预测概率吗?
- 需要类标签吗?
- 正课更重要吗?
- 使用准确率-召回 AUC
- 两个班都重要吗?
- 使用 ROC AUC
- 正课更重要吗?
- 你需要概率吗?
- 使用简短分数和简短技能分数
- 需要类标签吗?
- 你在预测类标签吗?
- 正课更重要吗?
- 假阴性和假阳性同等重要吗?
- 使用 F1-测量
- 假阴性更重要吗?
- 使用 F2-测量
- 假阳性更重要吗?
- 使用 f 0.5-测量
- 假阴性和假阳性同等重要吗?
- 两个班都重要吗?
- 多数班有< 80%-90%的例子吗?
- 使用精确度
- 多数班有> 80%-90%的例子吗?
- 使用 G 均值
- 多数班有< 80%-90%的例子吗?
- 正课更重要吗?
这些建议将重要的情况考虑在内,我们可以使用预测概率的模型,但是需要清晰的类标签。这是一类重要的问题,允许操作者或实现者选择阈值来权衡错误分类错误。在这种情况下,需要考虑所有合理阈值的误差指标,因此需要使用曲线下面积指标。
我们可以将这些建议转化为有用的模板。
如何选择不平衡分类的度量
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 分类表现测量的实验比较,2008。
- 不平衡数据的分类:综述,2009。
- 不平衡分布下的预测建模综述,2015。
书
- 第八章不平衡学习的评估指标,不平衡学习:基础、算法和应用,2013。
- 第三章绩效衡量,从不平衡数据集学习,2018。
文章
摘要
在本教程中,您发现了可以用于不平衡分类的指标。
具体来说,您了解到:
- 关于选择用于分类的度量的挑战,以及当存在偏斜的类分布时如何特别困难。
- 如何评估分类器模型有三种主要的度量,称为等级、阈值和概率。
- 如果你不知道从哪里开始,如何选择不平衡分类的度量。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
不平衡分类的欠采样算法
最后更新于 2021 年 1 月 27 日
重采样方法旨在改变不平衡分类任务的训练数据集的组成。
不平衡分类的重采样方法大多关注对少数类的过采样。然而,已经开发了一套对多数类进行欠采样的技术,可以与有效的过采样方法结合使用。
有许多不同类型的欠采样技术,尽管大多数可以分为选择要保留在转换数据集中的示例、选择要删除的示例以及组合这两种方法的混合。
在本教程中,您将发现不平衡分类的欠采样方法。
完成本教程后,您将知道:
- 如何使用“未遂事件”和“压缩最近邻规则”方法来选择不属于多数类的示例。
- 如何使用 Tomek 链接和编辑的最近邻规则方法从多数类中选择要删除的示例。
- 如何使用“单侧选择”和“邻域清理规则”,这两个规则结合了从多数类中保留和删除示例的选择方法。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2021 年 1 月更新:更新了 API 文档的链接。
如何使用欠采样算法进行不平衡分类 图片由诺根提供,保留部分权利。
教程概述
本教程分为五个部分;它们是:
- 不平衡分类的欠采样
- 不平衡学习库
- 选择要保留的示例的方法
- 差点采样不足
- 欠采样的压缩最近邻规则
- 选择要删除的示例的方法
- 用于欠采样的 Tomek 链接
- 欠采样的编辑最近邻规则
- 保留和删除方法的组合
- 欠采样的单侧选择
- 欠采样的邻域清理规则
不平衡分类的欠采样
欠采样是指一组技术,旨在平衡具有倾斜类分布的类别数据集的类分布。
不平衡的类分布会有一个或多个例子很少的类(少数类)和一个或多个例子很多的类(多数类)。最好在二进制(两类)分类问题的上下文中理解,其中类 0 是多数类,类 1 是少数类。
欠采样技术从训练数据集中移除属于多数类的示例,以便更好地平衡类分布,例如将偏斜从 1:100 减少到 1:10、1:2,甚至 1:1 类分布。这与过采样不同,过采样包括向少数类添加示例,以减少类分布的偏差。
…欠采样,包括通过消除属于多数类的示例来减少数据,目的是均衡每个类的示例数量…
—第 82 页,从不平衡数据集中学习,2018。
欠采样方法可以直接用于训练数据集,然后再用于拟合机器学习模型。通常,欠采样方法与少数类的过采样技术结合使用,这种组合通常比在训练数据集上单独使用过采样或欠采样带来更好的表现。
最简单的欠采样技术包括从多数类中随机选择示例,并将其从训练数据集中删除。这被称为随机欠采样。虽然简单而有效,但这种技术的一个限制是,在确定类之间的决策边界时,示例被移除,而不考虑它们可能有多有用或多重要。这意味着有用的信息有可能被删除。
随机欠采样的主要缺点是,这种方法可能会丢弃对归纳过程可能很重要的潜在有用数据。数据的移除是一个关键的决策,因此许多欠采样的建议使用启发式来克服非启发式决策的局限性。
—第 83 页,从不平衡数据集中学习,2018。
这种方法的一个扩展是更好地识别被删除的多数类的例子。这通常涉及试探法或学习模型,试图识别冗余的删除示例或有用的未删除示例。
有许多欠采样技术使用这些类型的试探法。在接下来的部分中,我们将回顾一些更常见的方法,并为它们在合成不平衡二进制类别数据集上的操作开发直觉。
我们可以使用 Sklearn 库中的 make_classification()函数定义一个合成的二进制类别数据集。例如,我们可以创建 10,000 个具有两个输入变量和 1:100 分布的示例,如下所示:
...
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
然后,我们可以通过散点图()Matplotlib 函数创建数据集的散点图,以了解每个类中示例的空间关系及其不平衡。
...
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
将这些联系在一起,下面列出了创建不平衡类别数据集并绘制示例的完整示例。
# Generate and plot a synthetic imbalanced classification dataset
from collections import Counter
from sklearn.datasets import make_classification
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例首先总结了类分布,显示了大约 1:100 的类分布,其中大约 10,000 个示例包含类 0,100 个示例包含类 1。
Counter({0: 9900, 1: 100})
接下来,创建散点图,显示数据集中的所有示例。我们可以看到大量 0 类(蓝色)的例子和少量 1 类(橙色)的例子。我们还可以看到,在属于类 0 的特征空间部分中,类与类 1 中的一些示例明显重叠。
不平衡类别数据集的散点图
这个图提供了发展直觉的起点,即不同的欠采样技术对多数类的影响。
接下来,我们可以开始回顾通过不平衡学习 Python 库提供的流行欠采样方法。
有许多不同的方法可供选择。我们将把它们分成从多数类中选择要保留的示例的方法、选择要删除的示例的方法以及两种方法的组合。
不平衡学习库
在这些例子中,我们将使用不平衡学习 Python 库提供的实现,可以通过 pip 安装如下:
sudo pip install imbalanced-learn
您可以通过打印已安装库的版本来确认安装成功:
# check version number
import imblearn
print(imblearn.__version__)
运行该示例将打印已安装库的版本号;例如:
0.5.0
选择要保留的示例的方法
在本节中,我们将仔细研究两种方法,这两种方法从多数类中选择要保留的示例,即方法的未遂家族和流行的压缩最近邻规则。
差点采样不足
Miss 指的是欠采样方法的集合,这些方法根据多数类示例到少数类示例的距离来选择示例。
这些方法是由张建平和 Inderjeet Mani 在他们 2003 年发表的题为“不平衡数据分布的 KNN 方法:涉及信息提取的案例研究”的论文中提出的
该技术有三个版本,分别名为“接近缺失-1”、“接近缺失-2”和“接近缺失-3”。
NearMiss-1 从多数类中选择与少数类中三个最接近的示例具有最小平均距离的示例。 NearMiss-2 从多数类中选择与少数类最远的三个示例之间平均距离最小的示例。 NearMiss-3 包括为少数民族中的每个例子选择给定数量的多数民族例子。
这里,使用欧几里德距离等在特征空间中确定距离。
- NearMiss-1 :与三个最接近的少数类示例平均距离最小的多数类示例。
- NearMiss-2 :多数类示例与三个最远的少数类示例之间的平均距离最小。
- NearMiss-3 :多数类示例,与每个少数类示例的距离最小。
NearMiss-3 似乎是可取的,因为它将只保留决策边界上的那些多数类示例。
我们可以使用接近缺失不平衡学习类来实现接近缺失方法。
所使用的接近未命中策略的类型由“版本”参数定义,默认情况下,该参数对于接近未命中-1 设置为 1,但是对于其他两种方法可以设置为 2 或 3。
...
# define the undersampling method
undersample = NearMiss(version=1)
默认情况下,该技术将对多数类进行欠采样,使其具有与少数类相同数量的示例,尽管这可以通过将 sampling_strategy 参数设置为少数类的一小部分来更改。
首先,我们可以演示 NearMiss-1,它只选择那些与三个少数类实例具有最小距离的多数类实例,由 n_neighbors 参数定义。
我们期望多数类例子围绕重叠的少数类例子。
下面列出了完整的示例。
# Undersample imbalanced dataset with NearMiss-1
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import NearMiss
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# define the undersampling method
undersample = NearMiss(version=1, n_neighbors=3)
# transform the dataset
X, y = undersample.fit_resample(X, y)
# summarize the new class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例对多数类进行欠采样,并创建转换后数据集的散点图。
我们可以看到,正如预期的那样,只有在重叠区域中最接近少数类示例的多数类中的那些示例被保留。
接近 Miss-1 的欠采样不平衡数据集散点图
接下来,我们可以演示接近缺失-2 策略,它与接近缺失-1 相反。它从少数民族类中选择最接近最遥远的例子,由 n_neighbors 参数定义。
单从描述来看,这并不是一个直观的策略。
下面列出了完整的示例。
# Undersample imbalanced dataset with NearMiss-2
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import NearMiss
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# define the undersampling method
undersample = NearMiss(version=2, n_neighbors=3)
# transform the dataset
X, y = undersample.fit_resample(X, y)
# summarize the new class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例,我们可以看到 NearMiss-2 选择看起来位于两个类重叠的质心的示例。
接近 Miss-2 的欠采样不平衡数据集散点图
最后,我们可以尝试 NearMiss-3,它从多数类中为每个少数类选择最接近的例子。
n_neighbors_ver3 参数确定了每个少数民族示例要选择的示例数量,尽管通过采样策略设置的所需平衡比率将对此进行过滤,从而实现所需的平衡。
下面列出了完整的示例。
# Undersample imbalanced dataset with NearMiss-3
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import NearMiss
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# define the undersampling method
undersample = NearMiss(version=3, n_neighbors_ver3=3)
# transform the dataset
X, y = undersample.fit_resample(X, y)
# summarize the new class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
不出所料,我们可以看到,少数族裔中与多数族裔重叠的每个例子都有最多三个来自多数族裔的邻居。
接近 Miss-3 的欠采样不平衡数据集散点图
压缩最近邻规则欠采样
压缩最近邻(简称 CNN)是一种欠采样技术,它寻找样本集合中不会导致模型表现损失的子集,称为最小一致集。
…样本集一致子集的概念。这是一个子集,当用作神经网络规则的存储参考集时,可以正确分类样本集中的所有剩余点。
— 压缩最近邻规则(Corresp。),1968 年。
这是通过枚举数据集中的示例并将其添加到“*存储”*中来实现的,前提是它们不能被存储的当前内容正确分类。彼得·哈特在 1968 年题为“压缩最近邻规则的通信中提出了这种方法,以减少 k 最近邻(KNN)算法的内存需求
当用于不平衡分类时,存储由少数集合中的所有示例组成,并且只有多数集合中不能正确分类的示例被递增地添加到存储中。
我们可以使用不平衡学习库中的condensednearestneighbor 类来实现欠采样的压缩最近邻。
在此过程中,KNN 算法用于对点进行分类,以确定它们是否要添加到商店中。k 值通过 n_neighbors 参数设置,默认为 1。
...
# define the undersampling method
undersample = CondensedNearestNeighbour(n_neighbors=1)
这是一个相对较慢的过程,所以小数据集和小 k 值是首选。
下面列出了演示欠采样的压缩最近邻规则的完整示例。
# Undersample and plot imbalanced dataset with the Condensed Nearest Neighbor Rule
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import CondensedNearestNeighbour
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# define the undersampling method
undersample = CondensedNearestNeighbour(n_neighbors=1)
# transform the dataset
X, y = undersample.fit_resample(X, y)
# summarize the new class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例首先报告原始数据集的偏斜分布,然后报告转换后数据集的更平衡的分布。
我们可以看到,最终的分布是少数与多数的比例大约为 1:2。这强调了尽管 sampling_strategy 参数试图平衡类分布,但算法将继续向存储(转换后的数据集)添加错误分类的示例。这是一个理想的属性。
Counter({0: 9900, 1: 100})
Counter({0: 188, 1: 100})
将创建结果数据集的散点图。我们可以看到,算法的重点是沿着两个类之间的决策边界的少数类中的那些例子,具体来说,是围绕少数类例子的那些多数例子。
基于压缩最近邻规则的欠采样不平衡数据集散点图
选择要删除的示例的方法
在本节中,我们将仔细研究从多数类中选择要删除的示例的方法,包括流行的 Tomek Links 方法和编辑最近邻居规则。
用于欠采样的 Tomek 链接
对压缩最近邻规则的批评是,示例是随机选择的,尤其是最初。
这样做的效果是允许多余的例子进入商店,并且允许分布质量内部的例子进入商店,而不是在类边界上。
压缩最近邻法随机选择样本。这导致 a)保留不必要的样品和 b)偶尔保留内部样品而不是边界样品。
——CNN的两次修改,1976 年。
伊万·托梅克在他 1976 年的论文《美国有线电视新闻网的两次修改》中提出了对美国有线电视新闻网程序的两次修改其中一个修改(Method2)是找到成对例子的规则,每个类一个例子;它们在特征空间中彼此之间的欧氏距离最小。
这意味着,在类别为 0 和 1 的二进制分类问题中,每一对都有一个来自每个类别的示例,并且是数据集上最接近的邻居。
换句话说,如果(I)实例 a 的最近邻居是 b,(ii)实例 b 的最近邻居是 a,以及(iii)实例 a 和 b 属于不同的类,则实例 a 和 b 定义了 Tomek Link。
—第 46 页,不平衡学习:基础、算法和应用,2013。
这些跨类对现在通常被称为“ Tomek Links ”,并且在定义类边界时很有价值。
方法 2 还有另一个潜在的重要特性:它找到参与(分段线性)边界形成的成对边界点。[……]这种方法可以使用这些对来逐步产生对原始完全指定边界的可接受的精确近似的更简单的描述。
——CNN的两次修改,1976 年。
查找 Tomek 链接的过程可用于定位所有跨类最近邻居。如果少数类中的示例保持不变,则该过程可用于查找多数类中最接近少数类的所有示例,然后将其移除。这些都是模棱两可的例子。
从这个定义中,我们可以看到在 Tomek Links 中的实例要么是边界实例,要么是有噪声的实例。这是因为只有边界实例和有噪声的实例才会有来自相反类的最近邻居。
—第 46 页,不平衡学习:基础、算法和应用,2013。
我们可以使用TomeLinks 不平衡学习类实现 Tomek Links 欠采样方法。
...
# define the undersampling method
undersample = TomekLinks()
下面列出了演示欠采样的 Tomek 链接的完整示例。
因为该过程只移除所谓的“ Tomek Links ”,所以我们不会期望得到的转换数据集是平衡的,只是沿着类边界不那么模糊。
# Undersample and plot imbalanced dataset with Tomek Links
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import TomekLinks
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# define the undersampling method
undersample = TomekLinks()
# transform the dataset
X, y = undersample.fit_resample(X, y)
# summarize the new class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例首先总结原始数据集的类分布,然后总结转换后的数据集。
我们可以看到,只有 26 个来自多数派的例子被删除。
Counter({0: 9900, 1: 100})
Counter({0: 9874, 1: 100})
转换后数据集的散点图不会使多数类的次要编辑变得明显。
这突出表明,虽然在类边界上找到模糊的例子是有用的,但是单独来看,这并不是一个很好的欠采样技术。在实践中,Tomek Links 过程经常与其他方法结合使用,例如压缩最近邻规则。
选择将 Tomek Links 和 CNN 合并是很自然的,因为 Tomek Links 可以说是去除了边界线和嘈杂的实例,而 CNN 则去除了冗余的实例。
—第 46 页,不平衡学习:基础、算法和应用,2013。
托梅克链接法欠采样不平衡数据集的散点图
欠采样的编辑最近邻规则
另一个在数据集中寻找模糊和有噪声的例子的规则叫做编辑最近邻,有时简称为 ENN。
该规则包括使用 k=3 最近邻来定位数据集中那些被错误分类的示例,然后在应用 k=1 分类规则之前将其移除。Dennis Wilson 在 1972 年发表的题为“使用编辑数据的最近邻规则的渐近性质”的论文中提出了这种重采样和分类方法
改进的三近邻规则是一个特别有吸引力的规则,它使用三近邻规则编辑预分类样本,然后使用单近邻规则进行决策。
——使用编辑数据的最近邻规则的渐近性质,1972。
当用作欠采样过程时,该规则可以应用于多数类中的每个示例,允许那些被错误分类为属于少数类的示例被移除,而那些被正确分类的示例被保留。
它也适用于少数类中的每个示例,其中那些被错误分类的示例删除了它们在多数类中的最近邻居。
…对于数据集中的每个实例 a,计算其三个最近的邻居。如果是多数类实例,并且被其三个最近的邻居错误分类,则从数据集中移除。或者,如果是少数类实例,并且被其三个最近的邻居错误分类,则移除 a 的邻居中的多数类实例。
—第 46 页,不平衡学习:基础、算法和应用,2013。
编辑最近邻规则可以使用编辑最近邻不平衡学习类来实现。
n_neighbors 参数控制编辑规则中使用的邻居数量,默认为三个,如本文中所示。
...
# define the undersampling method
undersample = EditedNearestNeighbours(n_neighbors=3)
下面列出了演示欠采样 ENN 规则的完整示例。
像 Tomek Links 一样,该过程只移除类边界上有噪声和不明确的点。因此,我们不会期望得到的转换数据集是平衡的。
# Undersample and plot imbalanced dataset with the Edited Nearest Neighbor rule
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import EditedNearestNeighbours
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# define the undersampling method
undersample = EditedNearestNeighbours(n_neighbors=3)
# transform the dataset
X, y = undersample.fit_resample(X, y)
# summarize the new class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例首先总结原始数据集的类分布,然后总结转换后的数据集。
我们可以看到,多数派中只有 94 个例子被删除。
Counter({0: 9900, 1: 100})
Counter({0: 9806, 1: 100})
考虑到执行的少量欠采样,从图中看,大多数示例的质量变化并不明显。
此外,像 Tomek Links 一样,当与另一种欠采样方法结合使用时,编辑最近邻规则会给出最佳结果。
使用编辑最近邻规则欠采样的不平衡数据集散点图
Tomek Links 的开发者 Ivan Tomek 在他 1976 年的论文《T0:编辑最近邻规则的实验》中探索了编辑最近邻规则的扩展
在他的实验中,有一种重复的 ENN 方法,该方法使用 ENN 规则对数据集进行固定次数的连续编辑,称为“无限编辑”
……无限重复威尔逊的编辑(事实上,编辑总是在有限的步骤后停止,因为在一定次数的重复后,设计集变得不受进一步消除的影响)
——编辑最近邻规则的实验,1976 年。
他还描述了一种称为“所有 k-NN ”的方法,该方法从数据集中删除了所有分类不正确的示例。
这两个额外的编辑程序也可以通过不平衡学习库通过重复编辑最近邻居和所有的类获得。
保留和删除方法的组合
在本节中,我们将更仔细地研究结合我们已经研究过的技术来保留和删除多数类中的示例的技术,例如单侧选择和邻域清理规则。
欠采样的单侧选择
单边选择,简称 OSS,是一种欠采样技术,结合了 Tomek Links 和压缩最近邻规则(CNN)。
具体来说,Tomek 链接是类边界上的模糊点,在多数类中被识别和移除。然后,使用 CNN 方法从远离决策边界的多数类中移除冗余示例。
开放源码软件是一种欠采样方法,是在应用美国有线电视新闻网之后应用托梅克链接的结果。Tomek 链接被用作欠采样方法,并删除有噪声和边缘的多数类示例。[……]美国有线电视新闻网旨在从远离决策边界的多数阶级中删除例子。
—第 84 页,从不平衡数据集中学习,2018。
这种方法的组合是由米罗斯拉夫·库巴特和斯坦·马特温在他们 1997 年的论文《解决不平衡训练集的诅咒:单边选择》中提出的
美国有线电视新闻网程序一步到位,包括首先将所有少数类示例添加到商店和一些多数类示例(例如 1),然后用 KNN ( k=1 )对所有剩余的多数类示例进行分类,并将那些错误分类的示例添加到商店。
欠采样程序的单侧选择概述 摘自《解决不平衡训练集的诅咒:单侧选择》。
我们可以通过one ided selection 不平衡学习类实现 OSS 欠采样策略。
种子示例的数量可以通过 n_seeds_S 设置,默认为 1,KNN 的 k 可以通过 n_neighbors 参数设置,默认为 1。
考虑到 CNN 过程发生在一个块中,为了有效地去除冗余的例子,具有更大的多数类的种子样本更有用。在这种情况下,我们将使用值 200。
...
# define the undersampling method
undersample = OneSidedSelection(n_neighbors=1, n_seeds_S=200)
下面列出了在二分类问题上应用开放源码软件的完整例子。
我们可能期望从分布的内部(例如,远离类边界)移除多数类的大量冗余示例。
# Undersample and plot imbalanced dataset with One-Sided Selection
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import OneSidedSelection
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# define the undersampling method
undersample = OneSidedSelection(n_neighbors=1, n_seeds_S=200)
# transform the dataset
X, y = undersample.fit_resample(X, y)
# summarize the new class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例首先报告原始数据集中的类分布,然后报告转换后的数据集。
我们可以看到,多数类中的大量示例被移除,包括冗余示例(通过 CNN 移除)和模糊示例(通过 Tomek Links 移除)。该数据集的比率现在约为 1:10。从 1:100 开始下降。
Counter({0: 9900, 1: 100})
Counter({0: 940, 1: 100})
创建转换数据集的散点图,显示大部分剩余的多数类示例属于类边界周围,而重叠的示例来自少数类。
探索来自多数类的更大的种子样本和在一步 CNN 程序中使用的 k 的不同值可能是有趣的。
单侧选择欠采样不平衡数据集的散点图
欠采样的邻域清理规则
邻域清理规则(简称 NCR)是一种欠采样技术,它结合了压缩最近邻(CNN)规则来移除冗余示例,以及编辑最近邻(ENN)规则来移除有噪声或不明确的示例。
像单侧选择(OSS)一样,CSS 方法以一步的方式应用,然后根据 ENN 规则,根据 KNN 分类器错误分类的例子被移除。与开放源码软件不同,删除的冗余例子更少,更多的注意力放在清理保留的例子上。
这样做的原因是不太注重改善班级分布的平衡,而更多地关注保留在大多数班级中的例子的质量(不模糊性)。
…分类结果的质量不一定取决于班级的规模。因此,除了类别分布之外,我们还应该考虑其他可能妨碍分类的数据特征,如噪声。
——通过平衡班级分布提高困难小班的识别,2001。
这种方法是由 Jorma Laurikkala 在她 2001 年的论文中提出的,该论文的标题是“通过平衡班级分布来改进困难小班的识别”
该方法包括首先从少数民族中选择所有的例子。然后,使用 ENN 规则识别并移除多数类中的所有模糊示例。最后,使用 CNN 的一步式版本,在该版本中,根据商店错误分类的多数类中的剩余示例将被删除,但前提是多数类中的示例数量大于少数类的一半。
邻域清理规则算法综述。 取自平衡班级分布提高困难小班识别。
这种技术可以使用邻居清理规则不平衡学习类来实现。ENN 和美国有线电视新闻网步骤中使用的邻居数量可以通过默认为 3 的 n_neighbors 参数来指定。阈值清理控制 CNN 是否应用于给定的类,如果有多个相似大小的少数民族类,这可能会很有用。这个保持在 0.5。
下面列出了将 NCR 应用于二分类问题的完整示例。
考虑到数据清理比删除冗余示例更为重要,我们预计多数类中的示例数量只会适度减少。
# Undersample and plot imbalanced dataset with the neighborhood cleaning rule
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import NeighbourhoodCleaningRule
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99], flip_y=0, random_state=1)
# summarize class distribution
counter = Counter(y)
print(counter)
# define the undersampling method
undersample = NeighbourhoodCleaningRule(n_neighbors=3, threshold_cleaning=0.5)
# transform the dataset
X, y = undersample.fit_resample(X, y)
# summarize the new class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例首先报告原始数据集中的类分布,然后报告转换后的数据集。
我们可以看到,只有 114 个来自多数派的例子被删除。
Counter({0: 9900, 1: 100})
Counter({0: 9786, 1: 100})
鉴于执行的欠采样数量有限且集中,从创建的散点图来看,大多数示例的质量变化并不明显。
基于邻域清理规则的欠采样不平衡数据集散点图
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 不平衡数据分布的 kNN 方法:涉及信息提取的案例研究,2003。
- 压缩最近邻规则(Corresp。),1968 年
- CNN的两次修改,1976 年。
- 解决不平衡训练集的诅咒:片面选择,1997。
- 使用编辑数据的最近邻规则的渐近性质,1972。
- 编辑最近邻规则的实验,1976 年。
- 平衡班级分布提高困难小班识别,2001。
书
- 从不平衡数据集中学习,2018。
- 不平衡学习:基础、算法和应用,2013。
应用程序接口
- 欠采样、不平衡学习用户指南。
- imblearn.under_sampling。近错过原料药
- imblearn.under_sampling。condensednearstneighbor API
- imblearn.under_sampling。托莫克林斯原料药
- imblearn.under_sampling。one idedselection API
- imblearn.under_sampling。编辑最近邻居应用编程接口。
- imblearn.under_sampling。邻里清洁规则应用编程接口
文章
摘要
在本教程中,您发现了不平衡分类的欠采样方法。
具体来说,您了解到:
- 如何使用“未遂事件”和“压缩最近邻规则”方法来选择不属于多数类的示例。
- 如何使用 Tomek 链接和编辑的最近邻规则方法从多数类中选择要删除的示例。
- 如何使用“单侧选择”和“邻域清理规则”,这两个规则结合了从多数类中保留和删除示例的选择方法。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
不平衡分类的温和介绍
最后更新于 2020 年 1 月 14 日
分类预测建模包括预测给定观察的类别标签。
不平衡分类问题是分类问题的一个例子,其中已知类中的例子分布是有偏差的。这种分布可以从轻微的偏差到严重的不平衡不等,少数群体中有一个例子,多数群体中有成百上千甚至上百万个例子。
不平衡分类对预测建模提出了挑战,因为大多数用于分类的机器学习算法都是围绕每个类具有相同数量的示例的假设而设计的。这导致模型的预测表现很差,特别是对于少数群体。这是一个问题,因为通常情况下,少数类更重要,因此该问题对少数类的分类错误比多数类更敏感。
在本教程中,您将发现不平衡分类预测建模。
完成本教程后,您将知道:
- 不平衡分类是当训练数据集中的类分布不均匀时的分类问题。
- 班级分布的不平衡可能会有所不同,但严重的不平衡对建模来说更具挑战性,可能需要专门的技术。
- 许多真实世界的分类问题具有不平衡的类别分布,例如欺诈检测、垃圾邮件检测和流失预测。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
不平衡分类的温和介绍约翰·梅森摄,版权所有。
教程概述
本教程分为五个部分;它们是:
- 分类预测建模
- 不平衡分类问题
- 阶层失衡的原因
- 不平衡分类的挑战
- 不平衡分类的例子
分类预测建模
分类是一个预测性建模问题,包括给每个观察分配一个类别标签。
……分类模型生成一个预测类,它以离散类别的形式出现。对于大多数实际应用,需要离散的类别预测来做出决定。
—第 248 页,应用预测建模,2013 年。
每个示例都由观察值和类标签组成。
- 示例:来自域(输入)的观察和关联的类标签(输出)。
例如,我们可以收集一朵花的测量值,并根据测量值对花的种类进行分类(标记为)。预测建模问题的类的数量通常在问题被框定或描述时是固定的,并且通常类的数量不会改变。
我们可以选择预测类成员的概率,而不是简单的类标签。
这允许预测模型在一系列选项中共享预测的不确定性,并允许用户在问题的上下文中解释结果。
像回归模型一样,分类模型产生连续值预测,其通常以概率的形式出现(即,任何单个样本的类别成员的预测值在 0 和 1 之间,总和为 1)。
—第 248 页,应用预测建模,2013 年。
例如,给定一朵花的测量值(观测值),我们可以预测该花作为 20 种不同花中每一种的例子的可能性(概率)。
预测建模问题的类的数量通常在问题被框定或描述时是固定的,并且通常类的数量不会改变。
分类预测建模问题可能有两个类别标签。这是最简单的分类问题,被称为二分类或二分类。或者,问题可能有两个以上的类,例如三个、十个甚至数百个类。这些类型的问题被称为多类分类问题。
- 二分类问题:分类预测建模问题,其中所有的例子都属于两类中的一类。
- 多类分类问题:一个分类预测建模问题,其中所有的例子都属于三类中的一类。
当处理分类预测建模问题时,我们必须收集训练数据集。
训练数据集是来自域的多个例子,包括输入数据(例如测量)和输出数据(例如类别标签)。
- 训练数据集:从问题域中收集的大量示例,包括输入观察和输出类标签。
根据问题的复杂性和我们可能选择使用的模型类型,我们可能需要域中的几十个、几百个、几千个甚至几百万个示例来构成训练数据集。
训练数据集用于更好地理解输入数据,以帮助为建模做好最好的准备。它还用于评估一套不同的建模算法。它用于调整所选模型的超参数。最后,训练数据集用于在所有可用数据上训练最终模型,我们可以在未来使用该模型对问题领域的新示例进行预测。
现在我们已经熟悉了分类预测建模,让我们考虑一下训练数据集中类的不平衡。
不平衡分类问题
属于每个类的例子的数量可以被称为类分布。
不平衡分类是指分类预测建模问题,其中每个类别标签的训练数据集中的示例数量是不平衡的。
也就是说,阶级分布不相等或接近相等,而是有偏差或偏斜的。
- 不平衡分类:分类预测建模问题,其中样本在类之间的分布不相等。
例如,我们可以收集花卉的测量值,并且有一个花卉物种的 80 个例子和第二个花卉物种的 20 个例子,并且只有这些例子构成我们的训练数据集。这是不平衡分类问题的一个例子。
当一个或多个类在训练数据中的比例与其他类相比非常低时,就会出现不平衡。
—第 419 页,应用预测建模,2013 年。
我们把这些类型的问题称为“T0”不平衡分类,而不是“T2”不平衡分类。不平衡是指曾经是平衡的,现在不再平衡的阶级分布,而不平衡是指本来就不平衡的阶级分布。
还有其他不太通用的名称可以用来描述这些类型的分类问题,例如:
- 罕见事件预测。
- 极端事件预测。
- 严重的阶级不平衡。
问题的不平衡由特定训练数据集中的类分布来定义。
…必须针对特定的数据集或分布定义类别不平衡。因为需要类别标签来确定类别不平衡的程度,所以类别不平衡通常是相对于训练分布来衡量的。
—第 16 页,不平衡学习:基础、算法和应用,2013。
用比率来描述数据集中类的不平衡是很常见的。
例如,不平衡度为 1 到 100 (1:100)的不平衡二进制分类问题意味着一个类中的每一个例子,另一个类中就有 100 个例子。
描述数据集中类不平衡的另一种方法是将类分布总结为训练数据集的百分比。例如,一个不平衡的多类分类问题可能有 80%的例子在第一类中,18%在第二类中,2%在第三类中。
现在我们已经熟悉了不平衡分类问题的定义,让我们看看为什么类可能不平衡的一些可能原因。
阶层失衡的原因
不平衡分类预测建模问题中类分布的不平衡可能有许多原因。
对于这种不平衡,我们可能要考虑两大类原因;它们是数据采样和域的属性。
不同类别的示例之间的不平衡可能是由从问题域中收集或采样示例的方式造成的。这可能涉及数据收集过程中引入的偏差,以及数据收集过程中出现的错误。
- 有偏采样。
- 测量误差。
例如,也许例子是从一个狭窄的地理区域或一段时间收集的,班级的分布可能有很大不同,甚至可能以不同的方式收集。
收集观察结果时可能会出错。一种类型的错误可能是在许多示例中应用了错误的类标签。或者,从其中收集示例的过程或系统可能已经被损坏或削弱,从而导致不平衡。
通常,在不平衡由采样偏差或测量误差引起的情况下,可以通过改进的采样方法和/或校正测量误差来校正不平衡。这是因为训练数据集不能公平地表示正在处理的问题领域。
不平衡可能是问题域的一个属性。
例如,一个类的自然出现或存在可能支配其他类。这可能是因为在一个类中生成观察值的过程在时间、成本、计算或其他资源上更昂贵。因此,简单地从域中收集更多的样本来改善类分布通常是不可行或难以处理的。相反,需要一个模型来了解类之间的区别。
现在我们已经熟悉了类不平衡的可能原因,让我们考虑一下为什么不平衡的分类问题具有挑战性。
不平衡分类的挑战
阶级分布的不平衡会因问题而异。
一个分类问题可能会有点歪斜,比如说是不是有轻微的不平衡。或者,对于给定的训练数据集,分类问题可能具有严重的不平衡,其中一个类中可能有数百或数千个示例,而另一个类中可能有数十个示例。
- 轻微不平衡。一种不平衡的分类问题,其中训练数据集中的少量样本(例如 4:6)的分布是不均匀的。
- 严重失衡。一种不平衡的分类问题,其中示例的分布在训练数据集中是不均匀的(例如 1:100 或更多)。
当代作品中的阶级不平衡大多集中在 1:4 到 1:100 的不平衡比例上。[……]在实际应用中,如欺诈检测或化学信息学,我们可能会处理比例从 1:1000 到 1:5000 不等的不平衡问题。
——从不平衡的数据中学习——开放的挑战和未来的方向,2016。
轻微的不平衡通常不是问题,这个问题通常可以像正常的分类预测建模问题一样处理。课程的严重不平衡可能对建模具有挑战性,并且可能需要使用专门的技术。
任何具有不等类分布的数据集在技术上都是不平衡的。然而,当每一类问题的例子数量明显不均衡时,或者在某些极端情况下,数据集就被认为是不平衡的。
—第 19 页,从不平衡数据集中学习,2018。
实例丰富的类称为主要类或多数类,而实例较少的类(通常只有一个)称为次要类或少数类。
- 多数类:有很多例子的不平衡分类预测建模问题中的类(或多个类)。
- 少数类:不平衡分类预测建模问题中的类,很少有例子。
当处理不平衡分类问题时,少数类通常是最感兴趣的。这意味着模型正确预测少数类的类标签或概率的技能比多数类更重要。
从不平衡数据中学习的发展主要是由许多现实生活中的应用程序推动的,在这些应用程序中,我们面临着数据表示不均匀的问题。在这种情况下,少数民族通常是更重要的一类,因此我们需要提高其识别率的方法。
——从不平衡的数据中学习——开放的挑战和未来的方向,2016。
少数族裔更难预测,因为根据定义,这类人的例子很少。这意味着模型从这个类中学习例子的特征,以及将这个类的例子与多数类(或多个类)区分开,更具挑战性。
来自多数阶级(或多个阶级)的大量例子会淹没少数阶级。大多数用于分类预测模型的机器学习算法是在假设类分布相等的问题上设计和演示的。这意味着一个模型的天真应用可能只关注于学习大量观察结果的特征,而忽略了少数群体的例子,事实上,他们更感兴趣,他们的预测更有价值。
……大多数分类算法的学习过程往往偏向于多数类示例,因此少数类示例无法很好地建模到最终系统中。
—第七页,从不平衡数据集中学习,2018。
不平衡分类不是解决的
它通常仍然是一个未解决的问题,实际上必须针对每个训练数据集进行识别和解决。
即使面对更多的数据也是如此,所谓的“大数据”、“大型神经网络模型,所谓的“深度学习”以及非常令人印象深刻的竞争制胜模型,所谓的“xboost”
尽管在过去的 20 年里对不平衡学习进行了大量的研究,但是在现有的方法中仍然有许多缺点和问题需要解决。
——从不平衡的数据中学习——开放的挑战和未来的方向,2016。
现在我们已经熟悉了不平衡分类的挑战,让我们看看一些常见的例子。
不平衡分类的例子
我们在实践中感兴趣解决的许多分类预测建模问题是不平衡的。
因此,不平衡分类没有得到比它更多的关注是令人惊讶的。
不平衡学习不仅给数据研究界带来了重大的新挑战,也在现实世界的数据密集型应用中提出了许多关键问题,从金融和生物医学数据分析等民用应用到监视和军事数据分析等安全和国防相关应用。
—第 2 页,不平衡学习:基础、算法和应用,2013。
下面是十个问题域的例子列表,其中例子的类分布本质上是不平衡的。
很多分类问题可能会出现班级分布严重失衡;然而,观察固有不平衡的常见问题领域将使阶级不平衡的想法和挑战具体化。
- 欺诈检测。
- 索赔预测
- 默认预测。
- 流失预测。
- 垃圾邮件检测。
- 异常检测。
- 异常值检测。
- 入侵检测
- 转换预测。
示例列表揭示了不平衡分类预测建模的本质。
这些问题领域中的每一个都代表了一个完整的研究领域,其中来自每个领域的具体问题都可以作为不平衡分类预测建模来构建和探索。这突出了类不平衡分类的多学科性质,以及为什么机器学习从业者意识到问题并熟练解决它如此重要。
不平衡可能出现在任何数据集或应用程序中,因此,从业者应该意识到建模这类数据的含义。
—第 419 页,应用预测建模,2013 年。
请注意,大多数(如果不是全部的话)示例可能是二分类问题。还要注意,少数民族的例子在某些方面是罕见的、极端的、不正常的或不寻常的。
还要注意的是,许多域被描述为“检测”,突出了在大量多数类的例子中发现少数类的愿望。
我们现在对不平衡分类预测建模有了一个稳健的概述。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
- 第十六章:严重阶级失衡的补救措施,应用预测建模,2013。
- 不平衡学习:基础、算法和应用,2013。
- 从不平衡数据集中学习,2018。
报纸
- 从不平衡的数据中学习——开放的挑战和未来的方向,2016。
文章
摘要
在本教程中,您发现了不平衡分类预测建模。
具体来说,您了解到:
- 不平衡分类是当训练数据集中的类分布不均匀时的分类问题。
- 班级分布的不平衡可能会有所不同,但严重的不平衡对建模来说更具挑战性,可能需要专门的技术。
- 许多真实世界的分类问题具有不平衡的类别分布,例如欺诈检测、垃圾邮件检测和流失预测。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何为不平衡分类配置 XGBoost
最后更新于 2020 年 8 月 21 日
XGBoost 算法对于广泛的回归和分类预测建模问题是有效的。
它是随机梯度提升算法的有效实现,并提供了一系列超参数,可对模型训练过程进行精细控制。尽管该算法总体上表现良好,即使在不平衡类别数据集上也是如此,但它提供了一种调整训练算法的方法,以更加关注具有倾斜类分布的数据集的少数类的误分类。
XGBoost 的这个修改版本被称为类加权 XGBoost 或成本敏感 XGBoost,并且可以在具有严重类不平衡的二进制分类问题上提供更好的表现。
在本教程中,您将发现用于不平衡分类的加权 XGBoost。
完成本教程后,您将知道:
- 梯度提升如何从高层次工作,以及如何开发一个用于分类的 XGBoost 模型。
- 如何修改 XGBoost 训练算法,以在训练过程中加权与正类重要性成比例的误差梯度。
- 如何为 XGBoost 训练算法配置正类权重,如何网格搜索不同的配置。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何配置不平衡分类的 xboost 图片由 flowcomm 提供,保留部分权利。
教程概述
本教程分为四个部分;它们是:
- 不平衡类别数据集
- 用于分类的 XGBoost 模型
- 类别不平衡的加权扩展
- 调整类别加权超参数
不平衡类别数据集
在我们深入到不平衡分类的 XGBoost 之前,让我们首先定义一个不平衡类别数据集。
我们可以使用make _ classification()sci kit-learn 函数定义一个合成的不平衡两类类别数据集。我们将生成 10,000 个少数与多数类比例大约为 1:100 的示例。
...
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=2, weights=[0.99], flip_y=0, random_state=7)
生成后,我们可以总结类分布,以确认数据集是按照我们的预期创建的。
...
# summarize class distribution
counter = Counter(y)
print(counter)
最后,我们可以创建示例的散点图,并按类别标签对它们进行着色,以帮助理解从该数据集中对示例进行分类的挑战。
...
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
将这些联系在一起,下面列出了生成合成数据集和绘制示例的完整示例。
# Generate and plot a synthetic imbalanced classification dataset
from collections import Counter
from sklearn.datasets import make_classification
from matplotlib import pyplot
from numpy import where
# define dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=2, weights=[0.99], flip_y=0, random_state=7)
# summarize class distribution
counter = Counter(y)
print(counter)
# scatter plot of examples by class label
for label, _ in counter.items():
row_ix = where(y == label)[0]
pyplot.scatter(X[row_ix, 0], X[row_ix, 1], label=str(label))
pyplot.legend()
pyplot.show()
运行该示例首先创建数据集并总结类分布。
我们可以看到,数据集具有大约 1:100 的类分布,多数类中的示例不到 10,000 个,少数类中的示例不到 100 个。
Counter({0: 9900, 1: 100})
接下来,创建数据集的散点图,显示多数类的大量示例(蓝色)和少数类的少量示例(橙色),并有一些适度的类重叠。
1 到 100 类不平衡的二进制类别数据集的散点图
用于分类的 XGBoost 模型
XGBoost 是极限梯度提升的简称,是随机梯度提升机学习算法的高效实现。
随机梯度提升算法,也称为梯度提升机或树增强,是一种强大的机器学习技术,在一系列具有挑战性的机器学习问题上表现良好,甚至最好。
树提升已经被证明在许多标准分类基准上给出了最先进的结果。
——xboost:一个可扩展的树提升系统,2016。
这是一个决策树算法的集合,其中新的树修复了那些已经是模型一部分的树的错误。树被添加,直到模型没有进一步的改进。
XGBoost 提供了随机梯度提升算法的高效实现,并提供了对一组模型超参数的访问,这些参数旨在提供对模型训练过程的控制。
XGBoost 成功背后最重要的因素是它在所有场景中的可扩展性。该系统在单台机器上的运行速度比现有的流行解决方案快十倍以上,并且在分布式或内存有限的环境中可扩展到数十亿个示例。
——xboost:一个可扩展的树提升系统,2016。
XGBoost 是一种有效的机器学习模型,即使在类分布有偏差的数据集上也是如此。
在对不平衡分类的 XGBoost 算法进行任何修改或调整之前,测试默认的 XGBoost 模型并建立表现基线是很重要的。
虽然 XGBoost 库有自己的 Python API,但是我们可以通过 XGBClassifier 包装类将 XGBoost 模型与 Sklearn API 一起使用。模型的一个实例可以像任何其他用于模型评估的 Sklearn 类一样被实例化和使用。例如:
...
# define model
model = XGBClassifier()
我们将使用重复交叉验证来评估模型,重复三次 10 倍交叉验证。
模型表现将使用重复和所有折叠的平均值曲线下的 ROC 面积 (ROC AUC)来报告。
...
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(model, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
# summarize performance
print('Mean ROC AUC: %.5f' % mean(scores))
将这些联系在一起,下面列出了在不平衡分类问题上定义和评估默认 XGBoost 模型的完整示例。
# fit xgboost on an imbalanced classification dataset
from numpy import mean
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from xgboost import XGBClassifier
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=2, weights=[0.99], flip_y=0, random_state=7)
# define model
model = XGBClassifier()
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(model, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
# summarize performance
print('Mean ROC AUC: %.5f' % mean(scores))
运行该示例会评估不平衡数据集上的默认 XGBoost 模型,并报告平均 ROC AUC。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
我们可以看到模型有技巧,实现了大于 0.5 的 ROC AUC,在这种情况下实现了 0.95724 的平均得分。
Mean ROC AUC: 0.95724
这为针对默认 XGBoost 算法执行的任何超参数调整提供了一个比较基准。
类别不平衡的加权扩展
尽管 XGBoost 算法在解决各种挑战性问题时表现良好,但它提供了大量超参数,其中许多参数需要进行调整,以便在给定的数据集上充分利用该算法。
该实现提供了一个超参数,用于针对不平衡分类问题调整算法的行为;这是刻度 _ pos _ 重量超参数。
默认情况下, scale_pos_weight 超参数设置为值 1.0,在提升决策树时,相对于负示例,具有权衡正示例的效果。对于不平衡的二进制类别数据集,负类指多数类(类 0),正类指少数类(类 1)。
XGBoost 被训练成最小化损失函数,梯度提升中的“梯度”指的是该损失函数的陡度,例如误差量。一个小的梯度意味着一个小的误差,反过来,一个修正误差的模型的小变化。训练期间的大误差梯度反过来导致大的校正。
- 小梯度:对模型的小误差或修正。
- 大梯度:对模型误差或修正较大。
梯度被用作拟合随后添加的树的基础,以增强或校正由决策树集合的现有状态产生的错误。
scale_pos_weight 值用于缩放正类的梯度。
这具有模型在正类训练期间产生的缩放误差的影响,并且鼓励模型过度校正它们。反过来,这可以帮助模型在对正类进行预测时获得更好的表现。推得太远,可能会导致模型过拟合正类,代价是负类或两个类的表现都变差。
因此, scale_pos_weight 可以用来训练一个类加权或成本敏感版本的 XGBoost 进行不平衡分类。
为 scale_pos_weight 超参数设置的合理默认值是类分布的倒数。例如,对于少数与多数类中示例比例为 1 比 100 的数据集, scale_pos_weight 可以设置为 100。这将使模型对少数类(正类)造成的分类错误产生 100 倍的影响,反过来,比多数类造成的错误产生 100 倍的修正。
例如:
...
# define model
model = XGBClassifier(scale_pos_weight=100)
XGBoost 文档提出了一种快速估计该值的方法,该方法使用训练数据集作为多数类中的示例总数除以少数类中的示例总数。
- scale _ pos _ weight = total _ 负值 _ 示例/total _ 正值 _ 示例
例如,我们可以为我们的合成类别数据集计算这个值。考虑到我们用来定义数据集的权重,我们预计该值约为 100,或者更准确地说,99。
...
# count examples in each class
counter = Counter(y)
# estimate scale_pos_weight value
estimate = counter[0] / counter[1]
print('Estimate: %.3f' % estimate)
下面列出了估计刻度 _ 位置 _ 重量 XGBoost 超参数值的完整示例。
# estimate a value for the scale_pos_weight xgboost hyperparameter
from sklearn.datasets import make_classification
from collections import Counter
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=2, weights=[0.99], flip_y=0, random_state=7)
# count examples in each class
counter = Counter(y)
# estimate scale_pos_weight value
estimate = counter[0] / counter[1]
print('Estimate: %.3f' % estimate)
运行该示例会创建数据集,并将 scale_pos_weight 超参数的值估计为 99,如我们所料。
Estimate: 99.000
我们将在 XGBoost 模型的配置中直接使用这个值,并使用重复的 k 倍交叉验证来评估它在数据集上的表现。
我们预计 ROC AUC 会有一些改进,尽管根据数据集的难度和所选的 XGBoost 模型配置,这并不能保证。
下面列出了完整的示例。
# fit balanced xgboost on an imbalanced classification dataset
from numpy import mean
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from xgboost import XGBClassifier
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=2, weights=[0.99], flip_y=0, random_state=7)
# define model
model = XGBClassifier(scale_pos_weight=99)
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(model, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
# summarize performance
print('Mean ROC AUC: %.5f' % mean(scores))
运行该示例准备合成不平衡类别数据集,然后使用重复交叉验证评估 XGBoost 训练算法的类加权版本。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到表现的适度提升,从上一节中 scale_pos_weight=1 时的约 0.95724 的 ROC AUC 提升到 scale_pos_weight=99 时的 0.95990 的值。
Mean ROC AUC: 0.95990
调整类别加权超参数
设置刻度 _ 位置 _ 重量的启发式方法在许多情况下都是有效的。
然而,使用不同的类权重可以获得更好的表现,这也将取决于用于评估模型的表现度量的选择。
在本节中,我们将网格搜索一系列不同的类权重,以获得类加权的 XGBoost,并发现哪一个导致最佳的 ROC AUC 分数。
我们将对正类尝试以下权重:
- 1(默认)
- Ten
- Twenty-five
- Fifty
- Seventy-five
- 99(推荐)
- One hundred
- One thousand
这些可以定义为网格搜索参数,如下所示:
...
# define grid
weights = [1, 10, 25, 50, 75, 99, 100, 1000]
param_grid = dict(scale_pos_weight=weights)
我们可以使用重复交叉验证对这些参数执行网格搜索,并使用 ROC AUC 估计模型表现:
...
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# define grid search
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=cv, scoring='roc_auc')
一旦执行,我们可以将最佳配置以及所有结果总结如下:
...
# report the best configuration
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
# report all configurations
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
将这些联系在一起,下面的例子在不平衡的数据集上为 XGBoost 算法搜索八个不同的正类权重。
我们可能会认为启发式类加权是表现最好的配置。
# grid search positive class weights with xgboost for imbalance classification
from numpy import mean
from sklearn.datasets import make_classification
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RepeatedStratifiedKFold
from xgboost import XGBClassifier
# generate dataset
X, y = make_classification(n_samples=10000, n_features=2, n_redundant=0,
n_clusters_per_class=2, weights=[0.99], flip_y=0, random_state=7)
# define model
model = XGBClassifier()
# define grid
weights = [1, 10, 25, 50, 75, 99, 100, 1000]
param_grid = dict(scale_pos_weight=weights)
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# define grid search
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=cv, scoring='roc_auc')
# execute the grid search
grid_result = grid.fit(X, y)
# report the best configuration
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
# report all configurations
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
运行该示例使用重复的 k 倍交叉验证评估每个正类别权重,并报告最佳配置和相关的平均 ROC AUC 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到 scale_pos_weight=99 正类加权达到了最好的平均 ROC 得分。这与一般启发式算法的配置相匹配。
有趣的是,几乎所有大于默认值 1 的值都有更好的平均 ROC AUC,即使是激进的值 1000。有趣的是,99 的值比 100 的值表现得更好,如果我没有按照 XGBoost 文档中的建议计算启发式方法,我可能会使用 100。
Best: 0.959901 using {'scale_pos_weight': 99}
0.957239 (0.031619) with: {'scale_pos_weight': 1}
0.958219 (0.027315) with: {'scale_pos_weight': 10}
0.958278 (0.027438) with: {'scale_pos_weight': 25}
0.959199 (0.026171) with: {'scale_pos_weight': 50}
0.959204 (0.025842) with: {'scale_pos_weight': 75}
0.959901 (0.025499) with: {'scale_pos_weight': 99}
0.959141 (0.025409) with: {'scale_pos_weight': 100}
0.958761 (0.024757) with: {'scale_pos_weight': 1000}
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- XGBoost:一个可扩展的树木提升系统,2016。
书
- 从不平衡数据集中学习,2018。
- 不平衡学习:基础、算法和应用,2013。
蜜蜂
- sklearn . datasets . make _ classification API。
- xgboost。xgbcclassifier API。
- XGBoost 参数,API 文档。
- 参数调整注释,应用编程接口文档。
摘要
在本教程中,您发现了用于不平衡分类的加权 XGBoost。
具体来说,您了解到:
- 梯度提升如何从高层次工作,以及如何开发一个用于分类的 XGBoost 模型。
- 如何修改 XGBoost 训练算法,以在训练过程中加权与正类重要性成比例的误差梯度。
- 如何为 XGBoost 训练算法配置正类权重,如何网格搜索不同的配置。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。