【精选优质专栏推荐】


每个专栏均配有案例与图文讲解,循序渐进,适合新手与进阶学习者,欢迎订阅。

在这里插入图片描述

引言

新手机器学习从业者几乎都会立刻意识到一个事实:并非所有数据集都是平等的。

这现在对你来说也许显而易见,但在你开始处理真实世界的机器学习项目之前,是否考虑过这一点?举个例子,在一种只有 1% 的人群患有的罕见疾病中,如果一个预测模型始终预测“无病”,它虽然 99% 正确,但能算有用吗?显然不能。

在机器学习中,数据集不平衡会成为模型性能的障碍,且常常难以克服。许多常见算法默认假设各类别在数据分布中被近似均衡地表示。而在不平衡数据上训练的模型通常会严重偏向多数类,从而导致少数类被低估——而少数类往往正是需要重点关注的部分。

这种严重偏斜的数据集在现实中非常普遍,从罕见疾病研究(数据稀少且难以获取)到金融欺诈检测(大部分交易并非欺诈)。本文的目标是介绍 5 种可靠的策略,用于处理类别不平衡问题。

1. 重采样技术(Resampling Techniques)

重采样通过增加少数类样本或移除多数类样本来平衡类别。

常见的少数类过采样方法包括生成新的少数类样本。
随机过采样(Random Oversampling)是一种简单方法,通过复制现有少数类样本生成新样本。但熟悉机器学习基础的人会立刻意识到其过拟合风险。更先进的做法是使用 SMOTE(Synthetic Minority Over-sampling Technique,合成少数类过采样技术),该方法通过在现有少数类样本之间插值来生成新样本。

同样地,多数类欠采样的策略是删除部分多数类样本。
随机欠采样(Random Under-Sampling)就是随机丢弃多数类的一些样本,但这可能导致信息丢失。为了减轻这种损失,可以使用更复杂的欠采样方法,如 Tomek Links 或邻域清理规则(Neighborhood Cleaning Rule, NCR),它们会删除与少数类过于接近或重叠的多数类样本,从而在减少噪声的同时保留重要信息,并使类别边界更加清晰。

下面是使用 imbalanced-learn 库进行 SMOTE 和随机欠采样的简单示例:

from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler

# 假设 X 为特征矩阵,y 为目标向量
# SMOTE 过采样
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)

# 随机欠采样
rus = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = rus.fit_resample(X, y)

每种方法都有其优缺点。过采样可能导致过拟合,尤其是在使用简单复制时;而欠采样可能会丢失有价值的信息。通常结合两种技术可以获得更好的结果。

2. 算法集成方法(Algorithmic Ensemble Methods)

集成方法通过组合多个模型来生成一个更强的整体模型,对不平衡数据问题尤其有用,特别是当目标类别是少数类时。

一种常见的集成方法是 Bagging(自助聚合)。其核心思想是从数据中随机创建多个子集,在每个子集上训练一个模型,然后结合这些模型的预测结果。随机森林(Random Forest)是 Bagging 的一种常见实现方式,常用于不平衡数据。随机森林通过在不同数据子集上创建多棵决策树并聚合它们的输出,有效防止过拟合并提升模型的泛化性能。

另一种方法是 Boosting(提升)。该方法按顺序训练多个模型,每个新模型都会努力纠正前一模型的错误。对于处理不平衡数据,Boosting 尤其强大。例如,梯度提升(Gradient Boosting)可以自我学习,使模型更关注那些容易被错误分类的少数类样本,从而自动调整模型行为。

以下是在 Python 中实现随机森林和梯度提升的示例:

from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier

# 随机森林
rf_classifier = RandomForestClassifier(n_estimators=100, class_weight='balanced_subsample')
rf_classifier.fit(X_train, y_train)

# 梯度提升
gb_classifier = GradientBoostingClassifier(n_estimators=100)
gb_classifier.fit(X_train, y_train)

在上面的代码中,n_estimators 定义了树或提升阶段的数量,而 class_weight 参数在随机森林中用于调整类别权重,以应对不平衡数据。

这些方法本身就具备一定的抗不平衡能力,因为它们通过结合多个模型或聚焦难分类样本来提升性能。通常即便不使用重采样,它们也能获得不错的效果,而与重采样技术结合使用时效果往往更佳。

