Machine Learning Mastery 不平衡数据教程(一)
用于不平衡分类的装袋和随机森林
最后更新于 2021 年 1 月 5 日
Bagging 是一种集成算法,它在训练数据集的不同子集上拟合多个模型,然后组合来自所有模型的预测。
随机森林是 bagging 的扩展,它也随机选择每个数据样本中使用的特征子集。装袋和随机森林都已被证明对各种不同的预测建模问题有效。
虽然有效,但它们不适合具有倾斜类分布的分类问题。然而,已经提出了对算法的许多修改,以适应它们的行为,并使它们更好地适应严重的类不平衡。
在本教程中,您将发现如何使用装袋和随机森林进行不平衡分类。
完成本教程后,您将知道:
- 如何使用随机欠采样 Bagging 进行不平衡分类?
- 如何使用带有类权重和随机欠采样的随机森林进行不平衡分类。
- 如何使用装袋和增强相结合的简单集成进行不平衡分类。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2021 年 1 月更新:更新了 API 文档的链接。
不平衡分类的装袋和随机森林 唐·格雷厄姆摄,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 不平衡分类的装袋
- 标准装袋
- 随机欠采样装袋
- 不平衡分类的随机森林
- 标准随机森林
- 具有类权重的随机森林
- 具有自举类加权的随机森林
- 随机欠采样的随机森林
- 不平衡分类的简单集成
- 轻松地在一起
不平衡分类的装袋
Bootstrap Aggregation,简称 Bagging】,是一种集成机器学习算法。
它包括首先选择带有替换的训练数据集的随机样本,这意味着给定的样本可能在训练数据集中包含零个、一个或多个样本副本。这被称为引导样本。然后在每个数据样本上拟合一个弱学习模型。典型地,不使用修剪的决策树模型(例如,可能稍微过度训练它们的训练集)被用作弱学习器。最后,来自所有适合的弱学习器的预测被组合以做出单个预测(例如,聚集的)。
集合中的每个模型随后被用于生成新样本的预测,并且这些 m 个预测被平均以给出袋装模型的预测。
—第 192 页,应用预测建模,2013 年。
创建新的引导样本以及对样本进行拟合和添加树的过程可以继续,直到在验证数据集上看不到集成表现的进一步提高。
这个简单的过程通常比单一配置良好的决策树算法产生更好的表现。
按原样装袋将创建引导样本,该样本将不考虑不平衡类别数据集的倾斜类分布。因此,尽管该技术总体上表现良好,但如果存在严重的类别不平衡,它可能表现不佳。
标准装袋
在我们深入探索 bagging 的扩展之前,让我们评估一个没有 bagging 的标准 bagging 决策树集成,并将其用作比较点。
我们可以使用装袋分类器 scikit-sklearn 类创建一个配置大致相同的装袋决策树模型。
首先,让我们用 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)
然后,我们可以定义标准的袋装决策树集成模型,以备评估。
...
# define model
model = BaggingClassifier()
然后,我们可以使用重复分层 k 倍交叉验证来评估该模型,重复 3 次,重复 10 次。
我们将使用所有折叠和重复的平均值 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)
将这些联系在一起,下面列出了在不平衡类别数据集上评估标准袋装集成的完整示例。
# bagged decision trees on an imbalanced classification problem
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 sklearn.ensemble import BaggingClassifier
# 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)
# define model
model = BaggingClassifier()
# 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: %.3f' % mean(scores))
运行该示例评估模型并报告平均 ROC AUC 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到模型获得了大约 0.87 的分数。
Mean ROC AUC: 0.871
随机欠采样装袋
有许多方法可以使装袋适用于不平衡分类。
也许最直接的方法是在拟合弱学习器模型之前对自举样本应用数据重采样。这可能涉及对少数类进行过采样或对多数类进行欠采样。
在装袋过程中面临重采样阶段时,克服类不平衡问题的一个简单方法是在从原始数据集中随机抽取实例时考虑它们的类。
—第 175 页,从不平衡数据集中学习,2018。
对引导中的少数类进行过采样被称为过采样;同样,对引导中的多数类进行欠采样被称为欠采样,而将两种方法结合起来被称为过欠采样。
不平衡学习库提供了欠标记的实现。
具体来说,它提供了 bagging 的一个版本,在引导样本内的多数类上使用随机欠采样策略,以便平衡这两个类。这在平衡分类器类中提供。
...
# define model
model = BalancedBaggingClassifier()
接下来,我们可以评估袋装决策树集成的修改版本,该版本在拟合每个决策树之前对多数类执行随机欠采样。
我们期望随机欠采样的使用将改善整体的表现。
该模型和前一模型的默认树数(n _ estimates)为 10。实际上,最好测试这个超参数的较大值,例如 100 或 1000。
下面列出了完整的示例。
# bagged decision trees with random undersampling for imbalanced classification
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 imblearn.ensemble import BalancedBaggingClassifier
# 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)
# define model
model = BalancedBaggingClassifier()
# 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: %.3f' % mean(scores))
运行该示例评估模型并报告平均 ROC AUC 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到平均 ROC AUC 从没有任何数据重采样的约 0.87 提升到大多数类随机欠采样的约 0.96。
这不是一个真正的苹果对苹果的比较,因为我们使用的是来自两个不同库的相同算法实现,但是它表明了一个普遍的观点,即在适应弱学习器之前平衡引导提供了一些好处,当类分布是倾斜的。
Mean ROC AUC: 0.962
虽然BalancedBaggingClassifier类使用了决策树,但是你可以测试不同的模型,比如 k 近邻等等。您可以在定义类时设置 base_estimator 参数,以使用不同的弱学习器分类器模型。
不平衡分类的随机森林
随机森林是决策树模型的另一个集合,可以认为是装袋后的改进。
像装袋一样,随机森林包括从训练数据集中选择自举样本,并在每个样本上拟合决策树。主要区别是没有使用所有的特性(变量或列);取而代之的是,为每个引导样本选择一个小的、随机选择的特征(列)子集。这具有去相关决策树(使它们更独立)的效果,并且反过来改善集成预测。
集合中的每个模型随后被用于生成新样本的预测,并且这些 m 个预测被平均以给出森林的预测。由于算法在每次分割时随机选择预测因子,因此树的相关性必然会降低。
—第 199 页,应用预测建模,2013 年。
同样,随机森林在广泛的问题上非常有效,但是像 bagging 一样,标准算法在不平衡分类问题上的表现不是很好。
在学习极不平衡的数据时,很有可能一个自举样本包含很少或甚至没有少数类,导致预测少数类的树表现很差。
——利用随机森林学习不平衡数据,2004。
标准随机森林
在我们深入研究随机森林集成算法的扩展以使其更适合不平衡分类之前,让我们在合成数据集上拟合和评估随机森林算法。
我们可以使用 scikit 中的 RandomForestClassifier 类——学习并使用少量的树,在本例中为 10 棵树。
...
# define model
model = RandomForestClassifier(n_estimators=10)
下面列出了在不平衡数据集上拟合标准随机森林集合的完整示例。
# random forest for imbalanced classification
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 sklearn.ensemble import RandomForestClassifier
# 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)
# define model
model = RandomForestClassifier(n_estimators=10)
# 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: %.3f' % mean(scores))
运行该示例评估模型并报告平均 ROC AUC 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到模型实现了大约 0.86 的平均 ROC AUC。
Mean ROC AUC: 0.869
具有类权重的随机森林
修改不平衡分类决策树的一个简单技术是,在计算所选分割点的“杂质”分数时,改变每个类别的权重。
杂质测量训练数据集中给定分割的样本组的混合程度,通常用基尼系数或熵来测量。计算可能会有偏差,因此有利于少数群体的混合是有利的,允许多数群体有一些假阳性。
随机森林的这种修改被称为加权随机森林。
另一种使随机森林更适合从极度不平衡的数据中学习的方法遵循成本敏感学习的思想。由于射频分类器倾向于偏向多数类,我们将对少数类的错误分类施加更重的惩罚。
——利用随机森林学习不平衡数据,2004。
这可以通过在随机森林分类器类上设置类权重参数来实现。
此参数使用一个字典,其中包含每个类值(例如 0 和 1)到权重的映射。可以提供“ balanced ”的自变量值,以自动使用来自训练数据集的反向加权,从而将焦点放在少数类上。
...
# define model
model = RandomForestClassifier(n_estimators=10, class_weight='balanced')
我们可以在我们的测试问题上测试随机森林的这个修改。虽然不是随机森林特有的,但我们希望有一些适度的改进。
下面列出了完整的示例。
# class balanced random forest for imbalanced classification
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 sklearn.ensemble import RandomForestClassifier
# 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)
# define model
model = RandomForestClassifier(n_estimators=10, class_weight='balanced')
# 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: %.3f' % mean(scores))
运行该示例评估模型并报告平均 ROC AUC 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到模型实现了平均 ROC AUC 从 0.86 到约 0.87 的适度提升。
Mean ROC AUC: 0.871
具有自举类加权的随机森林
假设每个决策树是从引导样本构建的(例如,带有替换的随机选择),数据样本中的类分布对于每个树将是不同的。
因此,基于每个引导样本中的类分布而不是整个训练数据集来改变类权重可能是有趣的。
这可以通过将 class_weight 参数设置为值“ balanced_subsample 来实现。
我们可以测试这种修改,并将结果与上面的“平衡”情况进行比较;下面列出了完整的示例。
# bootstrap class balanced random forest for imbalanced classification
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 sklearn.ensemble import RandomForestClassifier
# 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)
# define model
model = RandomForestClassifier(n_estimators=10, class_weight='balanced_subsample')
# 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: %.3f' % mean(scores))
运行该示例评估模型并报告平均 ROC AUC 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到模型实现了平均 ROC AUC 从 0.87 到约 0.88 的适度提升。
Mean ROC AUC: 0.884
随机欠采样的随机森林
对随机森林的另一个有用的修改是对引导样本执行数据重采样,以便显式地改变类分布。
不平衡学习库中的平衡随机森林分类器类实现了这一点,并对 reach bootstrap 样本中的大多数类执行随机欠采样。这通常被称为平衡随机森林。
...
# define model
model = BalancedRandomForestClassifier(n_estimators=10)
鉴于数据重采样技术的广泛成功,我们预计这将对模型表现产生更显著的影响。
我们可以在合成数据集上测试随机森林的这种修改,并比较结果。下面列出了完整的示例。
# random forest with random undersampling for imbalanced classification
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 imblearn.ensemble import BalancedRandomForestClassifier
# 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)
# define model
model = BalancedRandomForestClassifier(n_estimators=10)
# 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: %.3f' % mean(scores))
运行该示例评估模型并报告平均 ROC AUC 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到模型实现了平均 ROC AUC 从 0.89 到约 0.97 的适度提升。
Mean ROC AUC: 0.970
不平衡分类的简单集成
当考虑将袋装集成用于不平衡分类时,自然的想法可能是使用多数类的随机重采样来创建具有平衡类分布的多个数据集。
具体来说,可以从少数类中的所有示例和从多数类中随机选择的样本创建数据集。然后模型或弱学习器可以适合这个数据集。该过程可以重复多次,并且可以使用整个模型集合的平均预测来进行预测。
这正是徐等人在 2008 年的论文《类不平衡学习的探索性欠采样》中提出的方法
子样本的选择性构造被视为多数类的一种欠采样。多个子样本的生成允许集合克服欠采样的缺点,其中有价值的信息从训练过程中被丢弃。
……欠采样是处理阶级不平衡的有效策略。然而,欠采样的缺点是它丢弃了许多潜在有用的数据。
——班级不平衡学习的探索性欠采样,2008。
作者提出了该方法的变体,如简单集成和平衡级联。
让我们仔细看看轻松集成。
轻松地在一起
简单集成包括通过从少数类中选择所有示例,从多数类中选择一个子集,来创建训练数据集的平衡样本。
不是使用修剪的决策树,而是在每个子集上使用增强的决策树,特别是 AdaBoost 算法。
AdaBoost 的工作原理是首先在数据集上拟合一棵决策树,然后确定该树产生的错误,并根据这些错误对数据集中的示例进行加权,以便更多地关注错误分类的示例,而较少关注正确分类的示例。然后,在加权数据集上拟合后续树,以纠正错误。然后对给定数量的决策树重复该过程。
这意味着难以分类的样本将获得越来越大的权重,直到算法识别出能够正确分类这些样本的模型。因此,算法的每次迭代都需要学习数据的不同方面,重点是包含难以分类样本的区域。
—第 389 页,应用预测建模,2013 年。
来自不平衡学习库的简易集成分类器类提供了简易集成技术的实现。
...
# define model
model = EasyEnsembleClassifier(n_estimators=10)
我们可以评估我们的综合不平衡分类问题的技术。
给定一种随机欠采样的使用,我们期望该技术总体上表现良好。
下面列出了完整的示例。
# easy ensemble for imbalanced classification
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 imblearn.ensemble import EasyEnsembleClassifier
# 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)
# define model
model = EasyEnsembleClassifier(n_estimators=10)
# 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: %.3f' % mean(scores))
运行该示例评估模型并报告平均 ROC AUC 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到集成在数据集上表现良好,实现了约 0.96 的平均 ROC AUC,接近于在具有随机欠采样的随机森林的数据集上实现的平均 ROC AUC(0.97)。
Mean ROC AUC: 0.968
虽然在每个子样本上使用了一个 AdaBoost 分类器,但是可以通过将 base_estimator 参数设置到模型来使用替代分类器模型。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 利用随机森林学习不平衡数据,2004。
- 班级不平衡学习的探索性欠采样,2008。
书
- 从不平衡数据集中学习,2018。
- 不平衡学习:基础、算法和应用,2013。
- 应用预测建模,2013。
蜜蜂
- im learn .一起。平衡负载分类器 API 。
- 硬化。一起。bagginclassifier API。
- 硬化。一起。随机应变分类 API 。
- im learn . together . balance dradomforestclass ification API。
摘要
在本教程中,您发现了如何使用装袋和随机森林进行不平衡分类。
具体来说,您了解到:
- 如何使用随机欠采样 Bagging 进行不平衡分类?
- 如何使用带有类权重和随机欠采样的随机森林进行不平衡分类。
- 如何使用装袋和增强相结合的简单集成进行不平衡分类。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何为不平衡分类结合过采样和欠采样
最后更新于 2021 年 5 月 11 日
重采样方法旨在从训练数据集中添加或移除示例,以改变类别分布。
一旦类别分布更加平衡,标准机器学习分类算法套件就可以成功地适用于转换后的数据集。
过采样方法复制或创建少数类中的新合成示例,而欠采样方法删除或合并多数类中的示例。两种类型的重采样在单独使用时都是有效的,尽管当两种类型的方法一起使用时会更有效。
在本教程中,您将发现如何将过采样和欠采样技术结合起来用于不平衡分类。
完成本教程后,您将知道:
- 如何定义要应用于训练数据集或评估分类器模型时的过采样和欠采样方法序列。
- 如何手动结合过采样和欠采样方法进行不平衡分类?
- 如何使用预定义且表现良好的重采样方法组合进行不平衡分类。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2021 年 1 月更新:更新了 API 文档的链接。
结合过采样和欠采样进行不平衡分类 图片由拉德克·库恰尔斯基提供,保留部分权利。
教程概述
本教程分为四个部分;它们是:
- 二元测试问题与决策树模型
- 不平衡学习库
- 手动组合过采样和欠采样方法
- 手动组合随机过采样和欠采样
- 手动组合 SMOTE 和随机欠采样
- 使用预定义的重采样方法组合
- SMOTE 和 Tomek 链接的组合欠采样
- SMOTE 和编辑最近邻欠采样的组合
二元测试问题与决策树模型
在我们深入研究过采样和欠采样方法的组合之前,让我们定义一个合成数据集和模型。
我们可以使用 Sklearn 库中的 make_classification()函数定义一个合成的二进制类别数据集。
例如,我们可以用两个输入变量和 1:100 的类分布创建 10,000 个示例,如下所示:
...
# 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 中的一些示例明显重叠。
不平衡类别数据集的散点图
我们可以在这个数据集上拟合一个决策树分类器模型。这是一个很好的测试模型,因为它对训练数据集中的类分布很敏感。
...
# define model
model = DecisionTreeClassifier()
我们可以使用重复的分层 k 折叠交叉验证来评估模型,重复 3 次,重复 10 次。
曲线下 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: %.3f' % mean(scores))
将这些联系在一起,下面的例子评估了不平衡类别数据集上的决策树模型。
# evaluates a decision tree model on the imbalanced dataset
from numpy import mean
from sklearn.datasets import make_classification
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
# generate 2 class 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)
# define model
model = DecisionTreeClassifier()
# 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: %.3f' % mean(scores))
运行该示例会报告数据集上决策树在三次重复的 10 倍交叉验证中的平均 ROC AUC(例如,30 次不同模型评估的平均值)。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这个例子中,你可以看到模型实现了大约 0.76 的 ROC AUC。这为这个数据集提供了一个基线,我们可以用它来比较训练数据集中过采样和欠采样方法的不同组合。
Mean ROC AUC: 0.762
现在我们有了测试问题、模型和测试工具,让我们看看过采样和欠采样方法的手动组合。
不平衡学习库
在这些例子中,我们将使用不平衡学习 Python 库提供的实现,可以通过 pip 安装如下:
sudo pip install imbalanced-learn
您可以通过打印已安装库的版本来确认安装成功:
# check version number
import imblearn
print(imblearn.__version__)
运行该示例将打印已安装库的版本号;例如:
0.5.0
手动组合过采样和欠采样方法
不平衡学习 Python 库提供了一系列重采样技术,以及一个管道类,可用于创建应用于数据集的重采样方法的组合序列。
我们可以使用管道构建一系列过采样和欠采样技术来应用于数据集。例如:
# define resampling
over = ...
under = ...
# define pipeline
pipeline = Pipeline(steps=[('o', over), ('u', under)])
该流水线首先对数据集应用过采样技术,然后在返回最终结果之前对过采样变换的输出应用欠采样。它允许在数据集上按顺序堆叠或应用变换。
然后可以使用管道来转换数据集;例如:
# fit and apply the pipeline
X_resampled, y_resampled = pipeline.fit_resample(X, y)
或者,模型可以作为管道的最后一步添加。
这允许管道被视为一个模型。当在训练数据集上拟合时,首先将变换应用于训练数据集,然后将变换后的数据集提供给模型,以便它可以进行拟合。
...
# define model
model = ...
# define resampling
over = ...
under = ...
# define pipeline
pipeline = Pipeline(steps=[('o', over), ('u', under), ('m', model)])
回想一下,重采样仅应用于训练数据集,而不是测试数据集。
当在 k 折叠交叉验证中使用时,整个变换和拟合序列应用于由交叉验证折叠组成的每个训练数据集。这很重要,因为变换和拟合都是在不知道保持集的情况下执行的,这避免了数据泄露。例如:
...
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
现在我们知道了如何手动组合重采样方法,让我们看两个例子。
手动组合随机过采样和欠采样
组合重采样技术的一个很好的起点是从随机或简单的方法开始。
虽然它们很简单,而且单独应用时通常无效,但结合起来就可以有效。
随机过采样包括随机复制少数类中的示例,而随机欠采样包括从多数类中随机删除示例。
由于这两个转换是在不同的类上执行的,因此它们应用于训练数据集的顺序并不重要。
下面的示例定义了一个管道,该管道首先将少数类过采样到多数类的 10%,将多数类采样到比少数类多 50%,然后拟合决策树模型。
...
# define model
model = DecisionTreeClassifier()
# define resampling
over = RandomOverSampler(sampling_strategy=0.1)
under = RandomUnderSampler(sampling_strategy=0.5)
# define pipeline
pipeline = Pipeline(steps=[('o', over), ('u', under), ('m', model)])
下面列出了在二分类问题上评估这种组合的完整示例。
# combination of random oversampling and undersampling for imbalanced classification
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 sklearn.tree import DecisionTreeClassifier
from imblearn.pipeline import Pipeline
from imblearn.over_sampling import RandomOverSampler
from imblearn.under_sampling import RandomUnderSampler
# 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=1)
# define model
model = DecisionTreeClassifier()
# define resampling
over = RandomOverSampler(sampling_strategy=0.1)
under = RandomUnderSampler(sampling_strategy=0.5)
# define pipeline
pipeline = Pipeline(steps=[('o', over), ('u', under), ('m', model)])
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
# summarize performance
print('Mean ROC AUC: %.3f' % mean(scores))
运行该示例评估转换系统和模型,并将表现总结为平均 ROC AUC。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到 ROC AUC 表现从无变换的 0.76 适度提升到随机过采样和欠采样的约 0.81。
Mean ROC AUC: 0.814
手动组合 SMOTE 和随机欠采样
我们不限于使用随机重采样方法。
也许最流行的过采样方法是合成少数过采样技术,简称 SMOTE。
SMOTE 的工作方式是选择特征空间中靠近的示例,在特征空间中的示例之间绘制一条线,并沿着该线绘制一个新样本作为点。
该技术的作者建议在少数类上使用 SMOTE,然后在多数类上使用欠采样技术。
SMOTE 和欠采样的组合比普通欠采样表现更好。
——SMOTE:合成少数民族过采样技术,2011 年。
我们可以将 SMOTE 与随机欠采样结合起来。同样,这些过程的应用顺序并不重要,因为它们是在训练数据集的不同子集上执行的。
下面的管道实现了这种组合,首先应用 SMOTE 使少数类分布达到多数类的 10%,然后使用随机欠采样使多数类比少数类多 50%,然后拟合决策树分类器。
...
# define model
model = DecisionTreeClassifier()
# define pipeline
over = SMOTE(sampling_strategy=0.1)
under = RandomUnderSampler(sampling_strategy=0.5)
steps = [('o', over), ('u', under), ('m', model)]
下面的例子在我们的不平衡二进制分类问题上评估了这个组合。
# combination of SMOTE and random undersampling for imbalanced classification
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 sklearn.tree import DecisionTreeClassifier
from imblearn.pipeline import Pipeline
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
# 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=1)
# define model
model = DecisionTreeClassifier()
# define pipeline
over = SMOTE(sampling_strategy=0.1)
under = RandomUnderSampler(sampling_strategy=0.5)
steps = [('o', over), ('u', under), ('m', model)]
pipeline = Pipeline(steps=steps)
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
# summarize performance
print('Mean ROC AUC: %.3f' % mean(scores))
运行该示例评估转换系统和模型,并将表现总结为平均 ROC AUC。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到 ROC AUC 表现从大约 0.81 到大约 0.83 的另一个列表。
Mean ROC AUC: 0.833
使用预定义的重采样方法组合
已经证明过采样和欠采样方法的组合是有效的,并且可以一起被认为是重采样技术。
两个例子是 SMOTE 与 Tomek 链接欠采样和 SMOTE 与编辑最近邻欠采样的组合。
不平衡学习 Python 库直接为这两种组合提供了实现。让我们依次仔细看看每一个。
SMOTE 和 Tomek 链接的组合欠采样
SMOTE 是一种过采样方法,在少数民族类别中合成新的似是而非的例子。
Tomek Links 指的是一种用于识别数据集中具有不同类的最近邻对的方法。移除这些对中的一个或两个示例(例如多数类中的示例)具有使训练数据集中的决策边界不那么嘈杂或模糊的效果。
Gustavo Batista 等人在他们 2003 年发表的题为“平衡训练数据以自动标注关键词:案例研究”的论文中测试了组合这些方法
具体来说,首先应用 SMOTE 方法对少数类进行过采样以获得平衡分布,然后识别并移除多数类的 Tomek Links 中的示例。
在这项工作中,只有参与 Tomek 链接的多数类示例被删除,因为少数类示例被认为太罕见而不能被丢弃。[……]在我们的工作中,由于少数类示例是人为创建的,并且数据集目前是平衡的,因此形成 Tomek 链接的多数类和少数类示例都被删除了。
——平衡训练数据自动标注关键词:案例研究,2003。
这种组合被证明可以减少假阴性,但代价是增加了二进制分类任务的假阳性。
我们可以使用smottomek 类来实现这个组合。
...
# define resampling
resample = SMOTETomek()
SMOTE 配置可以通过“ smote ”参数设置,并采用已配置的 SMOTE 实例。可以通过“tomek”参数设置 Tomek 链接配置,并采用已配置的 TomekLinks 对象。
默认情况下,使用 SMOTE 平衡数据集,然后从所有类中移除 Tomek 链接。这是另一篇探索这种组合的论文中使用的方法,标题为“几种平衡机器学习训练数据的方法的行为研究”
……我们建议将 Tomek 链接应用于过采样的训练集,作为一种数据清理方法。因此,不是只移除形成 Tomek 链接的大多数类示例,而是移除两个类中的示例。
——平衡机器学习训练数据的几种方法的行为研究,2004。
或者,我们可以将组合配置为仅从多数类中移除链接,如 2003 年的论文中所述,方法是用实例指定“ tomek ”参数,将“ sampling_strategy ”参数设置为仅欠采样“多数类;例如:
...
# define resampling
resample = SMOTETomek(tomek=TomekLinks(sampling_strategy='majority'))
在我们的二进制分类问题上,我们可以用决策树分类器来评估这种组合重采样策略。
下面列出了完整的示例。
# combined SMOTE and Tomek Links resampling for imbalanced classification
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 imblearn.pipeline import Pipeline
from sklearn.tree import DecisionTreeClassifier
from imblearn.combine import SMOTETomek
from imblearn.under_sampling import TomekLinks
# 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=1)
# define model
model = DecisionTreeClassifier()
# define resampling
resample = SMOTETomek(tomek=TomekLinks(sampling_strategy='majority'))
# define pipeline
pipeline = Pipeline(steps=[('r', resample), ('m', model)])
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
# summarize performance
print('Mean ROC AUC: %.3f' % mean(scores))
运行该示例评估转换系统和模型,并将表现总结为平均 ROC AUC。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,这种组合的重采样策略似乎没有为该数据集上的模型提供好处。
Mean ROC AUC: 0.815
SMOTE 和编辑最近邻欠采样的组合
SMOTE 可能是最流行的过采样技术,可以与许多不同的欠采样技术相结合。
另一种非常流行的欠采样方法是编辑最近邻法,或 ENN 法则。该规则包括使用 k=3 最近邻来定位数据集中被错误分类然后被移除的那些示例。它可以应用于所有的类,也可以只应用于大多数类中的那些例子。
Gustavo Batista 等人在他们 2004 年的论文《几种平衡机器学习训练数据的方法的行为研究》中,探索了过采样和欠采样方法的许多组合,而不是孤立使用的方法
这包括以下组合:
- 压缩最近邻+托梅克链接
- SMOTE + Tomek 左侧
- 最近邻居
关于这最后的组合,作者评论说,ENN 在降低多数类的采样上比托梅克链接更积极,提供了更深入的清理。他们应用这种方法,从多数和少数群体中删除例子。
……ENN 被用来从这两个类中移除示例。因此,任何被其三个最近邻居错误分类的例子都将从训练集中移除。
——平衡机器学习训练数据的几种方法的行为研究,2004。
这可以通过不平衡学习库中的SMOTENN 类来实现。
...
# define resampling
resample = SMOTEENN()
SMOTE 配置可以通过“ smote 参数设置为 SMOTE 对象,ENN 配置可以通过“ enn 参数设置为编辑最近邻居对象。SMOTE 默认平衡分布,其次是 ENN,默认从所有类中移除错误分类的示例。
我们可以通过将“ enn ”参数设置为一个edited nearest neighbores实例,并将 sampling_strategy 参数设置为“more”来更改 ENN,只从多数类中移除示例。
...
# define resampling
resample = SMOTEENN(enn=EditedNearestNeighbours(sampling_strategy='majority'))
我们可以评估默认策略(编辑所有类中的示例),并在不平衡的数据集上使用决策树分类器进行评估。
下面列出了完整的示例。
# combined SMOTE and Edited Nearest Neighbors resampling for imbalanced classification
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 imblearn.pipeline import Pipeline
from sklearn.tree import DecisionTreeClassifier
from imblearn.combine import SMOTEENN
# 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=1)
# define model
model = DecisionTreeClassifier()
# define resampling
resample = SMOTEENN()
# define pipeline
pipeline = Pipeline(steps=[('r', resample), ('m', model)])
# define evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
# summarize performance
print('Mean ROC AUC: %.3f' % mean(scores))
运行该示例评估转换系统和模型,并将表现总结为平均 ROC AUC。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们看到随机欠采样方法的表现比 SMOTE 进一步提升,从约 0.81 提升到约 0.85。
Mean ROC AUC: 0.856
这一结果突出表明,编辑过采样的少数族裔也可能是一个很容易被忽略的重要考虑因素。
这与 2004 年论文中的发现相同,作者发现 SMOTE 与 Tomek Links 和 SMOTE 与 ENN 在一系列数据集上表现良好。
我们的结果表明,对于几乎没有正(少数)例子的数据集,一般的过采样方法,特别是 Smote + Tomek 和 Smote + ENN(本工作中提出的两种方法)在实践中提供了非常好的结果。
——平衡机器学习训练数据的几种方法的行为研究,2004。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- SMOTE:合成少数过采样技术,2011。
- 平衡训练数据进行关键词自动标注:案例研究,2003。
- 平衡机器学习训练数据的几种方法的行为研究,2004。
书
- 从不平衡数据集中学习,2018。
- 不平衡学习:基础、算法和应用,2013。
应用程序接口
- 不平衡学习,GitHub 。
- 过采样和欠采样相结合,不平衡学习用户指南。
- imblearn.over_sampling。randomoversacompler API。
- imb learn . pipeline . pipeline API。
- imblearn.under_sampling。随机欠采样应用编程接口。
- imblearn.over_sampling。SMOTE API 。
- imb learn . combine . smotetomek API。
- imb learn . combine . SMOTENN API。
文章
摘要
在本教程中,您发现了如何将过采样和欠采样技术结合起来用于不平衡分类。
具体来说,您了解到:
- 如何定义要应用于训练数据集或评估分类器模型时的过采样和欠采样方法序列。
- 如何手动结合过采样和欠采样方法进行不平衡分类?
- 如何使用预定义且表现良好的重采样方法组合进行不平衡分类。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
用于不平衡分类的成本敏感决策树
最后更新于 2020 年 8 月 21 日
决策树算法对于平衡分类是有效的,尽管它在不平衡的数据集上表现不佳。
选择树的分割点,以便最好地将示例分成两组,同时最小化混合。当两个组都被来自一个类的例子支配时,用于选择分裂点的标准将看到良好的分离,而事实上,来自少数类的例子被忽略了。
这个问题可以通过修改用于评估分割点的标准来克服,以考虑每个类的重要性,通常称为加权分割点或加权决策树。
在本教程中,您将发现用于不平衡分类的加权决策树。
完成本教程后,您将知道:
- 标准决策树算法如何不支持不平衡分类?
- 选择拆分时如何修改决策树算法以按类权重加权模型误差。
- 如何为决策树算法配置类权重,如何网格搜索不同的类权重配置。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何实现不平衡分类的加权决策树 Bonnie Moreland摄,保留部分权利。
教程概述
本教程分为四个部分;它们是:
- 不平衡类别数据集
- 不平衡分类的决策树
- 基于 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=3)
生成后,我们可以总结类分布,以确认数据集是按照我们的预期创建的。
...
# 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=1, weights=[0.99], flip_y=0, random_state=3)
# 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 类不平衡的二进制类别数据集散点图
接下来,我们可以在数据集上拟合标准决策树模型。
决策树可以使用 Sklearn 库中的决策树分类器类来定义。
...
# define model
model = DecisionTreeClassifier()
我们将使用重复交叉验证来评估模型,重复三次 10 倍交叉验证。模式表现将使用重复和所有折叠的平均曲线下面积来报告。
...
# 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: %.3f' % mean(scores))
将这些联系在一起,下面列出了定义和评估不平衡分类问题的标准决策树模型的完整示例。
决策树是二进制分类任务的有效模型,尽管默认情况下,它们在不平衡分类方面并不有效。
# fit a decision tree 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 sklearn.tree import DecisionTreeClassifier
# 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=3)
# define model
model = DecisionTreeClassifier()
# 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: %.3f' % mean(scores))
运行该示例评估不平衡数据集上的标准决策树模型,并报告平均 ROC AUC。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
我们可以看到模型有技巧,实现了 0.5 以上的 ROC AUC,在这种情况下实现了 0.746 的平均得分。
Mean ROC AUC: 0.746
这为标准决策树算法的任何修改提供了一个比较基准。
不平衡分类的决策树
决策树算法也被称为分类和回归树 (CART),包括从训练数据集中生长一棵树来分类例子。
可以认为树划分了训练数据集,其中示例沿着树的决策点向下前进,到达树的叶子,并被分配一个类标签。
该树是通过使用数据集中的变量值拆分训练数据集来构建的。在每一点上,以贪婪的方式选择导致最纯(最少混合)的示例组的数据分割。
这里,纯度意味着将实例干净地分成组,其中所有 0 或所有 1 类的一组实例是最纯的,两类的 50-50 混合物是最不纯的。纯度最常用基尼杂质计算,虽然也可以用熵计算。
纯度度量的计算包括计算给定类别的示例被拆分错误分类的概率。计算这些概率包括对每组中每一类的例子数量进行求和。
拆分标准可以更新,不仅要考虑拆分的纯度,还要根据每个类的重要性进行加权。
对于成本敏感的树归纳,我们的直觉是修改实例的权重,使其与错误分类实例所属类的成本成比例…
——一种诱导成本敏感树的实例加权方法,2002。
这可以通过用加权和代替每组中的实例数来实现,其中提供系数来加权和。
较大的权重分配给重要性较高的类,较小的权重分配给重要性较低的类。
- 小权重:重要性较小,对节点纯度影响较小。
- 大权重:重要性更高,对节点纯度影响更大。
可以给多数类分配一个较小的权重,这可以提高(降低)节点的纯度分数,否则该节点可能看起来排序不太好。反过来,这可能允许多数阶级的更多例子被归类为少数阶级,更好地适应少数阶级的那些例子。
更高的权重[被]分配给来自错误分类成本值更高的类的实例。
—第 71 页,从不平衡数据集中学习,2018。
因此,决策树算法的这种修改被称为加权决策树、类加权决策树或成本敏感决策树。
分裂点计算的修改是最常见的,尽管已经对决策树构造算法的一系列其他修改进行了大量研究,以更好地适应类别不平衡。
带 Sklearn 的加权决策树
Sklearn Python 机器学习库提供了支持类加权的决策树算法的实现。
决策树分类器类提供了可以指定为模型超参数的类权重参数。类别权重是一个字典,它定义了每个类别标签(例如 0 和 1)以及权重,当拟合模型时,该权重应用于决策树中拆分的组纯度计算。
例如,每个类别 0 和 1 的 1 比 1 权重可以定义如下:
...
# define model
weights = {0:1.0, 1:1.0}
model = DecisionTreeClassifier(class_weight=weights)
类别称重可以多种方式定义;例如:
- 领域专长,通过与主题专家交谈确定。
- 调谐,由超参数搜索如网格搜索确定。
- 启发式,使用一般最佳实践指定。
使用类别权重的最佳实践是使用训练数据集中类别分布的倒数。
例如,测试数据集的类分布是少数类与多数类的比例为 1:100。该比率的倒数可以与多数类的 1 和少数类的 100 一起使用。
例如:
...
# define model
weights = {0:1.0, 1:100.0}
model = DecisionTreeClassifier(class_weight=weights)
我们也可以使用分数来定义相同的比率,并获得相同的结果。
例如:
...
# define model
weights = {0:0.01, 1:1.0}
model = DecisionTreeClassifier(class_weight=weights)
通过将类权重设置为“平衡,可以直接使用该启发式算法。
例如:
...
# define model
model = DecisionTreeClassifier(class_weight='balanced')
我们可以使用上一节中定义的相同评估过程来评估带有类权重的决策树算法。
我们期望决策树的类加权版本比没有任何类加权的标准版本的决策树表现得更好。
下面列出了完整的示例。
# decision tree with class weight 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 sklearn.tree import DecisionTreeClassifier
# 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=3)
# define model
model = DecisionTreeClassifier(class_weight='balanced')
# 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: %.3f' % mean(scores))
运行该示例准备合成不平衡类别数据集,然后使用重复交叉验证评估决策树算法的类加权版本。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,报告的平均 ROC AUC 分数显示出比决策树算法的未加权版本更好的分数:0.759,而不是 0.746。
Mean ROC AUC: 0.759
网格搜索加权决策树
使用与训练数据成反比的类权重只是一种启发。
使用不同的类权重可以获得更好的表现,这也将取决于用于评估模型的表现度量的选择。
在本节中,我们将网格搜索一系列不同的类别权重,以获得加权决策树,并发现哪一个导致最佳的 ROC AUC 分数。
我们将对类别 0 和 1 尝试以下权重:
- 0:100 班,1:1 班。
- 0:10 班,1:1 班。
- 0:1 班,1:1 班。
- 0:1 班,1:10 班。
- 0:1 班,1:100 班。
这些可以被定义为网格搜索参数,如下所示:
...
# define grid
balance = [{0:100,1:1}, {0:10,1:1}, {0:1,1:1}, {0:1,1:10}, {0:1,1:100}]
param_grid = dict(class_weight=balance)
我们可以使用重复交叉验证对这些参数执行网格搜索,并使用 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))
将这些联系在一起,下面的示例在不平衡的数据集上为决策树算法搜索五个不同的类权重。
我们可能会认为启发式类加权是表现最好的配置。
# grid search class weights with decision tree 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 sklearn.tree import DecisionTreeClassifier
# 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=3)
# define model
model = DecisionTreeClassifier()
# define grid
balance = [{0:100,1:1}, {0:10,1:1}, {0:1,1:1}, {0:1,1:10}, {0:1,1:100}]
param_grid = dict(class_weight=balance)
# 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 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到 1:100 的多数对少数类权重获得了最佳的平均 ROC 分数。这与一般启发式算法的配置相匹配。
探索更严格的类别权重,看看它们对平均 ROC AUC 评分的影响,可能会很有趣。
Best: 0.752643 using {'class_weight': {0: 1, 1: 100}}
0.737306 (0.080007) with: {'class_weight': {0: 100, 1: 1}}
0.747306 (0.075298) with: {'class_weight': {0: 10, 1: 1}}
0.740606 (0.074948) with: {'class_weight': {0: 1, 1: 1}}
0.747407 (0.068104) with: {'class_weight': {0: 1, 1: 10}}
0.752643 (0.073195) with: {'class_weight': {0: 1, 1: 100}}
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 一种诱导成本敏感树的实例加权方法,2002。
书
- 从不平衡数据集中学习,2018。
- 不平衡学习:基础、算法和应用,2013。
蜜蜂
- sklearn . utils . class _ weight . compute _ class _ weight API。
- 硬化. tree .决策树分类器 API 。
- sklearn.model_selection。GridSearchCV API 。
摘要
在本教程中,您发现了用于不平衡分类的加权决策树。
具体来说,您了解到:
- 标准决策树算法如何不支持不平衡分类?
- 选择拆分时如何修改决策树算法以按类权重加权模型误差。
- 如何为决策树算法配置类权重,如何网格搜索不同的类权重配置。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
不平衡分类的成本敏感学习
大多数机器学习算法都假设模型产生的所有错误分类错误都是相等的。
这通常不是不平衡分类问题的情况,在不平衡分类问题中,遗漏一个正类或少数类比错误地将一个例子从负类或多数类中分类出来更糟糕。有许多真实的例子,如检测垃圾邮件、诊断医疗状况或识别欺诈。在所有这些情况下,假阴性(错过一个病例)比假阳性更糟糕或更昂贵。
成本敏感学习是机器学习的一个子领域,在训练机器学习模型时会考虑预测误差的成本(以及潜在的其他成本)。它是与不平衡学习领域密切相关的一个研究领域,涉及在具有偏斜类分布的数据集上的分类。因此,为成本敏感学习开发和使用的许多概念化和技术可以用于不平衡的分类问题。
在本教程中,您将发现对不平衡分类的成本敏感学习的温和介绍。
完成本教程后,您将知道:
- 不平衡分类问题通常对假阳性分类错误的重视程度不同于假阴性。
- 成本敏感学习是机器学习的一个子领域,它涉及在训练机器学习算法时明确定义和使用成本。
- 成本敏感技术可以分为三类,包括数据重采样、算法修改和集成方法。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
不平衡分类的成本敏感学习 图片由 bvi4092 提供,保留部分权利。
教程概述
本教程分为四个部分;它们是:
- 并非所有分类错误都相等
- 对成本敏感的学习
- 成本敏感的不平衡分类
- 对成本敏感的方法
并非所有分类错误都相等
分类是一个预测建模问题,包括预测观察的类别标签。
可能有许多类标签,即所谓的多类分类问题,尽管最简单也可能是最常见的分类问题类型有两类,被称为二分类。
大多数为分类而设计的机器学习算法都假设每个观察到的类都有相同数量的例子。
实际上并不总是这样,具有偏斜类分布的数据集被称为不平衡分类问题。
在对成本敏感的学习中,不是每个实例被正确或不正确地分类,而是每个类(或实例)被给予错误分类成本。因此,问题不是试图优化准确率,而是最小化总的错误分类成本。
—第 50 页,不平衡学习:基础、算法和应用,2013。
除了假设类分布是平衡的,大多数机器学习算法还假设分类器产生的预测误差是相同的,即所谓的误分类。
对于二进制分类问题,尤其是那些类别分布不平衡的问题,通常不是这样。
大多数分类器假设错误分类成本(假阴性和假阳性成本)是相同的。在大多数现实应用中,这个假设是不成立的。
——不平衡数据的成本敏感学习方法,2010。
对于不平衡分类问题,来自多数类的例子被称为负类,并被赋予类标签 0。那些来自少数民族的例子被称为正类,并被指定为类标签 1。
这种否定与肯定命名约定的原因是,多数类的示例通常代表正常或无事件情况,而少数类的示例代表例外或事件情况。
- 多数类:否定或无事件分配类标签 0。
- 少数民族类:正面或事件被赋予类标签 1。
现实世界中不平衡的二进制分类问题通常对每一个可能出现的分类错误都有不同的解释。例如,将一个负面案例归类为正面案例通常比将一个正面案例归类为负面案例少得多。
如果我们考虑不平衡二进制分类问题的分类器的目标是正确地检测阳性病例,并且阳性病例代表我们最感兴趣的异常或事件,这是有意义的。
我们可以用一些例子来说明这一点。
银行贷款问题:考虑一个银行想确定是否给客户贷款的问题。拒绝一个好客户的贷款并不像给一个可能永远不会还款的坏客户贷款那么糟糕。
癌症诊断问题:考虑一个医生想要确定患者是否患有癌症的问题。诊断一个健康的癌症患者,并进行更多的医学检查,比让一个癌症患者出院更好。
……在某一癌症的医学诊断中,如果将癌症视为阳性类别,将非癌症(健康)视为阴性,则遗漏了一个癌症(患者实际上是阳性,但被归类为阴性;因此它也被称为“假阴性”)比假阳性错误严重得多(因此昂贵)。
——成本敏感学习,《机器学习百科全书》,2010。
欺诈检测问题:考虑一个保险公司想要确定某个理赔是否存在欺诈的问题。将好的索赔确定为欺诈性索赔,并对客户进行跟进,这比接受欺诈性保险索赔要好。
从这些例子中我们可以看出,错误分类错误通常是不可取的,但一种错误分类比另一种更糟糕。具体来说,无论我们以何种方式来衡量目标领域的背景,将阳性病例预测为阴性病例都是更有害、更昂贵或更糟糕的。
……将一个实际的正面例子错误地归类为反面,往往比将一个实际的反面例子归类为正面更为昂贵。
——成本敏感学习,《机器学习百科全书》,2010。
将每种错误分类错误视为相同的机器学习算法无法满足这些类型问题的需要。
因此,少数类在训练数据中的代表性不足,以及正确识别少数类中的例子的重要性增加,使得不平衡分类成为应用机器学习中最具挑战性的问题之一。
类不平衡是机器学习算法面临的挑战性问题之一。
——不平衡数据的成本敏感学习方法,2010。
对成本敏感的学习
机器学习有一个子领域,专注于学习和使用数据模型,这些数据在进行预测等时具有不均衡的惩罚或成本。
这个领域通常被称为成本敏感机器学习,或者更简单地称为成本敏感学习。
……机器学习算法需要对它所处理的成本敏感,更好的情况是在模型拟合过程中考虑成本。这导致了机器学习中相对较新的研究课题——成本敏感的机器学习。
—第十三页,成本敏感型机器学习,2011 年。
传统上,机器学习算法在数据集上训练,并寻求最小化误差。在数据上拟合模型解决了一个优化问题,在这个问题中,我们明确地寻求最小化误差。一系列函数可以用来计算模型对训练数据的误差,更一般的术语称为损失。我们寻求最小化模型在训练数据上的损失,这与谈论误差最小化是一样的。
- 误差最小化:训练机器学习算法时的常规目标是最小化模型在训练数据集上的误差。
在对成本敏感的学习中,与不正确预测相关联的一种惩罚,被称为“成本”我们也可以把惩罚的反面称为“T2”利益,尽管这种框架很少使用。
- 成本:与不正确预测相关的惩罚。
成本敏感学习的目标是最小化训练数据集上模型的成本,其中假设不同类型的预测误差具有不同且已知的相关成本。
- 成本最小化:成本敏感学习的目标是最小化训练数据集上模型的成本。
成本敏感学习是一种将错误分类成本(可能还有其他类型的成本)考虑在内的学习。这种学习的目标是使总成本最小化。
——成本敏感学习,《机器学习百科全书》,2010。
不平衡分类和成本敏感学习之间存在紧密耦合。具体来说,不平衡的学习问题可以使用成本敏感的学习来解决。
然而,对成本敏感的学习是一个单独的子领域的研究,成本的定义可能比预测误差或分类误差更广泛。这意味着,尽管成本敏感学习中的一些方法可以有助于不平衡分类,但并非所有成本敏感学习技术都是不平衡学习技术,相反,并非所有用于解决不平衡学习的方法都适用于成本敏感学习。
为了使这一点具体化,我们可以考虑在数据集上训练模型时可能希望考虑或测量成本的各种其他方法。例如,彼得·特尼在他 2000 年发表的题为“归纳概念学习中的成本类型的论文中列出了机器学习中可能考虑的九种成本类型
概括来说,它们是:
- 错误分类错误(或更一般的预测错误)的成本。
- 测试或评估的成本。
- 教师或标签费用。
- 干预或改变观察系统的成本。
- 干预带来的不必要的成就或结果的代价。
- 计算成本或计算复杂性。
- 案例或数据收集的成本。
- 人机交互或构建问题并使用软件来适应和使用模型的成本。
- 不稳定或变化的代价被称为概念漂移。
尽管成本和成本敏感学习对许多现实问题至关重要,但直到最近,这一概念还是一个很大程度上被忽视的新话题。
在概念学习的实际应用中,涉及到许多不同类型的成本。大多数机器学习文献忽略了所有类型的成本…
——归纳概念学习中的成本类型,2000。
上面的列表强调了我们对不平衡分类感兴趣的成本只是更广泛的成本敏感学习领域可能考虑的成本范围的一种类型。
在下一节中,我们将仔细研究如何利用错误分类成本敏感学习的思想来帮助不平衡的分类。
成本敏感的不平衡分类
不平衡分类的成本敏感学习的重点是首先为可能出现的错误分类错误类型分配不同的成本,然后使用专门的方法将这些成本考虑在内。
使用成本矩阵的思想可以最好地理解不同的误分类成本。
让我们从回顾混淆矩阵开始。
一个混淆矩阵是一个模型对分类任务所做预测的总结。这是一个表,总结了每个类的预测数量,用每个示例所属的实际类来分隔。
最好使用具有负类和正类的二分类问题来理解,通常分别分配 0 和 1 类标签。表中的列代表示例所属的实际类,行代表预测类(尽管行和列的含义可以而且经常互换,不会失去意义)。表格中的单元格是满足行和列条件的示例数的计数,每个单元格都有一个特定的通用名称。
下面列出了二进制分类任务的混淆矩阵示例,显示了表中四个单元格中的值的通用名称。
| Actual Negative | Actual Positive
Predicted Negative | True Negative | False Negative
Predicted Positive | False Positive | True Positive
我们可以看到,我们最感兴趣的是错误,即所谓的假阳性和假阴性,在许多不平衡的分类任务中,假阴性可能是我们最感兴趣的。
现在,我们可以考虑具有相同行和列的同一个表,并为每个单元格分配一个成本。这叫做成本矩阵。
- 成本矩阵:为混淆矩阵中的每个单元格分配成本的矩阵。
下面的例子是一个成本矩阵,我们使用符号 C() 来表示成本,第一个值表示为预测类,第二个值表示实际类。混淆矩阵中每个单元格的名称也作为首字母缩略词列出,例如,假阳性是 FP。
| Actual Negative | Actual Positive
Predicted Negative | C(0,0), TN | C(0,1), FN
Predicted Positive | C(1,0), FP | C(1,1), TP
我们可以看到,假阳性的成本是 C(1,0),假阴性的成本是 C(0,1)。
成本矩阵的这个公式和符号来自查尔斯·埃尔坎 2001 年的开创性论文,题目是“T2 对成本敏感学习的基础”
这个矩阵的一个直觉是,错误分类的成本总是高于正确分类,否则,可以通过预测一个类来最小化成本。
从概念上讲,错误标注一个例子的成本应该总是大于正确标注的成本。
——成本敏感学习的基础,2001。
例如,我们可能在每个类中没有分配正确预测的成本,假阳性的成本为 5,假阴性的成本为 88。
| Actual Negative | Actual Positive
Predicted Negative | 0 | 88
Predicted Positive | 5 | 0
我们可以使用这个框架将分类器的总成本定义为假阴性和假阳性的成本加权和。
- 总成本= C(0,1) *假阴性+ C(1,0) *假阳性
这是我们在对成本敏感的学习中寻求最小化的价值,至少在概念上是这样。
CSL 的目的是建立一个错误分类成本(总成本)最小的模型
——不平衡数据的成本敏感学习方法,2010。
必须仔细定义成本矩阵的值。与传统机器学习模型中误差函数的选择一样,成本或成本函数的选择将决定模型的质量和实用性,该模型适合于训练数据。
成本敏感学习的有效性强烈依赖于所提供的成本矩阵。提供的参数对训练和预测步骤都至关重要。
—第 66 页,从不平衡数据集中学习,2018。
在某些问题领域,定义成本矩阵可能是显而易见的。在保险索赔的例子中,假阳性的成本可能是客户跟进公司的货币成本,假阴性的成本可能是保险索赔的成本。
在其他领域,定义成本矩阵可能具有挑战性。例如,在癌症诊断测试示例中,假阳性的成本可能是执行后续测试的货币成本,而让生病的患者回家并病情加重的等价美元成本是多少?在这种情况下,成本矩阵可以由领域专家或经济学家定义,也可以不定义。
此外,成本可能是一个复杂的多维函数,包括货币成本、声誉成本等等。
不平衡分类任务的一个很好的起点是基于逆类分布分配成本。
在许多情况下,我们无法获得领域专家的帮助,并且在分类器训练期间没有关于成本矩阵的先验信息可用。当我们想要将成本敏感学习作为解决不平衡问题的方法时,这是一个常见的场景…
—第 67 页,从不平衡数据集中学习,2018。
例如,我们可能有一个数据集,少数类中的示例与多数类中的示例的比例为 1 比 100 (1:100)。这个比率可以反过来用作错误分类错误的成本,其中假阴性的成本是 100,假阳性的成本是 1。
| Actual Negative | Actual Positive
Predicted Negative | 0 | 100
Predicted Positive | 1 | 0
一般来说,这是一种设置成本的有效启发式方法,尽管它假设在训练数据中观察到的类分布代表更广泛的问题,并且适用于所选择的对成本敏感的方法。
因此,使用这种启发式方法作为起点是一个好主意,然后测试一系列类似的相关成本或比率,以确认它是合理的。
对成本敏感的方法
对成本敏感的机器学习方法是那些明确使用成本矩阵的方法。
鉴于我们对不平衡分类的关注,我们对那些以某种方式使用不同错误分类成本的成本敏感技术特别感兴趣。
对成本敏感的学习方法通过使用不同的成本矩阵来解决不平衡学习的问题,这些成本矩阵描述了对任何特定数据示例进行错误分类的成本。
—第 3-4 页,不平衡学习:基础、算法和应用,2013。
可能有三组主要的成本敏感方法与不平衡学习最相关;它们是:
- 成本敏感重采样
- 成本敏感算法
- 对成本敏感的集成
让我们依次仔细看看每一个。
成本敏感重采样
在不平衡分类中,数据重采样指的是变换训练数据集以更好地平衡类分布的技术。
这可能涉及选择性地从多数类中删除示例,称为欠采样。更常见的是,它指的是复制或合成少数类中的新示例,称为过采样,或欠采样和过采样的组合。
数据重采样是一种可以直接用于成本敏感学习的技术。重采样的重点不是平衡倾斜的类分布,而是改变训练数据集的组成,以满足成本矩阵的期望。
这可能涉及直接对数据分布进行重采样,或者使用一种方法对数据集中的示例进行加权。这种方法可以称为训练数据集的成本比例加权或成本比例重采样。
我们提出并评估了一系列基于训练示例的成本比例加权的方法……,这可以通过将权重馈送到分类算法(在 boosting 中经常这样做)或(以黑盒方式)通过仔细的二次采样来实现。
——按成本比例示例加权的成本敏感学习,2003 年。
对于使用类别分布定义成本矩阵的不平衡分类,数据重采样技术没有区别。
成本敏感算法
机器学习算法很少专门为成本敏感的学习而开发。
相反,现有机器学习算法的财富可以被修改以利用成本矩阵。
这可能涉及对每种算法的独特修改,并且开发和测试可能相当耗时。已经为流行的算法提出了许多这样的算法特定的扩展,如决策树和支持向量机。
在所有的分类器中,代价敏感决策树的归纳无疑获得了最多的关注。
—第 69 页,从不平衡数据集中学习,2018。
Sklearn Python 机器学习库通过以下分类器上的 class_weight 参数提供了这些成本敏感扩展的示例:
修改现有算法的另一种更通用的方法是,在训练算法时,使用成本作为错误分类的惩罚。考虑到大多数机器学习算法都是为了最小化误差而训练的,因此在训练过程中,错误分类的成本会被添加到误差中,或者用于对误差进行加权。
这种方法可以用于迭代训练的算法,如逻辑回归和人工神经网络。
Sklearn 库通过以下分类器上的 class_weight 参数提供了这些成本敏感扩展的示例:
- 物流损耗
- 重制
Keras Python 深度学习库还提供了在训练模型时通过 fit()函数上的 class_weight 参数对神经网络的成本敏感增强的使用进行访问。
同样,当逆类分布被用作成本矩阵时,算法的成本敏感扩展和算法的不平衡分类扩展之间的界限是模糊的。
在对成本敏感的机器学习领域,这些算法用“对成本敏感的前缀来表示,例如对成本敏感的逻辑回归,而在不平衡学习领域,这些算法用“类加权的前缀来表示,例如类加权的逻辑回归或简单的加权逻辑回归。
对成本敏感的集成
第二组不同的方法是设计用于过滤或组合来自传统机器学习模型的预测的技术,以便将误分类成本考虑在内。
这些方法被称为“包装器方法”,因为它们包装了一个标准的机器学习分类器。他们也被称为“T2”元学习器“T3”或“T4”集合“T5”,因为他们学习如何使用或组合来自其他模型的预测。
对成本敏感的元学习将现有的对成本不敏感的分类器转换为对成本敏感的分类器,而无需修改它们。因此,它可以被视为一个中间件组件,用于预处理训练数据,或者对成本不敏感的学习算法的输出进行后处理。
——成本敏感学习,《机器学习百科全书》,2010。
也许最简单的方法是使用机器学习模型来预测类别成员的概率,然后在阈值上使用线性搜索,在该阈值下,示例被分配给每个清晰的类别标签,从而最小化错误分类的成本。
这通常被称为“阈值化”或阈值优化,并且更一般地用于二进制分类任务,尽管它可以被容易地修改以最小化成本,而不是特定类型的分类误差度量。
*MetaCost 是一种数据预处理技术,它在训练数据集中重新标记示例,以便最小化成本。
……我们提出了一种有原则的方法,通过在任意分类器周围包装一个成本最小化过程,使其对成本敏感。
——元成本:一种使分类器对成本敏感的通用方法,1999。
在元成本中,首先将分类器的袋装集成拟合到训练数据集中,以识别那些需要重新标记的示例,创建具有重新标记示例的数据集的变换版本,然后丢弃该集成,并使用变换后的数据集来训练分类器模型。
另一个重要领域是考虑成本矩阵的决策树集成的修改,例如装袋和提升算法,最显著的是 AdaBoost 的成本敏感版本,如 AdaCost。
AdaCost 是 AdaBoost 的变体,是一种对成本敏感的误分类 boosting 方法。它使用错误分类的成本来更新连续提升轮的训练分布。
——AdaCost:误分类成本敏感提升,1999。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 阶级不平衡问题:系统研究,2002。
- 归纳概念学习中的成本类型,2000。
- 成本敏感学习的基础,2001。
- 按成本比例示例加权的成本敏感学习,2003。
- 不平衡数据的成本敏感学习方法,2010。
- 元成本:一种使分类器对成本敏感的通用方法,1999。
- AdaCost:误分类成本敏感提升,1999。
书
- 成本敏感学习,机器学习百科,2010。
- 成本敏感型机器学习,2011。
- 第四章成本敏感学习,从不平衡数据集学习,2018。
- 不平衡学习:基础、算法和应用,2013。
文章
摘要
在本教程中,您发现了不平衡分类的成本敏感学习。
具体来说,您了解到:
- 不平衡分类问题通常对假阳性分类错误的重视程度不同于假阴性。
- 成本敏感学习是机器学习的一个子领域,它涉及在训练机器学习算法时明确定义和使用成本。
- 成本敏感技术可以分为三类,包括数据重采样、算法修改和集成方法。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。*
不平衡分类的成本敏感逻辑回归
最后更新于 2020 年 10 月 26 日
逻辑回归不直接支持不平衡分类。
相反,用于拟合逻辑回归模型的训练算法必须被修改以考虑偏斜分布。这可以通过指定用于影响训练期间更新逻辑回归系数的数量的类加权配置来实现。
加权可以对多数类的例子中的错误较少地惩罚模型,而对少数类的例子中的错误较多地惩罚模型。结果是逻辑回归的一个版本,在不平衡分类任务上表现更好,通常被称为成本敏感或加权逻辑回归。
在本教程中,您将发现不平衡分类的成本敏感逻辑回归。
完成本教程后,您将知道:
- 标准逻辑回归如何不支持不平衡分类?
- 如何在拟合系数时用类权重修正逻辑回归来加权模型误差?
- 如何为逻辑回归配置类权重,如何网格搜索不同的类权重配置。
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 更新 2020 年 2 月:修正了重量计算中的错别字。
- 2020 年 10 月更新:修正了余额比例描述中的错别字。
不平衡分类的成本敏感逻辑回归 图片由海军提供,保留部分权利。
教程概述
本教程分为五个部分;它们是:
- 不平衡类别数据集
- 不平衡分类的逻辑回归
- 基于 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=2)
生成后,我们可以总结类分布,以确认数据集是按照我们的预期创建的。
...
# 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=1, weights=[0.99], flip_y=0, random_state=2)
# 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 类不平衡的二进制类别数据集的散点图
接下来,我们可以在数据集上拟合标准逻辑回归模型。
我们将使用重复交叉验证来评估模型,重复三次 10 倍交叉验证。模式表现将使用重复和所有折叠的平均曲线下面积(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: %.3f' % mean(scores))
将这些联系在一起,下面列出了不平衡分类问题的标准逻辑回归的完整例子。
# fit a logistic regression model 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 sklearn.linear_model import LogisticRegression
# 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=2)
# define model
model = LogisticRegression(solver='lbfgs')
# 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: %.3f' % mean(scores))
运行该示例评估不平衡数据集上的标准逻辑回归模型,并报告平均 ROC AUC。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
我们可以看到模型有技巧,实现了 0.5 以上的 ROC AUC,在这种情况下实现了 0.985 的平均得分。
Mean ROC AUC: 0.985
这为标准逻辑回归算法的任何修改提供了比较基准。
不平衡分类的逻辑回归
逻辑回归是二分类任务的有效模型,尽管默认情况下,它在不平衡分类中无效。
可以修改逻辑回归,使其更适合逻辑回归。
使用优化算法拟合逻辑回归算法的系数,该优化算法最小化训练数据集上模型的负对数似然(损失)。
- 将总和 I 最小化为 n-(log(yhat _ I)* y _ I+log(1–yhat _ I)*(1–y _ I))
这包括重复使用模型进行预测,然后在减少模型损失的方向上调整系数。
可以修改给定系数集的损失计算,以考虑类别平衡。
默认情况下,每个类别的误差可以被认为具有相同的权重,比如 1.0。这些权重可以根据每个类别的重要性进行调整。
- 将总和 I 最小化为 n-(w0 * log(yhat _ I)* y _ I+w1 * log(1–yhat _ I)*(1–y _ I))
加权被应用于损失,使得较小的权重值导致较小的误差值,并且反过来,较少更新模型系数。较大的权重值导致较大的误差计算,进而导致模型系数的更多更新。
- 小权重:重要性小,对模型系数更新少。
- 大权重:更重要,对模型系数更新更多。
因此,逻辑回归的修改版本被称为加权逻辑回归、类加权逻辑回归或成本敏感逻辑回归。
权重有时被称为重要性权重。
虽然实现起来很简单,但加权逻辑回归的挑战在于为每个类选择权重。
基于 Sklearn 的加权逻辑回归
Sklearn Python 机器学习库提供了支持类加权的逻辑回归的实现。
后勤分类类提供了可以指定为模型超参数的 class_weight 参数。class_weight 是一个字典,它定义了每个类标签(例如 0 和 1)以及在拟合模型时计算负对数似然时应用的权重。
例如,每个类别 0 和 1 的 1 比 1 权重可以定义如下:
...
# define model
weights = {0:1.0, 1:1.0}
model = LogisticRegression(solver='lbfgs', class_weight=weights)
类别称重可以多种方式定义;例如:
- 领域专长,通过与主题专家交谈确定。
- 调谐,由超参数搜索如网格搜索确定。
- 启发式,使用一般最佳实践指定。
使用类别权重的最佳实践是使用训练数据集中类别分布的倒数。
例如,训练数据集的类分布是少数类与多数类的比例为 1:100。该比率的倒数可以用于多数类的 1 和少数类的 100;例如:
...
# define model
weights = {0:1.0, 1:100.0}
model = LogisticRegression(solver='lbfgs', class_weight=weights)
我们也可以使用分数来定义相同的比率,并获得相同的结果;例如:
...
# define model
weights = {0:0.01, 1:1.0}
model = LogisticRegression(solver='lbfgs', class_weight=weights)
我们可以使用上一节中定义的相同评估过程来评估带有类权重的逻辑回归算法。
我们期望类别加权的逻辑回归比没有任何类别加权的标准逻辑回归表现得更好。
下面列出了完整的示例。
# weighted logistic regression model 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 sklearn.linear_model import LogisticRegression
# 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=2)
# define model
weights = {0:0.01, 1:1.0}
model = LogisticRegression(solver='lbfgs', class_weight=weights)
# 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: %.3f' % mean(scores))
运行该示例准备合成不平衡类别数据集,然后使用重复交叉验证评估逻辑回归的类加权版本。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
报告了平均 ROC AUC 评分,在这种情况下显示出比逻辑回归的未加权版本更好的评分,0.989 比 0.985。
Mean ROC AUC: 0.989
Sklearn 库为类加权提供了最佳实践启发式的实现。
它通过 compute_class_weight()函数实现,计算如下:
- n _ samples/(n _ class * n _ samples _ with _ class)
我们可以在数据集上手动测试这个计算。例如,我们的数据集中有 10,000 个示例,0 类有 9900 个,1 类有 100 个。
类别 0 的权重计算如下:
- 加权= n _ samples/(n _ class * n _ samples _ with _ class)
- 权重= 10000 / (2 * 9900)
- 权重= 10000 / 19800
- 权重= 0.05
类别 1 的权重计算如下:
- 加权= n _ samples/(n _ class * n _ samples _ with _ class)
- 权重= 10000 / (2 * 100)
- 权重= 10000 / 200
- 权重= 50
我们可以通过调用 compute_class_weight() 函数并将 class_weight 指定为“平衡来确认这些计算例如:
# calculate heuristic class weighting
from sklearn.utils.class_weight import compute_class_weight
from sklearn.datasets import make_classification
# generate 2 class 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=2)
# calculate class weighting
weighting = compute_class_weight('balanced', [0,1], y)
print(weighting)
运行该示例,我们可以看到,对于类 0,我们可以实现大约 0.5 的权重,对于类 1,我们可以实现 50 的权重。
这些值与我们的手动计算相匹配。
[ 0.50505051 50\. ]
这些值也与我们上面的启发式计算相匹配,用于反演训练数据集中的类分布比率;例如:
- 0.5:50 == 1:100
通过将 class_weight 参数设置为“平衡”,我们可以将默认的类平衡直接用于logisticreduce类例如:
...
# define model
model = LogisticRegression(solver='lbfgs', class_weight='balanced')
下面列出了完整的示例。
# weighted logistic regression for class imbalance with heuristic weights
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 sklearn.linear_model import LogisticRegression
# 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=2)
# define model
model = LogisticRegression(solver='lbfgs', class_weight='balanced')
# 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: %.3f' % mean(scores))
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
运行该示例给出的平均 ROC AUC 与我们通过手动指定反向类比率获得的相同。
Mean ROC AUC: 0.989
网格搜索加权逻辑回归
使用与训练数据成反比的类权重只是一种启发。
使用不同的类权重可以获得更好的表现,这也将取决于用于评估模型的表现度量的选择。
在本节中,我们将网格搜索一系列不同的加权逻辑回归的类别权重,并发现哪一个导致最佳的 ROC AUC 分数。
我们将对类别 0 和 1 尝试以下权重:
- {0:100,1:1}
- {0:10,1:1}
- {0:1,1:1}
- {0:1,1:10}
- {0:1,1:100}
这些可以定义为网格搜索参数,如下所示:
...
# define grid
balance = [{0:100,1:1}, {0:10,1:1}, {0:1,1:1}, {0:1,1:10}, {0:1,1:100}]
param_grid = dict(class_weight=balance)
我们可以使用重复交叉验证对这些参数执行网格搜索,并使用 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))
将这些联系在一起,下面的示例在不平衡的数据集上搜索五个不同的类别权重进行逻辑回归。
我们可能会认为启发式类加权是表现最好的配置。
# grid search class weights with logistic regression 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 sklearn.linear_model import LogisticRegression
# 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=2)
# define model
model = LogisticRegression(solver='lbfgs')
# define grid
balance = [{0:100,1:1}, {0:10,1:1}, {0:1,1:1}, {0:1,1:10}, {0:1,1:100}]
param_grid = dict(class_weight=balance)
# 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 分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到 1:100 的多数对少数类权重获得了最佳的平均 ROC 分数。这与一般启发式算法的配置相匹配。
探索更严格的类别权重,看看它们对平均 ROC AUC 评分的影响,可能会很有趣。
Best: 0.989077 using {'class_weight': {0: 1, 1: 100}}
0.982498 (0.016722) with: {'class_weight': {0: 100, 1: 1}}
0.983623 (0.015760) with: {'class_weight': {0: 10, 1: 1}}
0.985387 (0.013890) with: {'class_weight': {0: 1, 1: 1}}
0.988044 (0.010384) with: {'class_weight': {0: 1, 1: 10}}
0.989077 (0.006865) with: {'class_weight': {0: 1, 1: 100}}
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 罕见事件数据中的逻辑回归,2001。
- 基于选择样本的选择概率估计,1977。
书
- 从不平衡数据集中学习,2018。
- 不平衡学习:基础、算法和应用,2013。
蜜蜂
- sklearn . utils . class _ weight . compute _ class _ weight API。
- sklearn.linear_model。物流配送应用编程接口。
- sklearn.model_selection。GridSearchCV API 。
摘要
在本教程中,您发现了不平衡分类的成本敏感逻辑回归。
具体来说,您了解到:
- 标准逻辑回归如何不支持不平衡分类?
- 如何在拟合系数时用类权重修正逻辑回归来加权模型误差?
- 如何为逻辑回归配置类权重,如何网格搜索不同的类权重配置。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何为不平衡分类开发成本敏感的神经网络
最后更新于 2020 年 8 月 21 日
深度学习神经网络是一类灵活的机器学习算法,在广泛的问题上表现良好。
使用误差反向传播算法训练神经网络,该算法包括计算模型在训练数据集上产生的误差,并根据这些误差按比例更新模型权重。这种训练方法的局限性在于,每个类的例子都被同等对待,对于不平衡的数据集,这意味着一个类比另一个类更适合模型。
反向传播算法可以被更新,以与类别的重要性成比例地加权错误分类误差,称为加权神经网络或成本敏感神经网络。这使得模型在类分布严重偏斜的数据集中,更关注少数类的例子,而不是多数类的例子。
在本教程中,您将发现用于不平衡分类的加权神经网络。
完成本教程后,您将知道:
- 标准神经网络算法如何不支持不平衡分类?
- 如何修改神经网络训练算法,以便根据类别重要性按比例加权错误分类错误。
- 如何为神经网络配置类权重并评估对模型表现的影响?
用我的新书Python 不平衡分类启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何为不平衡分类开发一个成本敏感的神经网络。新西兰,保留部分权利。
教程概述
本教程分为四个部分;它们是:
- 不平衡类别数据集
- Keras 神经网络模型
- 不平衡分类的深度学习
- 带 Keras 的加权神经网络
不平衡类别数据集
在我们深入研究不平衡分类的神经网络修改之前,让我们首先定义一个不平衡类别数据集。
我们可以使用 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=2, weights=[0.99], flip_y=0, random_state=4)
生成后,我们可以总结类分布,以确认数据集是按照我们的预期创建的。
...
# 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=4)
# 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 类不平衡的二进制类别数据集的散点图
Keras 神经网络模型
接下来,我们可以在数据集上拟合标准神经网络模型。
首先,我们可以定义一个函数来创建合成数据集,并将其分成单独的训练和测试数据集,每个数据集有 5000 个示例。
# prepare train and test dataset
def prepare_data():
# generate 2d classification 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=4)
# split into train and test
n_train = 5000
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
return trainX, trainy, testX, testy
可以使用 Keras 深度学习库定义多层感知器神经网络。我们将定义一个神经网络,它需要两个输入变量,有一个包含 10 个节点的隐藏层,然后是一个预测类标签的输出层。
我们将在隐藏层使用流行的 ReLU 激活函数,在输出层使用 sigmoid 激活函数,以确保预测的概率在[0,1]范围内。该模型将使用具有默认学习率的随机梯度下降进行拟合,并根据交叉熵损失进行优化。
网络结构和超参数没有针对问题进行优化;相反,当训练算法后来被修改以处理倾斜的类分布时,网络提供了比较的基础。
下面的 define_model() 函数定义并返回模型,以网络的输入变量个数为自变量。
# define the neural network model
def define_model(n_input):
# define model
model = Sequential()
# define first hidden layer and visible layer
model.add(Dense(10, input_dim=n_input, activation='relu', kernel_initializer='he_uniform'))
# define output layer
model.add(Dense(1, activation='sigmoid'))
# define loss and optimizer
model.compile(loss='binary_crossentropy', optimizer='sgd')
return model
一旦定义了模型,它就可以适合训练数据集。
我们将为 100 个训练阶段的模型设定默认的批次大小。
...
# fit model
model.fit(trainX, trainy, epochs=100, verbose=0)
一旦拟合,我们可以使用该模型对测试数据集进行预测,然后使用 ROC AUC 分数评估预测。
...
# make predictions on the test dataset
yhat = model.predict(testX)
# evaluate the ROC AUC of the predictions
score = roc_auc_score(testy, yhat)
print('ROC AUC: %.3f' % score)
将这些联系在一起,下面列出了在不平衡类别数据集上拟合标准神经网络模型的完整示例。
# standard neural network on an imbalanced classification dataset
from sklearn.datasets import make_classification
from sklearn.metrics import roc_auc_score
from keras.layers import Dense
from keras.models import Sequential
# prepare train and test dataset
def prepare_data():
# generate 2d classification 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=4)
# split into train and test
n_train = 5000
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
return trainX, trainy, testX, testy
# define the neural network model
def define_model(n_input):
# define model
model = Sequential()
# define first hidden layer and visible layer
model.add(Dense(10, input_dim=n_input, activation='relu', kernel_initializer='he_uniform'))
# define output layer
model.add(Dense(1, activation='sigmoid'))
# define loss and optimizer
model.compile(loss='binary_crossentropy', optimizer='sgd')
return model
# prepare dataset
trainX, trainy, testX, testy = prepare_data()
# define the model
n_input = trainX.shape[1]
model = define_model(n_input)
# fit model
model.fit(trainX, trainy, epochs=100, verbose=0)
# make predictions on the test dataset
yhat = model.predict(testX)
# evaluate the ROC AUC of the predictions
score = roc_auc_score(testy, yhat)
print('ROC AUC: %.3f' % score)
运行该示例评估不平衡数据集上的神经网络模型,并报告 ROC AUC。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,模型实现了大约 0.949 的 ROC AUC。这表明,与 ROC AUC 为 0.5 的朴素分类器相比,该模型具有一些技巧。
ROC AUC: 0.949
这为标准神经网络训练算法的任何修改的比较提供了基线。
不平衡分类的深度学习
神经网络模型通常使用误差算法的反向传播来训练。
这包括使用模型的当前状态为训练集示例进行预测,计算预测的误差,然后使用误差更新模型权重,并将误差的信用分配给从输出层向后到输入层的不同节点和层。
给定对错误分类错误的平衡关注,大多数标准神经网络算法不太适合具有严重偏斜分类分布的数据集。
现有的深度学习算法大多没有考虑数据不平衡问题。因此,这些算法可以在平衡数据集上很好地执行,而在不平衡数据集上它们的表现不能得到保证。
——在不平衡数据集上训练深度神经网络,2016。
可以修改这个训练过程,使得一些例子比其他例子有更多或更少的误差。
也可以通过改变被最小化的误差函数来考虑错误分类成本。反向传播学习过程应该使错误分类成本最小化,而不是最小化平方误差。
——神经网络成本敏感学习,1998。
实现这一点的最简单的方法是基于示例的类别对其使用固定的错误分数权重,其中对于更重要类别中的示例,预测错误增加,而对于不太重要类别中的示例,预测错误减少或保持不变。
……成本敏感的学习方法基于与错误分类样本相关的成本考虑来解决数据不平衡问题。特别是,它为样本的错误分类分配了不同的成本值。
——在不平衡数据集上训练深度神经网络,2016。
可以对少数类中的那些示例应用较大的误差权重,因为它们在不平衡分类问题中通常比多数类中的示例更重要。
- 大权重:分配给小众类的例子。
- 小权重:分配给多数类的例子。
对神经网络训练算法的这种修改被称为加权神经网络或成本敏感神经网络。
通常,在定义成本或用于成本敏感学习的“T0”权重时,需要特别注意。然而,对于只关注错误分类的不平衡分类,加权可以使用在训练数据集中观察到的类别分布的倒数。
带 Keras 的加权神经网络
Keras Python 深度学习库提供支持类加权。
用于训练 Keras 神经网络模型的 fit()函数采用了一个名为 class_weight 的参数。此参数允许您定义一个字典,将类整数值映射到应用于每个类的重要性。
此函数用于训练每种不同类型的神经网络,包括多层感知器、卷积神经网络和递归神经网络,因此类别加权功能适用于所有这些网络类型。
例如,每个类别 0 和 1 的 1 比 1 权重可以定义如下:
...
# fit model
weights = {0:1, 1:1}
history = model.fit(trainX, trainy, class_weight=weights, ...)
类别称重可以多种方式定义;例如:
- 领域专长,通过与主题专家交谈确定。
- 调谐,由超参数搜索如网格搜索确定。
- 启发式,使用一般最佳实践指定。
使用类别权重的最佳实践是使用训练数据集中类别分布的倒数。
例如,测试数据集的类分布是少数类与多数类的比例为 1:100。该比率的倒数可以与多数类的 1 和少数类的 100 一起使用,例如:
...
# fit model
weights = {0:1, 1:100}
history = model.fit(trainX, trainy, class_weight=weights, ...)
代表相同比率的分数没有相同的效果。例如,对多数类和少数类分别使用 0.01 和 0.99 可能会导致比使用 1 和 100 更差的表现(在这种情况下确实如此)。
...
# fit model
weights = {0:0.01, 1:0.99}
history = model.fit(trainX, trainy, class_weight=weights, ...)
原因是从多数阶级和少数阶级提取的例子的误差减少了。此外,多数类的误差减少被显著地缩小到非常小的数字,这些数字可能对模型权重有有限的影响或者只有非常小的影响。
因此,建议使用这样的整数来表示类别权重,例如 1 表示无变化,100 表示类别 1 的错误分类错误,其影响或损失是类别 0 的错误分类错误的 100 倍。
我们可以使用上一节中定义的相同评估过程,使用类权重来评估神经网络算法。
我们期望神经网络的类加权版本比没有任何类加权的训练算法版本表现得更好。
下面列出了完整的示例。
# class weighted neural network on an imbalanced classification dataset
from sklearn.datasets import make_classification
from sklearn.metrics import roc_auc_score
from keras.layers import Dense
from keras.models import Sequential
# prepare train and test dataset
def prepare_data():
# generate 2d classification 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=4)
# split into train and test
n_train = 5000
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
return trainX, trainy, testX, testy
# define the neural network model
def define_model(n_input):
# define model
model = Sequential()
# define first hidden layer and visible layer
model.add(Dense(10, input_dim=n_input, activation='relu', kernel_initializer='he_uniform'))
# define output layer
model.add(Dense(1, activation='sigmoid'))
# define loss and optimizer
model.compile(loss='binary_crossentropy', optimizer='sgd')
return model
# prepare dataset
trainX, trainy, testX, testy = prepare_data()
# get the model
n_input = trainX.shape[1]
model = define_model(n_input)
# fit model
weights = {0:1, 1:100}
history = model.fit(trainX, trainy, class_weight=weights, epochs=100, verbose=0)
# evaluate model
yhat = model.predict(testX)
score = roc_auc_score(testy, yhat)
print('ROC AUC: %.3f' % score)
运行该示例准备合成的不平衡类别数据集,然后评估神经网络训练算法的类加权版本。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
报告了 ROC AUC 分数,在这种情况下显示出比训练算法的未加权版本更好的分数,或者与大约 0.949 相比大约 0.973。
ROC AUC: 0.973
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 神经网络的成本敏感学习,1998。
- 在不平衡数据集上训练深度神经网络,2016。
书
- 从不平衡数据集中学习,2018。
- 不平衡学习:基础、算法和应用,2013。
蜜蜂
摘要
在本教程中,您发现了用于不平衡分类的加权神经网络。
具体来说,您了解到:
- 标准神经网络算法如何不支持不平衡分类?
- 如何修改神经网络训练算法,以便根据类别重要性按比例加权错误分类错误。
- 如何为神经网络配置类权重并评估对模型表现的影响?
你有什么问题吗? 在下面的评论中提问,我会尽力回答。