如何修复11分类任务中SMOTE过采样的samples < K-neighbours错误?
解决SMOTE多分类时出现的
ValueError: Expected n_neighbors <= n_samples问题 嗨,我来帮你拆解一下这个问题~这个错误的核心原因其实很直白:你的11个分类标签里,存在某个极端少数类,它的样本数量只有1个,但SMOTE默认会用6个近邻(k_neighbors=6)来生成新的合成样本——样本数连找近邻的数量都不够,自然就报错了。
为什么小数据集没问题?
你在10万行4标签的数据集上能正常运行,是因为那4个标签的每个类别样本数都≥6,满足SMOTE找近邻的最低要求;但当前11标签的数据集里,有某个类别的样本数只有1,完全达不到默认的近邻数量要求,才会触发这个报错。
怎么验证这个结论?
先统计每个类别的样本数量,找到那个拖后腿的极端少数类:
import pandas as pd # 如果你的Y_f是one-hot编码的多分类标签,先转成单类别索引 Y_labels = Y_f.argmax(axis=1) # 统计每个类别的样本数 class_counts = pd.Series(Y_labels).value_counts() print(class_counts)
运行后你肯定能看到某个类的样本数是1,这就是问题根源。
针对性解决方案
根据你的需求和试过的方法,给你几个可行的方向:
1. 先处理极端少数类,再用SMOTE
如果那个只有1个样本的类别业务优先级不高,可以直接删除该类的样本:
# 假设极端少数类是类别9,筛选掉该类样本 idx = Y_labels != 9 X_f_filtered = X_f[idx] Y_f_filtered = Y_f[idx] # 再跑SMOTE就不会报错了 sm = SMOTE(random_state=42) X_res, Y_res = sm.fit_resample(X_f_filtered, Y_f_filtered)
如果必须保留这个类别,可以先用RandomOverSampler给它先随机过采样到至少6个样本,再用SMOTE处理整体不平衡:
from imblearn.over_sampling import RandomOverSampler # 先给极端少数类(比如类别9)采样到6个样本 ros = RandomOverSampler(sampling_strategy={9: 6}, random_state=42) X_ros, Y_ros = ros.fit_resample(X_f, Y_labels) # 再用SMOTE处理其他不平衡类别 sm = SMOTE(random_state=42) X_res, Y_res = sm.fit_resample(X_ros, Y_ros)
2. 调整SMOTE的近邻参数
如果你不想修改数据集,可以把SMOTE的k_neighbors参数调低到≤1(因为那个类只有1个样本),但这种方法生成的合成样本质量会很差,不推荐作为长期方案:
sm = SMOTE(random_state=42, k_neighbors=1) X_res, Y_res = sm.fit_resample(X_f, Y_f)
3. 尝试更适合极不平衡场景的过采样方法
比如ADASYN,它和SMOTE类似,但会根据样本的难分程度生成不同数量的合成样本,对极端少数类的处理更灵活:
from imblearn.over_sampling import ADASYN ada = ADASYN(random_state=42, n_neighbors=1) X_res, Y_res = ada.fit_resample(X_f, Y_f)
关于你试过的方法的补充说明
- SVMSMOTE太慢:这个方法需要先训练SVM来筛选支持向量,本身计算量就极大,不适合200万行的大数据集,放弃是对的;
- RandomOverSampler准确率低:随机过采样只是简单复制样本,很容易导致模型过拟合,所以准确率低是正常的,建议结合SMOTE使用(先随机补全极端少数类,再用SMOTE合成其他少数类样本);
- 调整sampling_strategy无效:可能是你没针对那个只有1个样本的类别单独设置目标数量,比如你可以指定
sampling_strategy={9: 10},但前提是该类的原样本数要≥k_neighbors,否则还是会报错。
内容的提问来源于stack exchange,提问作者cappy0704
相关产品推荐
相关产品推荐

