不平衡数据集是指类别分布严重倾斜的数据集,例如少数类别与多数类别的比例为 1:100 或 1:1000。
训练数据集中这种偏差会影响许多机器学习算法,导致某些算法完全忽略少数类别。这是一个问题,因为通常情况下,少数类别的预测最为重要。
解决类别不平衡问题的一种方法是随机重采样训练数据集。随机重采样不平衡数据集的两种主要方法是删除多数类别中的示例(称为欠采样)和复制少数类别中的示例(称为过采样)。
在本教程中,您将了解不平衡分类的随机过采样和欠采样。
完成本教程后,您将了解:
- 随机重采样为不平衡数据集提供了一种重新平衡类别分布的朴素技术。
- 随机过采样会复制训练数据集中的少数类别示例,并可能导致某些模型过拟合。
- 随机欠采样会删除多数类别中的示例,并可能导致丢失对模型宝贵的信息。
通过我的新书《使用 Python 进行不平衡分类》启动您的项目,包括分步教程和所有示例的 Python 源代码文件。
让我们开始吧。
- 2021 年 1 月更新:更新了 API 文档链接。

不平衡分类的随机过采样和欠采样
照片由 RichardBH 拍摄,保留部分权利。
教程概述
本教程分为五个部分;它们是:
- 随机重采样不平衡数据集
- Imbalanced-Learn 库
- 随机过采样不平衡数据集
- 随机欠采样不平衡数据集
- 结合随机过采样和欠采样
随机重采样不平衡数据集
重采样涉及创建训练数据集的新转换版本,其中选定的示例具有不同的类别分布。
这是一种简单有效的不平衡分类问题策略。
应用重采样策略以获得更平衡的数据分布是解决不平衡问题的有效方案。
— 不平衡分布下的预测建模调查,2015 年。
最简单的策略是随机选择转换数据集的示例,称为随机重采样。
不平衡分类的随机重采样主要有两种方法:过采样和欠采样。
- 随机过采样:随机复制少数类别中的示例。
- 随机欠采样:随机删除多数类别中的示例。
随机过采样涉及从少数类别中随机(有放回地)选择示例,并将它们添加到训练数据集中。随机欠采样涉及从多数类别中随机选择示例,并将其从训练数据集中删除。
在随机欠采样中,多数类别实例被随机丢弃,直到达到更平衡的分布。
— 第 45 页,《不平衡学习:基础、算法和应用》,2013 年。
这两种方法都可以重复,直到在训练数据集中达到所需的类别分布,例如类别之间的均匀划分。
它们被称为“朴素重采样”方法,因为它们不假设数据,也不使用启发式方法。这使得它们易于实现且执行速度快,这对于非常大和复杂的数据集来说是理想的。
这两种技术都可以用于两类(二元)分类问题和具有一个或多个多数或少数类的多类分类问题。
重要的是,类别分布的更改仅应用于训练数据集。目的是影响模型的拟合。重采样不应用于用于评估模型性能的测试或保留数据集。
通常,这些朴素方法可能是有效的,尽管这取决于数据集和所涉及模型的具体情况。
让我们仔细研究每种方法以及如何在实践中使用它们。
Imbalanced-Learn 库
在这些示例中,我们将使用 imbalanced-learn Python 库提供的实现,该库可以通过 pip 安装,如下所示:
1 |
sudo pip install imbalanced-learn |
您可以通过打印已安装库的版本来确认安装成功。
1 2 3 |
# 检查版本号 import imblearn print(imblearn.__version__) |
运行示例将打印已安装库的版本号;例如
1 |
0.5.0 |
想要开始学习不平衡分类吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
随机过采样不平衡数据集
随机过采样涉及从少数类别中随机复制示例并将其添加到训练数据集中。
从训练数据集中随机有放回地选择示例。这意味着少数类别中的示例可以被多次选择并添加到新的“更平衡”的训练数据集中;它们从原始训练数据集中选择,添加到新的训练数据集中,然后返回或“替换”到原始数据集中,从而允许它们再次被选择。
这种技术对于那些受倾斜分布影响的机器学习算法以及对于给定类别,多个重复示例可以影响模型拟合的情况可能有效。这可能包括迭代学习系数的算法,例如使用随机梯度下降的人工神经网络。它还可能影响寻求良好数据分割的模型,例如支持向量机和决策树。
调整目标类别分布可能很有用。在某些情况下,对于严重不平衡的数据集寻求平衡分布可能会导致受影响的算法过拟合少数类别,从而导致泛化误差增加。其结果可能是训练数据集上的性能更好,但在保留或测试数据集上的性能更差。
……随机过采样可能会增加过拟合的可能性,因为它会精确复制少数类别示例。这样,例如,符号分类器可能会构建表面上准确但实际上只覆盖一个复制示例的规则。
— 第 83 页,《从不平衡数据集中学习》,2018 年。
因此,为了深入了解该方法的影响,最好在过采样后监控训练和测试数据集上的性能,并将结果与原始数据集上的相同算法进行比较。
少数类别示例数量的增加,特别是如果类别倾斜严重,还可能导致拟合模型时计算成本显著增加,特别是考虑到模型在训练数据集中一次又一次地看到相同的示例。
……在随机过采样中,将随机选择的少数类别示例副本添加到数据中。这可能会增加过拟合的可能性,特别是对于较高的过采样率。此外,它可能会降低分类器性能并增加计算工作量。
— 不平衡分布下的预测建模调查,2015 年。
随机过采样可以使用 RandomOverSampler 类实现。
该类可以定义并接受一个 sampling_strategy 参数,该参数可以设置为“minority”以自动平衡少数类别与多数类别。
例如:
1 2 3 |
... # 定义过采样策略 oversample = RandomOverSampler(sampling_strategy='minority') |
这意味着如果多数类别有 1,000 个示例,少数类别有 100 个示例,则此策略将对少数类别进行过采样,使其也拥有 1,000 个示例。
可以指定一个浮点值来表示转换数据集中少数类别与多数类别示例的比例。例如
1 2 3 |
... # 定义过采样策略 oversample = RandomOverSampler(sampling_strategy=0.5) |
这将确保对于二元分类问题,少数类别被过采样到拥有多数类别一半的示例数量。这意味着如果多数类别有 1,000 个示例,少数类别有 100 个示例,则转换后的数据集将有 500 个少数类别示例。
该类类似于 scikit-learn 转换对象,因为它在数据集上拟合,然后用于生成新的或转换后的数据集。与 scikit-learn 转换不同,它将改变数据集中的示例数量,而不仅仅是值(如 scaler)或特征数量(如投影)。
例如,它可以通过调用 fit_sample() 函数一步拟合和应用。
1 2 3 |
... # 拟合并应用转换 X_over, y_over = oversample.fit_resample(X, y) |
我们可以在一个简单的合成二元分类问题上演示这一点,该问题具有 1:100 的类别不平衡。
1 2 3 |
... # 定义数据集 X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0) |
定义数据集并执行随机过采样以平衡类别分布的完整示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 随机过采样以平衡类别分布的示例 from collections import Counter from sklearn.datasets import make_classification from imblearn.over_sampling import RandomOverSampler # 定义数据集 X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0) # 总结类别分布 print(Counter(y)) # 定义过采样策略 oversample = RandomOverSampler(sampling_strategy='minority') # 拟合并应用转换 X_over, y_over = oversample.fit_resample(X, y) # 总结类别分布 print(Counter(y_over)) |
运行示例首先创建数据集,然后总结类别分布。我们可以看到多数类别中有近 1 万个示例,少数类别中有 100 个示例。
然后定义随机过采样转换以平衡少数类别,然后将其拟合并应用于数据集。报告转换后数据集的类别分布,显示现在少数类别与多数类别具有相同数量的示例。
1 2 |
Counter({0: 9900, 1: 100}) Counter({0: 9900, 1: 9900}) |
此转换可用作 Pipeline 的一部分,以确保它仅作为 k 折交叉验证中每个分割的一部分应用于训练数据集。
不能使用传统的 scikit-learn Pipeline;相反,可以使用 imbalanced-learn 库的 Pipeline。例如
1 2 3 4 |
... # 流水线 steps = [('over', RandomOverSampler()), ('model', DecisionTreeClassifier())] pipeline = Pipeline(steps=steps) |
下面的示例提供了一个完整的示例,用于评估具有 1:100 类别分布的不平衡数据集上的决策树。
该模型使用重复的 10 折交叉验证进行评估,重复三次,并且在每个折叠内分别对训练数据集执行过采样,从而确保不会发生数据泄漏,就像在交叉验证之前执行过采样可能发生的情况一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 评估具有随机过采样的决策树的示例 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 # 定义数据集 X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0) # 定义流水线 steps = [('over', RandomOverSampler()), ('model', DecisionTreeClassifier())] pipeline = Pipeline(steps=steps) # 评估流水线 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) scores = cross_val_score(pipeline, X, y, scoring='f1_micro', cv=cv, n_jobs=-1) score = mean(scores) print('F1 Score: %.3f' % score) |
运行示例评估了带有过采样的不平衡数据集上的决策树模型。
所选模型和重采样配置是任意的,旨在提供一个模板,您可以使用它来测试您的数据集和学习算法的欠采样,而不是最佳地解决合成数据集。
注意:由于算法或评估过程的随机性或数值精度的差异,您的结果可能会有所不同。请考虑多次运行示例并比较平均结果。
使用了默认的过采样策略,该策略平衡了少数类别与多数类别。报告了在每个折叠和每次重复中平均的 F1 分数。
1 |
F1 Score: 0.990 |
现在我们熟悉了过采样,让我们来看看欠采样。
随机欠采样不平衡数据集
随机欠采样涉及随机选择多数类中的示例以从训练数据集中删除。
这会减少转换后的训练数据集中多数类示例的数量。这个过程可以重复,直到达到所需的类分布,例如每个类的示例数量相等。
这种方法可能更适合那些存在类不平衡,但在少数类中有足够多的示例,从而可以拟合出有用模型的训练数据集。
欠采样的一个限制是,多数类中的示例被删除,而这些示例可能对拟合鲁棒决策边界很有用、很重要,甚至至关重要。鉴于示例是随机删除的,无法检测或保留多数类中“好”或信息更丰富的示例。
……在随机欠采样中,(可能)会丢弃大量数据。 […] 这可能是一个高度问题,因为这些数据的丢失会使少数类和多数类实例之间的决策边界更难学习,从而导致分类性能下降。
— 第 45 页,《不平衡学习:基础、算法和应用》,2013 年。
随机欠采样技术可以使用 RandomUnderSampler imbalanced-learn 类实现。
该类的用法与上一节中的 RandomOverSampler 类相同,只是策略影响多数类而不是少数类。例如,将 sampling_strategy 参数设置为“majority”将对多数类进行欠采样,该多数类由具有最多示例的类决定。
1 2 3 |
... # 定义欠采样策略 undersample = RandomUnderSampler(sampling_strategy='majority') |
例如,一个多数类别有 1,000 个示例,少数类别有 100 个示例的数据集将被欠采样,使得转换后的训练数据集中两个类别都包含 100 个示例。
我们还可以将 sampling_strategy 参数设置为浮点值,这将是相对于少数类别的百分比,具体来说是少数类别中的示例数量除以多数类别中的示例数量。例如,如果我们将 sampling_strategy 设置为 0.5,在一个多数类别有 1,000 个示例、少数类别有 100 个示例的不平衡数据集中,那么转换后的数据集中多数类别将有 200 个示例(或 100/200 = 0.5)。
1 2 3 |
... # 定义欠采样策略 undersample = RandomUnderSampler(sampling_strategy=0.5) |
这可能是更优选的方法,以确保生成的数据集既足够大,可以拟合一个合理的模型,又不会丢弃太多来自多数类的有用信息。
在随机欠采样中,可以尝试通过随机删除 90 个多数类实例来创建平衡的类分布。生成的数据集将包含 20 个实例:10 个(随机剩余的)多数类实例和(原始的)10 个少数类实例。
— 第 45 页,《不平衡学习:基础、算法和应用》,2013 年。
然后可以通过调用 fit_resample() 函数并将未转换的数据集作为参数传递,一步拟合并将转换应用于数据集。
1 2 3 |
... # 拟合并应用转换 X_over, y_over = undersample.fit_resample(X, y) |
我们可以在一个具有 1:100 类别不平衡的数据集上演示这一点。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 随机欠采样以平衡类别分布的示例 from collections import Counter from sklearn.datasets import make_classification from imblearn.under_sampling import RandomUnderSampler # 定义数据集 X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0) # 总结类别分布 print(Counter(y)) # 定义欠采样策略 undersample = RandomUnderSampler(sampling_strategy='majority') # 拟合并应用转换 X_over, y_over = undersample.fit_resample(X, y) # 总结类别分布 print(Counter(y_over)) |
运行示例首先创建数据集并报告不平衡的类别分布。
转换在数据集上拟合并应用,并报告新的类别分布。我们可以看到,多数类被欠采样以具有与少数类相同的示例数量。
需要根据判断和经验结果来确定只有 200 个示例的训练数据集是否足以训练模型。
1 2 |
Counter({0: 9900, 1: 100}) Counter({0: 100, 1: 100}) |
此欠采样转换也可用于 Pipeline,就像上一节中的过采样转换一样。
这允许仅使用 k 折交叉验证等评估方案将转换应用于训练数据集,从而避免模型评估中的任何数据泄漏。
1 2 3 4 |
... # 定义流水线 steps = [('under', RandomUnderSampler()), ('model', DecisionTreeClassifier())] pipeline = Pipeline(steps=steps) |
我们可以定义一个在不平衡分类数据集上拟合决策树的示例,其中在重复的 10 折交叉验证的每个分割上对训练数据集应用欠采样转换。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 评估具有随机欠采样的决策树的示例 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.under_sampling import RandomUnderSampler # 定义数据集 X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0) # 定义流水线 steps = [('under', RandomUnderSampler()), ('model', DecisionTreeClassifier())] pipeline = Pipeline(steps=steps) # 评估流水线 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) scores = cross_val_score(pipeline, X, y, scoring='f1_micro', cv=cv, n_jobs=-1) score = mean(scores) print('F1 Score: %.3f' % score) |
运行示例评估了带有欠采样的不平衡数据集上的决策树模型。
所选模型和重采样配置是任意的,旨在提供一个模板,您可以使用它来测试您的数据集和学习算法的欠采样,而不是最佳地解决合成数据集。
注意:由于算法或评估过程的随机性或数值精度的差异,您的结果可能会有所不同。请考虑多次运行示例并比较平均结果。
使用了默认的欠采样策略,该策略平衡了多数类别与少数类别。报告了在每个折叠和每次重复中平均的 F1 分数。
1 |
F1 Score: 0.889 |
结合随机过采样和欠采样
结合随机过采样和欠采样可能会取得有趣的结果。
例如,可以对少数类别应用适量的过采样以改善对这些示例的偏差,同时对多数类别应用适量的欠采样以减少对该类别的偏差。
这可能比单独执行其中一种技术能带来整体性能的提升。
例如,如果我们有一个 1:100 类别分布的数据集,我们可能会首先应用过采样以通过复制少数类别的示例将比例增加到 1:10,然后应用欠采样以通过删除多数类别的示例将比例进一步提高到 1:2。
这可以通过使用 imbalanced-learn 实现,方法是使用 RandomOverSampler 并将 sampling_strategy 设置为 0.1 (10%),然后使用 RandomUnderSampler 并将 sampling_strategy 设置为 0.5 (50%)。例如
1 2 3 4 5 6 7 8 9 |
... # 定义过采样策略 over = RandomOverSampler(sampling_strategy=0.1) # 拟合并应用转换 X, y = over.fit_resample(X, y) # 定义欠采样策略 under = RandomUnderSampler(sampling_strategy=0.5) # 拟合并应用转换 X, y = under.fit_resample(X, y) |
我们可以在一个具有 1:100 类别分布的合成数据集上演示这一点。完整示例如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 结合随机过采样和欠采样处理不平衡数据的示例 from collections import Counter from sklearn.datasets import make_classification from imblearn.over_sampling import RandomOverSampler from imblearn.under_sampling import RandomUnderSampler # 定义数据集 X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0) # 总结类别分布 print(Counter(y)) # 定义过采样策略 over = RandomOverSampler(sampling_strategy=0.1) # 拟合并应用转换 X, y = over.fit_resample(X, y) # 总结类别分布 print(Counter(y)) # 定义欠采样策略 under = RandomUnderSampler(sampling_strategy=0.5) # 拟合并应用转换 X, y = under.fit_resample(X, y) # 总结类别分布 print(Counter(y)) |
运行示例首先创建合成数据集并总结类别分布,显示近似 1:100 的类别分布。
然后应用过采样,将分布从大约 1:100 增加到大约 1:10。最后,应用欠采样,进一步将类别分布从 1:10 改善到大约 1:2。
1 2 3 |
Counter({0: 9900, 1: 100}) Counter({0: 9900, 1: 990}) Counter({0: 1980, 1: 990}) |
在评估模型时,我们可能也希望应用这种混合方法,使用 k 折交叉验证。
这可以通过使用带有转换序列的 Pipeline 并以正在评估的模型结尾来实现;例如
1 2 3 4 5 6 |
... # 定义流水线 over = RandomOverSampler(sampling_strategy=0.1) under = RandomUnderSampler(sampling_strategy=0.5) steps = [('o', over), ('u', under), ('m', DecisionTreeClassifier())] pipeline = Pipeline(steps=steps) |
我们可以使用决策树模型在相同的合成数据集上演示这一点。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 评估具有随机过采样和欠采样的模型的示例 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 # 定义数据集 X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0) # 定义流水线 over = RandomOverSampler(sampling_strategy=0.1) under = RandomUnderSampler(sampling_strategy=0.5) steps = [('o', over), ('u', under), ('m', DecisionTreeClassifier())] pipeline = Pipeline(steps=steps) # 评估流水线 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) scores = cross_val_score(pipeline, X, y, scoring='f1_micro', cv=cv, n_jobs=-1) score = mean(scores) print('F1 Score: %.3f' % score) |
运行示例评估了使用重复 k 折交叉验证的决策树模型,其中训练数据集首先使用过采样进行转换,然后使用欠采样进行转换,对每次分割和重复操作进行。报告了在每个折叠和每次重复中平均的 F1 分数。
注意:由于算法或评估过程的随机性或数值精度的差异,您的结果可能会有所不同。请考虑多次运行示例并比较平均结果。
所选模型和重采样配置是任意的,旨在提供一个模板,您可以使用它来测试您的数据集和学习算法的欠采样,而不是最佳地解决合成数据集。
1 |
F1 Score: 0.985 |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
书籍
- 第 5 章 数据级别预处理方法,《从不平衡数据集中学习》,2018 年。
- 第 3 章 不平衡数据集:从采样到分类器,《不平衡学习:基础、算法和应用》,2013 年。
论文
- 一项关于平衡机器学习训练数据的几种方法行为的研究, 2004.
- 不平衡分布下预测建模的调查, 2015.
API
- Imbalanced-Learn 文档.
- imbalanced-learn,GitHub.
- imblearn.over_sampling.RandomOverSampler API.
- imblearn.pipeline.Pipeline API.
- imblearn.under_sampling.RandomUnderSampler API.
文章
总结
在本教程中,您了解了不平衡分类的随机过采样和欠采样。
具体来说,你学到了:
- 随机重采样为不平衡数据集提供了一种重新平衡类别分布的朴素技术。
- 随机过采样会复制训练数据集中的少数类别示例,并可能导致某些模型过拟合。
- 随机欠采样会删除多数类别中的示例,并可能导致丢失对模型宝贵的信息。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
您好,过采样与加权损失在增加稀有类别训练方面的表现如何?有做过实验测试吗?
这因问题而异。
您能做的最好的事情是在您的数据集上使用受控实验来发现哪种方法效果最好。
你好 Jason,
我正在努力理解以下示例。
我对第一段代码感到困惑。在我看来,两个示例中的 cv = 5 都是一样的。结果也一样。那么它们是一样的吗?有什么区别(对我来说没有区别)。
scores = cross_val_score(xgbr, xtrain,ytrain,cv=5)
print(“Mean cross-validation score: %.2f” % scores.mean())
平均交叉验证分数:0.87
# k 折交叉验证方法可以如下检查。
kfold = KFold(n_splits=5, shuffle=True)
kf_cv_scores = cross_val_score(xgbr, xtrain, ytrain, cv=kfold )
print(“K-fold CV average score: %.2f” % kf_cv_scores.mean())
K 折交叉验证平均分数:0.87
谢谢,
Marco
两者看起来都在做同样的事情。
嗨
在尝试评估随机过采样和欠采样的模型示例时,我将过采样和欠采样的顺序更改如下:
steps = [(‘u’, under), (‘o’, over), (‘m’, DecisionTreeClassifier())]
然后 F1 分数变为 nan,并出现以下警告:
FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details
ValueError: The specified ratio required to remove samples from the minority class while trying to generate new samples. Please increase the ratio.
你知道为什么吗?
谢谢
不,也许可以实验/调查来发现答案?
我早期也收到了同样的消息;通常这是因为达到指定比率需要欠采样而不是过采样。请检查 a) 开始时少数类别中的实例是否多于预期,b) 您已经使用不同的技术对数据进行了过采样,并且指定的步骤是在此之后。
交换顺序后得到 nan,请尝试此 pipeline.fit(X,y),然后您会得到错误信息,看来您需要更改比率。这是我得到的信息
ValueError: The specified ratio required to remove samples from the minority class while trying to generate new samples. Please increase the ratio.
嗨
我将随机过采样应用于我的数据集,因为它具有不平衡分布,采样策略为“minority”。我正在处理一个多类别分类问题,它有 22 个类别。在训练随机森林模型后,我使用它进行预测。
根据分类报告,模型的准确率非常低(0.44),并且总是对于 2 个类别的精确率和召回率很高,对于 5 个类别它们是中等,对于其余类别,精确率和召回率都是 0.0。
我能知道我这里做错了什么吗?
到目前为止,我基本上已经,
1. 填充缺失值
2. 应用独热编码
3. 执行 train_test_split
4. 对训练数据应用随机过采样
5. 训练模型
6. 选择模型
7. 进行预测
谢谢
San
忽略准确率
https://machinelearning.org.cn/failure-of-accuracy-for-imbalanced-class-distributions/
尝试一系列模型和不平衡学习技术,并发现哪种方法对您的数据集效果最好。受控实验是唯一的出路。
嗨
类别的精确率和召回率现在略有提高。我的数据集有 6 个少数类别,这些类别只有 1 或 2 个实例。在应用随机过采样后,我注意到其中一个少数类别的实例从 1 增加到 56,而所有其他少数类别保持不变。少数类别的精确率和召回率仍然为 0.0。
此外,我无法应用 SMOTE 或任何其他与 SMOTE 相关的技术,因为我收到此错误 ValueError: Expected n_neighbors <= n_samples, but n_samples = 1, n_neighbors = 6。因为我的数据集中有一些类别少于 6 个实例。
我想提高模型的整体性能,包括那些少数类别。您能给我一个解决这个问题的方法吗?
谢谢
San
干得不错。
我想知道您是否可以删除只有 6 个示例的类别?听起来数据不够。
您好,有些问题
1. 我有一个目标不平衡的数据集。在不重采样的情况下,使用 XGBClassifier,我得到了 0.94 的 F1_score。如果我过采样,使用基本方法或 SMOTE(速度超慢),我得到了 0.92。这是否意味着我不需要过采样,或者它仍然有益?
2. 我在数据分割后进行了过采样。如果在分割前进行过采样,理论上这可能会导致过拟合。但是,如果我在 XGBoost 中使用 early_stopping 来防止过拟合,那么这是否会抵消在数据分割前进行过采样的过拟合问题?
谢谢
您好 Joe...以下资源可能有助于澄清
https://machinelearning.org.cn/smote-oversampling-for-imbalanced-classification/
嗨,Jason,
我明白随机过采样会导致过拟合。但我无法从数学上理解在训练过程中这是如何发生的。您能否对此进行更详细的解释。
提前感谢。
当模型在训练数据中存在重复数据时,它们可能会过拟合,因为它们会过度重视这些示例,从而以增加泛化误差为代价。
感谢您的回复,Jason。我明白损失会更倾向于重复样本,从而使学习到的权重产生偏差。
您还能帮助我理解哪些类别的模型会受到类别不平衡的影响,以及为什么它们只预测多数类别而不预测少数类别。我凭直觉理解这一点,但正在寻找数学解释。
谢谢!!
感谢您的建议。我将来可能会准备一些东西。
谢谢Jason!!
不客气。
您好 Jason Brownie,
感谢您精彩的课程,它们很容易理解。您能否突出说明您在其中提到特定类别为少数类的行,我的意思是,在多标签分类问题中,如何提及一个以上类别不平衡?
提前感谢。
默认情况下,类别 0 是多数类别,类别 1 是少数类别。
是的,您可以为 sampling_strategy 参数指定一个字典,其中包含过采样每个类别的百分比。
https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.SMOTE.html
您好,感谢您的文章。
将过采样和欠采样应用于 1:1000 二进制类别分布的数据集是否可能反而会降低模型的性能?我使用精确率-召回率曲线下面积进行评分,分类器包括:KNearestNeighbors、随机森林、逻辑回归、随机梯度下降、线性 SVM,并且所有这些分类器都出现了这种情况。
是的,这是可能的。
嗨
感谢这篇文章。
我可以使用其中一种相似性度量技术来对多数数据进行欠采样吗?
您具体会怎么做?
我的意思是,我们不进行随机重采样,而是找到多数类别中最相似的实例(使用相似性度量),并将其删除,直到与少数类别相等。
是的,这是一种欠采样类型,请参阅此处
https://machinelearning.org.cn/data-sampling-methods-for-imbalanced-classification/
您好 Jason,我们应该在测试集上应用采样技术,还是应该保持不变以代表实际的类别分布?
我宁愿保持不变,因为测试集应该反映你在现实生活中的所见。但如果你有理由这样做(例如,想专注于罕见情况),你可以自由地这样做。
谢谢 Jason。
一个问题,如果我们进行随机欠采样或过采样(甚至 SMOTE),准确率是否会给我们任何启发?或者换句话说,在随机过采样/欠采样后,我们是否需要计算准确率?
我没有找到任何关于随机过/欠采样与召回率、精确率或 F1 等其他指标之间联系的文献。
采样仅应用于训练集,不应用于测试集。它不会直接影响指标,只会通过模型的性能间接影响。
推荐仔细选择一个指标,这个框架会帮助您
https://machinelearning.org.cn/tour-of-evaluation-metrics-for-imbalanced-classification/
你好,
我正在处理一个二元分类问题,我的数据集非常不平衡(43200 对 400)。我使用了上/下采样(尝试了不同的重采样方法)来平衡我的数据集。
如果我先重采样数据然后将其分割成训练集和测试集,一些机器学习模型(主要是基于树的模型)的性能很好。但是,如果我只重采样训练集然后在“未重采样”的集合上进行测试,机器学习模型的性能就会非常差。
该项目的目标是找到数据集中可用的特征中的优秀预测因子,以及这些特征如何影响模型预测目标。我为此目的使用 SHAP 值。
我正在处理观测数据,无法获得更多数据。
您有什么建议?
您好 Sara...感谢您的提问。
抱歉,我无法帮助你完成你的项目。
我很乐意帮忙,但我没有能力参与你的项目到你需要的程度或能做好工作的程度。
我相信你能理解我的立场,因为我每天都会收到许多项目帮助请求。
尽管如此,我很乐意回答你关于机器学习的任何具体问题。
你好,
谢谢你的回复。
我的问题具体是关于重采样部分。
我的目标是找到性能足够好的模型,然后应用 SHAP。在评论中您提到不应触碰测试集。在我的情况下,是否可以在重采样测试集上测试模型?
您好 Sara...我的建议是永远不要对数据进行重采样并用于测试。以下内容可能对您有帮助
https://machinelearning.org.cn/train-test-split-for-evaluating-machine-learning-algorithms/
嗨,Jason,
关于这些技术(欠采样/过采样/混合采样)应用于哪种类型的不平衡数据集有任何线索吗?有什么经验法则吗?或者这需要大量计算的实验才能评估?
谢谢
我不相信启发式方法,我相信结果。我建议使用受控实验来发现哪种方法最适合您的数据集。如今计算成本非常低。
请参阅此框架
https://machinelearning.org.cn/framework-for-imbalanced-classification-projects/
嗨,Jason,
感谢您提供如此精彩的内容。
您能告诉我为什么不使用传统的 sklearn 管道吗?如果我们使用 sklearn 管道会发生什么?
sklearn 管道不允许您更改行数,而 imbalanced learn 管道可以。
您好 Jason,感谢您的澄清。
不客气。
File “pandas\_libs\index_class_helper.pxi”, line 109, in pandas._libs.index.Int64Engine._check_type
KeyError: ‘Class’
很抱歉听到这个消息,这些提示可能会帮助您
https://machinelearning.org.cn/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me
嗨,Jason,
我怎么才能把它应用到我的数据集上?
将数据集更改为您的数据集。
您好 Jason。非常感谢您的精彩帖子。
随机过采样与倾向得分匹配(基于逻辑回归)。
您会选择哪一个?为什么?(作为数据集独立)
对于特定数据集,哪种方法能带来所选指标的最佳性能。
您能否解释一下为什么在示例中使用 f1_micro 而不是 f1 评分?
我尝试了“随机过采样不平衡数据集”部分中的一个。当 scoring='f1_micro' 时,平均分数为 0.99;但当 scoring='f1' 时,它较低且在 0.2 到 0.7 之间变化。我原以为对于二元分类,它们是相似的,但不是吗?
好问题,我怀疑我应该使用“binary”。
Jason,我知道通过 imblearn.pipeline,可以在 K 折交叉验证期间的每次迭代中仅对数据的训练部分应用重采样,并且在您的示例中可以通过 CV 获得 F1 分数。有没有办法获得混淆矩阵(我的意思是,使用 K 折交叉验证和重采样)?您能给一个简单的例子吗?谢谢。
不。您无法使用 CV 计算混淆矩阵。
谢谢 Jason。
嗨,Jason,
感谢您如此详细的解释。
只有一个问题:如果您像您展示的那样对训练集进行过采样和欠采样,并且您进行了交叉验证,那么 F1 分数将基于验证集的预测,该验证集也经过重采样。
因此,即使这些交叉验证分数很高,当我们预测未经过采样/欠采样的测试集时,它们也会大幅降低。
您有什么办法即使在不平衡的测试集(即现实生活)中,经过采样的训练集后也能获得好的结果吗?谢谢!
不客气。
不,测试集从未被重采样。
但是,验证集不也应该是不平衡的,以匹配测试集(真实数据)的分布吗?
您好 Alex...以下讨论可能对您有益
https://datascience.stackexchange.com/questions/32818/train-test-split-of-unbalanced-dataset-classification
你好
如果我们得到 CV 混淆矩阵,
为什么我们不通过添加在此矩阵中获得的值来达到平衡后的记录数量?
例如,我们在平衡前有 100,000 条记录,平衡后有 150,000 条
为什么混淆矩阵中的总记录不等于 15,000?
抱歉,我的英语不好
在我看来,在交叉验证下计算混淆矩阵没有意义,抱歉。
为什么随机过采样后灵敏度仍低于 0.1?
我不认为我们在本教程中测量了灵敏度。
亲爱的 Jason,
首先,感谢您所有关于不平衡分类的精彩文章。
我阅读了您关于 SMOTE 和阈值移动的文章以及本文,它们对我的模型开发帮助很大。
现在,我想知道您是如何设置欠采样或过采样的比例的?
此外,有些方法,例如 LGBM,提供了参数 scale_pos_weight 或 is_unbalance,它们本质上平衡了主导标签的权重。
您对这种方法有什么看法?您是更倾向于随机过采样/欠采样,还是在学习方法中为某一类别设置权重?
谢谢你
试错是一个很好的起点,或者像超参数一样进行调整。
是的,这被称为成本敏感学习,与更改训练数据集不同。
https://machinelearning.org.cn/cost-sensitive-learning-for-imbalanced-classification/
您可以混合使用这些方法,但不建议这样做。
嗨,Jason,
感谢您的文章。
我只是有一个关于应用这些库(imblearn)的快速问题。似乎这些函数(oversample.fit_resample)只能应用于二维数组?
谢谢你
Vignesh
不客气!
是的,表格数据的行和列。
它有什么特殊原因吗?有没有办法将此函数用于高维数据?例如,维度为 (9000, 40, 40, 2) 的训练数据,就像图像一样?
谢谢你
我看不出有什么理由不行。只是实现是为二维/表格数据设计的。
听起来不错。谢谢。我只是好奇他们为什么选择二维实现而不是将其泛化。
再次感谢您的帮助和精彩内容!
Vignesh
也许您可以直接询问作者。
嗨
首先,非常感谢您与社区分享您的机器学习知识!
我正在尝试客观地衡量数据集的“不平衡性”,但我还没有找到任何方法。也许您可以帮助我解决这个问题。
此外,我想知道 SMOTE 能走多远。换句话说,可以生成多少样本,作为变量的函数,例如:您的类之间的大小差异、它们的稀疏性或熵……大多数文章通过分类器成本函数或 F1 分数(和其他花哨的度量)来发现这一点,但我想知道在馈送分类器之前您是否可以知道。
提前感谢。
不客气。
您可以客观地衡量不平衡,以计数、百分比或比率表示——它们都表达相同的意思。
尝试生成不同数量的示例,看看哪种方法最适合您的数据集。通常您会生成足够的数据以使类别平衡。
嗨,Jason,
OverSampler 是否有回归模型的集成?
不,一般来说这些方法只适用于分类。
尊敬的Jason博士,
感谢您的教程。
我感兴趣的是将学习曲线应用于位于“结合随机过采样和欠采样”副标题下的管道模型。
过拟合、欠拟合和“恰到好处”的典型曲线位于 https://machinelearning.org.cn/learning-curves-for-diagnosing-machine-learning-model-performance/。
问题:我想获取准确度与 epoch 曲线的图,如以下小标题所示:”
可视化 Keras 中的模型训练历史”:https://machinelearning.org.cn/display-deep-learning-model-training-history-in-keras/ 针对管道模型
也就是说,我想了解管道模型在模型准确度方面,在过拟合、欠拟合和“恰到好处”的情况下表现如何。
谢谢你,
悉尼的Anthony
你只能为增量拟合的模型创建学习曲线,例如神经网络和一些决策树的集成。
在 sklearn 中实现这一点可能需要自定义代码,以便一次拟合模型一步并在每个循环中评估数据集上的模型。例如,我没有示例,也没有能力为您编写一个,抱歉。
另外,这可能会有所帮助
https://machinelearning.org.cn/overfitting-machine-learning-models/
尊敬的Jason博士,
我设法为任何模型制作了学习曲线。
制作学习曲线的方法有很多,包括您在 https://machinelearning.org.cn/overfitting-machine-learning-models/ 中“Scikit-Learn 中过拟合的反例”小标题下的示例代码中建议的方法
制作学习曲线的一种方法是使用 sklearn 的学习曲线方法
模型可以是任何东西,例如 LogisticRegression、带权重的 LogisticRegression、DecisionTreeClassifier,以及带权重的 LogisticRegression 的 SMOTE。
在下面的示例中,我们使用 model=pipeline
我们制作学习曲线
灵感来自 https://chrisalbon.com/machine_learning/model_evaluation/plot_the_learning_curve/
结果
当模型是带有加权 LogisticRegression 的 SMOTE 管道且 AUC = 0.945 时,cross_validation_score 曲线与 training_score 验证曲线相交。
然而,cross_validation_score 曲线和 training_score 验证曲线在 DecisionTreeClassifier 中从不相交。
结论——带有加权 LogisticRegression 的管道生成了在 AUC=0.945 处相交的学习曲线
谢谢你,
悉尼的Anthony
干得好!
尊敬的Jason博士,
还有另一种方法可以找到特定模型的学习曲线。它来自 mlextend 包。
得到了另一种学习曲线。
结果
* 测试集和训练集的学习曲线相互追踪。这表明模型是“恰到好处的拟合”。
* 在 50 和 70 次迭代时,最高分数是 0.9
* 在 100 次迭代时,最高分数是 0.85。
* 绘图似乎有一个错误,不允许完整显示标题。
谢谢你,
悉尼的Anthony
感谢分享。
尊敬的Jason博士,
对于上一个帖子,我没有提到允许多个绘图的 mlxtend 包,为此我表示歉意。
完全不同的东西
我对分数进行了进一步的实验。我通常确定平均(roc_aoc)和平均(准确度)
示例代码
这就是问题:我发现某些模型的准确度分数 > roc_auc 分数。例如
只要 ROC_AUC > 0.5,这样可以吗?
谢谢你
悉尼的Anthony
你不能相互比较“准确度”和“roc auc”指标。
尊敬的Jason博士,
感谢您的回复。
我的问题是:根据您在 https://machinelearning.org.cn/roc-curves-and-precision-recall-curves-for-classification-in-python/ 上的文章,只要“橙色”曲线在“蓝色”对角线“无技能”线上方。“橙色”线越高,真阳性的可能性越大,而不是假阳性。
再次感谢您,
悉尼的Anthony
如果我有一个类别不平衡,大约有 450 万行,并且想使用 smote 并并行执行,在这种情况下应该考虑什么方法?
您可能需要开发一个自定义实现。
或者在不同的机器上使用相同的代码/数据,并分摊工作。
嗨,Jason,
感谢您如此精彩的解释。我正在处理推文,提取了 88 条推文作为示例,并使用 KMeans 聚类对其进行标记。44 条推文具有标签 0,44 条推文具有标签 1。我现在拥有的数据集是平衡的。但是,如果我使用比率 0.5 和 0.8(采样策略)运行过采样和欠采样的代码,我得到了
ValueError: The specified ratio required to remove samples from the minority class while trying to generate new samples. Please increase the ratio.
但是如果我使用参数 sampling_strategy=”minority” 和 sampling_strategy=”majority”
代码有效。
你能解释一下吗?
也许尝试不同的比率并比较结果?
嗨
假设您有一个非常不平衡的数据,并且使用数据(未过采样)在测试集上获得了 40% 的分类准确度。然后您使用过采样,并在从过采样数据中提取的测试集上获得了 95% 的准确度。
现在,如果您使用原始数据(过采样之前)来测试您使用过采样数据训练的多类分类器的性能,您会期望获得约 40% 的准确度还是约 95%?
准确度不是不平衡分类的良好指标
https://machinelearning.org.cn/tour-of-evaluation-metrics-for-imbalanced-classification/
永远不要在过采样数据上评估模型,这是无效的。
你做得很好。我喜欢你解释所有困难材料的方式。请继续分享。祝好运。
嗨,Jason,
我们可以将相同的算法用于有序数据,还是必须转向其他算法?
非常感谢您如此清晰的解释。
祝好,
Maxime
嗨 Maxime……以下内容可能会让您感兴趣
https://machinelearning.org.cn/one-hot-encoding-for-categorical-data/
嗨,Jason,
我认为在对数据集进行采样时存在一个错误,因为我们正在对 X 而不是 X_train 执行转换。这可能导致数据泄漏问题。如果我错了,请纠正我。
嗨
我想在大型数据集(大数据环境)上使用 pyspark(spark 平台..)实现 smote 算法,请问您能帮我吗?
嗨 Noureddine...以下内容可能会让您感兴趣
https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-14-106
嗨,Jason,
构建此管道时,交叉验证分数将我们的数据分割为训练集和验证集,对吗?
我们是否对这两个集合都应用了过采样?
或者 cross_validate 函数是先分割数据,然后再应用过采样/欠采样?
嗨 Lior,
以下资源有望提供清晰的解释
https://medium.com/analytics-vidhya/deeply-explained-cross-validation-in-ml-ai-2e846a83f6ed
此外,关于重复 K 折交叉验证的最佳实践可以在这里找到
https://machinelearning.org.cn/repeated-k-fold-cross-validation-with-python/
很棒的教程!非常感谢。我如何返回原始索引?不幸的是,此方法似乎重新索引了索引。
嗨……以下讨论可能会让您感兴趣
https://stackoverflow.com/questions/64187342/how-to-create-random-samples-without-replacement-of-a-population-in-a-fast-way
很棒的教程!非常感谢。我如何返回原始索引?不幸的是,此方法似乎重新索引了索引。
非常感谢这篇内容丰富的帖子。
我只有一个问题,文章提到重采样只应在训练集上进行。
但在代码中,过采样和欠采样是在整个数据集 X 上进行的,然后应用交叉验证将 X 分割为训练集和测试集。
难道不应该先应用交叉验证来获取训练集和测试集,然后只在训练集上应用重采样吗?
还是随机重采样也可以应用于测试集?
嗨 Eman……你的谨慎是完全正确的——这是正确处理不平衡数据集的关键点。
### 🔑 关键原则
**重采样(无论是过采样还是欠采样)应该 *只* 应用于交叉验证的每个折叠中的训练数据。**测试数据(或验证折叠)必须保持不变,并保留其自然的类别分布。原因如下:
—
### ❌ 为什么不应该在交叉验证之前对整个数据集进行重采样
如果你在交叉验证之前进行重采样:
– **会发生数据泄漏。**
– 合成样本(对于 SMOTE 等过采样情况)来源于原始数据,如果这些样本渗透到验证/测试集中,你的模型在训练时会看到与测试时过于相似的数据。
– **评估指标会变得过于乐观。**
– 你正在测试的数据受到了训练过程的影响,即使是间接影响。
—
### ✅ 使用交叉验证正确应用重采样的方法
你需要将**重采样 *应用于* 交叉验证循环内部**。以下是使用
StratifiedKFold
和Pipeline
在scikit-learn
中的常见方法:python
from imblearn.pipeline import Pipeline
from imblearn.over_sampling import SMOTE
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.ensemble import RandomForestClassifier
# 定义管道:仅对训练折叠应用 SMOTE
pipeline = Pipeline([
('smote', SMOTE(random_state=42)),
('classifier', RandomForestClassifier())
])
# 执行交叉验证
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(pipeline, X, y, cv=cv, scoring='f1')
print("F1 分数:", scores)
在此设置中:
– 每个折叠将数据分割为训练/测试集。
–
SMOTE
只应用于每个折叠中的训练部分。– 模型在重采样后的训练数据上进行训练。
– 模型在未触及的测试部分上进行评估。
—
### 🧠 总结
– ✔️ 重采样**只**应发生在每个交叉验证折叠内的训练数据上。
– ❌ 永远不要在分割之前对整个数据集进行重采样——这会导致**数据泄漏**。
– 🔧 使用
imblearn.pipeline.Pipeline
等工具,在交叉验证中安全地结合重采样和建模。