SMOTE 过采样:合成少数类样本以平衡数据
SMOTE 过采样:合成少数类样本以平衡数据
在分类问题中,不平衡数据集是常态而非例外。欺诈检测、罕见病诊断、故障预测等场景下,目标类别的样本量可能仅占总数1%甚至更低。常规模型会对多数类过拟合,导致少数类召回率极低。SMOTE(Synthetic Minority Over-sampling Technique)正是为了解决这一问题而提出的经典方法。它并不简单复制已有样本,而是通过在特征空间中插值,生成人工但合理的少数类样本,从而改善数据分布。
为什么简单过采样会失效
初学者常采用随机过采样:从少数类中随机复制样本,直至类别均衡。但这等同于让模型多次看到完全相同的样本,极易引发过拟合,尤其是当少数类样本本已稀疏时,决策边界会围绕这些重复点紧缩,泛化能力很差。SMOTE 则彻底转变思路:创造全新样本。
SMOTE 核心思想
SMOTE 基于一个直观假设:特征空间中相邻的少数类样本之间的点,大概率也属于少数类。它的做法是:对每个少数类样本,找到它的k个最近少数类邻居,然后在样本点与邻居之间的连线上,随机选择一个点作为新合成样本。
算法流程详解
-
确定过采样倍率
假设少数类有 $T$ 个样本,多数类有 $M$ 个样本。期望获得平衡数据,通常需合成 $N = M - T$ 个新样本。定义倍率 $R = \lceil N/T \rceil$,即每个少数类样本大致参与 $R$ 次合成。 -
寻找k近邻
对每个少数类样本 $x_i$,计算它在所有少数类样本中的欧氏距离(也可用其他距离),选取最近的 $k$ 个邻居(通常 $k=5$)。 -
生成合成样本
对于样本 $x_i$,从其 $k$ 个邻居中随机选择 $R$ 个邻居(允许重复选择)。对每一个选中的邻居 $x_{zi}$,按以下公式生成新样本:x_new = x_i + λ × (x_{zi} - x_i)其中 $λ$ 是 $(0, 1)$ 区间内的随机数。这等价于在两点之间的线段上随机取一点。
-
形成新的数据集
将所有原少数类样本与合成样本合并,再与多数类样本组合,得到平衡后的训练集。
一个具体的算例
假设一个二维数据集,少数类有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:可处理包含分类特征的数据,对连续特征按插值生成,对分类特征取最近邻的多数投票值。
使用注意事项
-
先划分再采样
务必在训练集上应用 SMOTE,测试集保持原始分布不变。使用train_test_split后再fit_resample,否则会造成数据泄漏,导致评估虚高。 -
高维数据风险
维度灾难会导致距离度量失效,近邻可能不代表真实相似性。这时建议先降维(如 PCA)再 SMOTE,或使用基于深度学习的生成方法(如 CTGAN)。 -
噪声敏感性
若少数类中包含大量噪声点,合成样本会放大噪声。建议采样前做必要的数据清洗,或使用 Borderline-SMOTE 等变体。 -
类别比例非必须 1:1
平衡比例可视具体问题调整。某些场景下轻微偏向少数类反而更优,可通过sampling_strategy微调。 -
模型评估指标
不平衡数据不应只看准确率。应采用精准率、召回率、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 中。理解其生成机制与局限性,能帮助你在真实项目中少走弯路,稳健提升模型对少数类的检出能力。