SMOTE 过采样:合成少数类样本以平衡数据

FreeGuideOnline 最新 2026-06-14

SMOTE 过采样:合成少数类样本以平衡数据

在分类问题中,不平衡数据集是常态而非例外。欺诈检测、罕见病诊断、故障预测等场景下,目标类别的样本量可能仅占总数1%甚至更低。常规模型会对多数类过拟合,导致少数类召回率极低。SMOTE(Synthetic Minority Over-sampling Technique)正是为了解决这一问题而提出的经典方法。它并不简单复制已有样本,而是通过在特征空间中插值,生成人工但合理的少数类样本,从而改善数据分布。

为什么简单过采样会失效

初学者常采用随机过采样:从少数类中随机复制样本,直至类别均衡。但这等同于让模型多次看到完全相同的样本,极易引发过拟合,尤其是当少数类样本本已稀疏时,决策边界会围绕这些重复点紧缩,泛化能力很差。SMOTE 则彻底转变思路:创造全新样本。

SMOTE 核心思想

SMOTE 基于一个直观假设:特征空间中相邻的少数类样本之间的点,大概率也属于少数类。它的做法是:对每个少数类样本,找到它的k个最近少数类邻居,然后在样本点与邻居之间的连线上,随机选择一个点作为新合成样本。

算法流程详解

  1. 确定过采样倍率
    假设少数类有 $T$ 个样本,多数类有 $M$ 个样本。期望获得平衡数据,通常需合成 $N = M - T$ 个新样本。定义倍率 $R = \lceil N/T \rceil$,即每个少数类样本大致参与 $R$ 次合成。

  2. 寻找k近邻
    对每个少数类样本 $x_i$,计算它在所有少数类样本中的欧氏距离(也可用其他距离),选取最近的 $k$ 个邻居(通常 $k=5$)。

  3. 生成合成样本
    对于样本 $x_i$,从其 $k$ 个邻居中随机选择 $R$ 个邻居(允许重复选择)。对每一个选中的邻居 $x_{zi}$,按以下公式生成新样本:

    x_new = x_i + λ × (x_{zi} - x_i)
    

    其中 $λ$ 是 $(0, 1)$ 区间内的随机数。这等价于在两点之间的线段上随机取一点。

  4. 形成新的数据集
    将所有原少数类样本与合成样本合并,再与多数类样本组合,得到平衡后的训练集。

一个具体的算例

假设一个二维数据集,少数类有3个点:A(2,3), B(3,5), C(5,4)。多数类有10个点,需要合成7个新少数类点。令 $k=2$,$R=3$。

  • 对点A,最近邻居为B和C。随机选B,生成 $λ=0.6$:
    x_new=2+0.6×(3-2)=2.6, y_new=3+0.6×(5-3)=4.2 → (2.6,4.2)
    再选C,生成 $λ=0.3$:(2+0.3×3, 3+0.3×1) = (2.9,3.3)
    再选B,生成 $λ=0.8$: (2+0.8×1, 3+0.8×2) = (2.8,4.6)
  • 对B、C进行类似操作,直至凑齐7个新样本。

这样得到的点全部位于原始点连线内部,填补了类别区域,而非简单重复。

Python 实现(基于 imbalanced-learn)

from imblearn.over_sampling import SMOTE
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from collections import Counter

# 生成不平衡数据:少数类占10%
X, y = make_classification(n_samples=1000, n_features=4, weights=[0.9, 0.1], random_state=42)
print('原始分布:', Counter(y))

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 应用 SMOTE,k_neighbors 默认=5
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)
print('重采样后分布:', Counter(y_resampled))

关键参数说明:

  • k_neighbors:构建k近邻所用的邻居数,默认5。少数类样本数若少于k,需调低。
  • sampling_strategy:目标平衡比例。默认为 'auto'(使所有类数量相等),也可传入字典指定各类最终数量。
  • random_state:控制随机种子,保证可复现。

SMOTE 的变体与进阶

由于原始 SMOTE 在边界附近可能引入噪声,或在类别重叠区域合成无效点,后续出现了多种改进:

  • Borderline-SMOTE:仅对靠近多数类的少数类“边界点”进行过采样,避免在安全区盲目合成。
  • ADASYN:根据少数类样本学习的难易程度自适应生成样本,在更难学习的区域合成更多点。
  • SMOTENC:可处理包含分类特征的数据,对连续特征按插值生成,对分类特征取最近邻的多数投票值。

使用注意事项

  1. 先划分再采样
    务必在训练集上应用 SMOTE,测试集保持原始分布不变。使用 train_test_split 后再 fit_resample,否则会造成数据泄漏,导致评估虚高。

  2. 高维数据风险
    维度灾难会导致距离度量失效,近邻可能不代表真实相似性。这时建议先降维(如 PCA)再 SMOTE,或使用基于深度学习的生成方法(如 CTGAN)。

  3. 噪声敏感性
    若少数类中包含大量噪声点,合成样本会放大噪声。建议采样前做必要的数据清洗,或使用 Borderline-SMOTE 等变体。

  4. 类别比例非必须 1:1
    平衡比例可视具体问题调整。某些场景下轻微偏向少数类反而更优,可通过 sampling_strategy 微调。

  5. 模型评估指标
    不平衡数据不应只看准确率。应采用精准率、召回率、F1‑score、AUC‑ROC,重点关注少数类的召回率改善。

效果对比实验示意

使用逻辑回归在不平衡与 SMOTE 平衡后的数据上对比:

指标 原始不平衡数据集 SMOTE 平衡后
少数类召回率 0.35 0.82
少数类精准率 0.72 0.68
F1‑score 0.47 0.75

可见召回率大幅提升,精准率略有下降,整体 F1 收益显著。实际应用中需权衡 Precision-Recall 曲线。

总结

SMOTE 通过邻域插值的思想制造合成样本,改进了随机过采样的过拟合问题,成为处理结构化数据不平衡问题的基准方法。借助 imbalanced-learn 库只需几行代码即可集成到 Pipeline 中。理解其生成机制与局限性,能帮助你在真实项目中少走弯路,稳健提升模型对少数类的检出能力。