
使用 Pandas 和 Scikit-learn 处理不平衡数据集
作者 | Ideogram 提供图片
引言
不平衡数据集,即大多数数据样本属于一个类别,而少数数据样本属于其他类别,并不少见。事实上,不平衡数据可能源于各种现实世界情况,例如银行和金融领域的欺诈检测系统,其中欺诈性交易远少于合法交易;以及医疗诊断,其中罕见疾病的发生频率远低于常见健康状况。
问题在于:拥有不平衡数据通常会使分析过程更加困难,特别是对于机器学习模型而言。由于数据类别分布极度不均,模型很容易偏向多数类别,从而最终成为一个几乎“虚拟分类器”,将相同的类别分配给几乎所有内容——在最极端的情况下。
本文展示了几种使用 Python 中两个最出色的“数据处理”库:Pandas 和 Scikit-learn 来处理不平衡数据集的策略。
实用指南:银行营销数据集
为了举例说明这份在 Python 中处理不平衡数据的实用指南,我们将考虑 银行营销数据集。这是一个公开可用的不平衡数据集,包含描述银行客户的数据,并标记有两个可能的类别:客户在接到银行营销电话后是否订阅了定期存款(“是”与“否”)。
为什么这个数据集不平衡?因为数据集中只有约 11% 的客户订阅了定期存款,其余约 89% 的客户拒绝订阅,因此,正类别(“是”)的代表性明显不足。
让我们开始加载数据集
1 2 3 4 5 6 7 8 9 10 11 |
from ucimlrepo import fetch_ucirepo bank_marketing = fetch_ucirepo(id=222) # 将目标标签与其余特征分离 X = bank_marketing.data.features y = bank_marketing.data.targets # 显示一些数据集元数据 print(bank_marketing.metadata) print(bank_marketing.variables) |
对于一个可能不平衡的数据集,首先也是最合乎逻辑的做法是探索其类别分布。
1 2 3 4 5 6 7 |
print("类别分布:") print(y.value_counts()) print(f"百分比:\n{y.value_counts(normalize=True) * 100}") # 不平衡比率 (%) imbalance_ratio = y.value_counts().min() / y.value_counts().max() print(f"不平衡比率:{imbalance_ratio:.3f}") |
因此,准确地说,有 39922 位银行客户拒绝订阅所提供的服务,而只有 5289 位客户订阅了该服务。这分别占数据总量的 88.3% 和 11.7%。
策略 #1:反频率加权
现在介绍一些处理不平衡数据集的策略。第一个策略由 Scikit-learn 提供,它包括使用特定的机器学习模型进行分类,并提供自定义选项,以便更有效、更少偏差地在不平衡数据上进行训练。`class_weight='balanced'` 参数将实例权重调整为与类别频率成反比,从而给予少数类别更大的权重,并弥补类别不平衡。
此代码在数据集的预处理版本上训练平衡随机森林分类器,该版本通过独热编码(使用 Pandas 的 `pd.get_dummies()`)对分类属性进行编码。
1 2 3 4 5 6 7 8 9 10 11 12 |
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split import pandas as pd rf_balanced = RandomForestClassifier(class_weight='balanced', random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 编码分类变量 X_train_encoded = pd.get_dummies(X_train) X_test_encoded = pd.get_dummies(X_test).reindex(columns=X_train_encoded.columns, fill_value=0) rf_balanced.fit(X_train_encoded, y_train.values.ravel()) |
策略 #2:欠采样
另一种策略,这次由 Pandas 主导并侧重于机器学习模型训练前的数据预处理阶段,是**欠采样**。这是一种常见的处理数据集中某些类别代表性不足的情况的方法,它涉及到减少多数类别中的实例数量以匹配少数类别中的实例数量。这种方法的有效性取决于少数类别中是否有足够的实例,以避免多数类别实例在可能被大幅欠采样后造成信息丢失。虽然它减少了后期训练模型对多数类别的偏差,但欠采样也可能导致模型方差,有时由于足够信息量实例的丢失而导致欠拟合。
此示例展示了如何使用 Pandas 应用欠采样 — 请注意,预测器属性和标签首先统一以便于操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
df_combined = pd.concat([X, y], axis=1) target_col = y.columns[0] # 将实例分成多数类别与少数类别 df_majority = df_combined[df_combined[target_col] == 'no'] df_minority = df_combined[df_combined[target_col] == 'yes'] # 欠采样:我们保留与少数实例数量 (n) 相同的多数实例 df_majority_downsampled = df_majority.sample(n=len(df_minority), random_state=42) df_balanced = pd.concat([df_majority_downsampled, df_minority]) print(f"原始数据集:{len(df_combined)}") print(f"平衡数据集:{len(df_balanced)}") |
欠采样得到的平衡数据集只有 10.5K 个实例,而不是完整数据集中的大约 45K 个实例。这足够吗?您随后训练的分类模型的性能可能会给出答案。
总而言之,如果您的数据集足够大,以便在过拟合后仍能获得足够有代表性和多样性的实例子集,请尝试欠采样。
策略 #3:过采样
相反,Pandas 也允许通过带替换的随机采样来**对少数类别进行过采样**。仅当少数类别数量较少但具有代表性时,以及最重要的是,在添加重复实例不太可能引入噪声或导致过拟合等问题的情况下才使用此策略。尽管如此,此技术有时可以帮助缓解模型对多数类别的偏差。
1 2 3 4 |
df_minority_upsampled = df_minority.sample(n=len(df_majority), replace=True, random_state=42) df_oversampled = pd.concat([df_majority, df_minority_upsampled]) print(f"过采样数据集:{len(df_oversampled)}") |
总结
本文探讨了数据集中的类别不平衡问题,并介绍了使用 Pandas 和 Scikit-learn 库处理该问题的一些常用策略。我们重点关注了三种特定的常用策略:训练平衡分类模型、欠采样和过采样。值得注意的是,还有更多处理不平衡数据集的策略,例如 Scikit-learn 的**重采样**工具、**SMOTE**(合成少数类过采样技术)等高级技术,以及更多。
暂无评论。