3. 调整类别权重(Adjust Class Weights)

类别加权(class weighting)是一种在模型训练中给少数类分配更高权重的技术,使模型在优化过程中更加关注那些代表性不足的类别。

在一些机器学习库(如 scikit-learn)中,可以直接设置类别权重。当数据集中某个类别出现的频率远高于其他类别时,模型会对少数类的错误分类施加更高的惩罚,从而平衡学习过程。

例如,在逻辑回归中可以这样设置类别权重:

from sklearn.linear_model import LogisticRegression
from sklearn.utils.class_weight import compute_class_weight
import numpy as np

# 计算权重
class_weights = compute_class_weight('balanced', classes=np.unique(y), y=y)
weight_dict = dict(zip(np.unique(y), class_weights))

# 应用权重到模型
lr_classifier = LogisticRegression(class_weight=weight_dict)
lr_classifier.fit(X_train, y_train)

通过调整类别权重,我们改变了模型在误分类时的惩罚方式。需要注意的是,这些权重不会改变模型的预测过程本身,而是影响模型在优化阶段对损失函数的计算方式。
不过要避免对少数类加权过高,否则模型可能会过度偏向该类,甚至“遗忘”其他类别。

4. 使用合适的评估指标(Use Appropriate Evaluation Metrics)

在处理不平衡数据时,仅仅使用“准确率”往往具有误导性。一个总是预测多数类的模型可能准确率很高,但完全无法识别少数类。

更合适的指标包括:

  • Precision(精确率):预测为正样本的结果中有多少是真的正样本。
  • Recall(召回率):所有真实正样本中有多少被模型识别出来。
  • F1-score(F1 值):精确率和召回率的调和平均,平衡两者。
  • AUC-ROC(受试者工作特征曲线下面积):衡量模型在不同阈值下区分类别的能力,对类别不平衡不敏感。

混淆矩阵(Confusion Matrix)同样非常有用,它能直观展示模型的预测情况,包括真阳性、假阳性、真阴性和假阴性。

下面是这些指标的计算示例:

from sklearn.metrics import precision_recall_fscore_support, roc_auc_score, confusion_matrix

# 假设 y_true 为真实标签, y_pred 为模型预测结果
precision, recall, f1, _ = precision_recall_fscore_support(y_true, y_pred, average='binary')
auc_roc = roc_auc_score(y_true, y_pred)
conf_matrix = confusion_matrix(y_true, y_pred)

print(f"Precision: {precision}, Recall: {recall}, F1: {f1}")
print(f"AUC-ROC: {auc_roc}")
print("Confusion Matrix:")
print(conf_matrix)

选择指标时应基于具体问题:

  • 假阳性代价高(如误判为欺诈),应关注精确率;
  • 漏判代价高(如漏诊疾病),应关注召回率;
  • F1 值和 AUC-ROC 通常提供更平衡的整体评估。

5. 生成合成样本(Generate Synthetic Samples)

合成样本生成是一种更高级的平衡数据技术,通过为少数类生成人工样本来扩充数据集。

SMOTE(Synthetic Minority Over-sampling Technique)是常用算法。它通过选取一个少数类样本,并寻找其 k 个最近邻,然后在该样本与邻居之间插值生成新样本。

实现示例如下:

from imblearn.over_sampling import SMOTE

smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)

进阶版本如 ADASYN(Adaptive Synthetic)Borderline-SMOTE 会专注于少数类易被误分类的区域生成样本,从而提升边界学习效果。

不过,生成合成样本也存在风险。若使用不当,可能引入噪声或生成不现实的样本。因此,必须验证这些新样本在实际业务语境中是否合理。

总结

处理不平衡数据是许多机器学习任务中的关键步骤。本文介绍了五种常用方法:

  1. 重采样(Resampling)
  2. 集成方法(Ensemble Methods)
  3. 类别权重调整(Class Weighting)
  4. 合适的评估指标(Evaluation Metrics)
  5. 合成样本生成(Synthetic Sample Generation)

需要注意,没有通用的解决方案。不同的数据集、业务目标和评估标准需要不同的策略。通常,混合使用多种方法或调整参数能获得最佳效果。

掌握这些应对不平衡数据的技术,能让你在机器学习项目中构建更可靠、更具实用价值的模型。

更多推荐