使用Python的imbalanced-learn库SMOTEN方法时遇到"ValueError: Expected n_neighbors <= n_samples"错误如

问题现象与原因分析

当使用imbalanced-learn库的SMOTEN(Synthetic Minority Over-sampling Technique for Nominal features)方法处理分类数据时,开发者常会遇到以下报错:

ValueError: Expected n_neighbors <= n_samples, 
but n_neighbors = 6, n_samples = 5

这个错误的核心原因是最近邻算法的参数配置问题。SMOTEN默认使用n_neighbors=5作为最近邻数量,但当少数类样本数少于或等于该值时,算法无法找到足够的邻居进行插值。

四种解决方案

1. 调整n_neighbors参数

最直接的解决方法是修改n_neighbors参数,使其不超过少数类样本数:

from imblearn.over_sampling import SMOTEN

smo = SMOTEN(n_neighbors=3)  # 调整为小于最小类别样本数的值
X_res, y_res = smo.fit_resample(X, y)

注意事项:值过小可能导致生成的样本多样性不足。

2. 使用SMOTEN的变体方法

当样本极少时,可以考虑使用SMOTENC(混合数据类型)或ADASYN等替代方法:

from imblearn.over_sampling import SMOTENC

smo = SMOTENC(categorical_features=[0,1], n_neighbors=2)
X_res, y_res = smo.fit_resample(X, y)

3. 数据预处理策略

通过欠采样多数类或人工收集更多少数类样本:

  • 使用RandomUnderSampler平衡类别分布
  • 采用数据增强技术扩增现有样本

4. 分层抽样保障最小样本量

在数据划分阶段使用分层抽样确保训练集包含足够样本:

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X, y, stratify=y, test_size=0.2)

三种预防措施

  1. 样本量检查:实施前验证少数类样本数
  2. 参数验证:建立n_neighbors动态调整机制
  3. 监控系统:设置异常处理流程

典型应用场景代码

处理医疗诊断数据中的罕见病例分类:

import pandas as pd
from collections import Counter

# 模拟医疗数据集
data = pd.DataFrame({
    '症状': ['发烧', '咳嗽', '头痛', '皮疹', '乏力'],
    '诊断': ['流感', '流感', '流感', '麻疹', '流感']
})

print("原始分布:", Counter(data['诊断']))

# 安全执行SMOTEN
try:
    smoten = SMOTEN(random_state=42)
    X_res, y_res = smoten.fit_resample(data[['症状']], data['诊断'])
except ValueError as e:
    print(f"执行失败: {e}")
    smoten = SMOTEN(n_neighbors=2)
    X_res, y_res = smoten.fit_resample(data[['症状']], data['诊断'])

print("过采样后:", Counter(y_res))

性能优化建议

策略 实施方法 效果
特征工程 合并相似类别 增加有效样本量
算法选择 改用Borderline-SMOTE 提升边界样本质量
硬件加速 使用GPU版imbalanced-learn 加快计算速度

通过合理配置超参数和采用防御性编程策略,可以有效避免SMOTEN应用中常见的邻居数错误问题。