SMOTE通过sampling_strategy参数控制少数类目标数量而非生成倍数,其值以多数类样本数为基准计算;需精确生成指定数量样本时,应采用自定义SMOTE实现,手动控制合成总数。

SMOTE 本身不能直接指定“生成多少个新样本”,它只接受比例控制(如 sampling_strategy=0.5 表示少数类最终占多数类的 50%),如果你需要精确控制合成样本数量(比如“必须新增 87 个”),用现成库的默认接口会卡住——得自己动手或绕道调整。
SMOTE 的 sampling_strategy 参数到底怎么算
sampling_strategy 看似简单,实则容易误解。它不是“生成几倍”,而是“目标类别比例”。例如:
- 原始数据中,少数类有 40 个,多数类有 200 个;
- 设
sampling_strategy=1.0→ 少数类目标数量 = 200 × 1.0 = 200,即需新增 160 个; - 设
sampling_strategy=0.8→ 目标 = 200 × 0.8 = 160,新增 120 个; - 设
sampling_strategy='minority'→ 少数类目标数量 = 多数类数量(即 1:1); - 设
sampling_strategy={1: 150}(假设少数类标签是 1)→ 强制目标为 150,新增 110 个。
关键点:
- 它始终以多数类样本数为基准(除非显式用字典指定);
- 小数点后精度不保证严格达成(内部会向下取整到最接近的整数倍);
- 若你传入
sampling_strategy=100,会被当作字典键处理,报KeyError。
如何真正实现“我要 100 个新样本”这个需求
最稳妥的方式是:先用 SMOTE 生成足够多的样本,再手动截断,或改用自定义实现。推荐后者,逻辑清晰、无黑箱:
立即学习“Python免费学习笔记(深入)”;
- 先提取所有少数类样本:
X_minor = X[y == minority_label]; - 初始化
NearestNeighbors(n_neighbors=k),对每个样本找 k 个同类近邻; - 对每个样本,循环生成 N 次:随机选一个近邻,按
x_new = x + np.random.rand() * (x_nn - x)插值; - 控制总生成数:用
while len(synthetic) < target_count:循环,避免依赖原始样本数倍率。
示例片段:
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
from sklearn.neighbors import NearestNeighbors
import numpy as np
<p>def smote_exact(X_minor, k=5, target_count=100):
n_samples, n_features = X_minor.shape
synthetic = []
nn = NearestNeighbors(n_neighbors=k).fit(X_minor)</p><pre class='brush:python;toolbar:false;'>while len(synthetic) < target_count:
i = np.random.randint(0, n_samples)
dists, inds = nn.kneighbors(X_minor[i].reshape(1, -1), return_distance=False)
nn_idx = np.random.choice(inds[0][1:]) # 排除自己
gap = np.random.rand()
x_new = X_minor[i] + gap * (X_minor[nn_idx] - X_minor[i])
synthetic.append(x_new)
return np.array(synthetic[:target_count])注意:
-
inds[0][1:]是为了跳过自身(索引 0 总是自己); - 用
[:target_count]防止 while 循环多生成一个; - 这种方式完全绕开
imblearn的比例机制,适合 pipeline 中需要确定性输出的场景。
fit_resample 后标签没对齐?检查 y 类型和顺序
常见错误现象:X_resampled 行数变多了,但 y_resampled 里全是 0,或长度不匹配。
根本原因通常是:
-
y是 pandasSeries且索引非连续(比如删过行),fit_resample内部重排时没重置索引; - 或者
y是 list 但含字符串标签(如['cat', 'dog']),而SMOTE要求数值型标签([0, 1]); - 更隐蔽的是:你传了
X和y,但二者 index 不一致(pandas DataFrame/Series 场景下极易发生)。
解决办法:
- 统一转成 numpy 数组:
X = np.array(X),y = np.array(y); - 若 y 是字符串,先用
LabelEncoder编码,过采样完再映射回去; - 检查
len(X) == len(y)且np.all(pd.isna(y) == False),排除空值干扰。
自定义数量的 SMOTE 看似只是“多写几行”,但它把控制权从库的启发式策略里拿回来了。真正容易被忽略的,不是公式本身,而是k 值选择对边界样本的影响——k 太小(如 k=2)会让合成点过于集中,k 太大(如 k=20)又可能拉进异类邻居,尤其在高维稀疏空间里。建议先用 NearestNeighbors 查看少数类内平均最近邻距离分布,再定 k。

















