You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数据平衡后KNN模型无法识别全部类别问题求助

问题分析与解决方案

先来说说你遇到的两个核心问题,以及重采样后训练前必须做的关键步骤:

一、为什么原始KNN模型准确率1.0,但新数据无法识别最小类别?

你的原始数据集极度不平衡,而准确率是一个对不平衡数据极不友好的指标——模型只要一直预测占比75%的类别,就能轻松拿到75%的准确率,但你这里拿到了1.0,大概率是两种情况:

  1. 特征存在标签泄露:比如某个特征直接和标签强相关(甚至就是标签的变形),导致KNN能完美区分训练/测试集中的所有类别,但这种完美只存在于你的现有数据中,新数据没有这种泄露,所以模型失效。
  2. 训练集与测试集特征分布高度重合:虽然用了StratifiedShuffleSplit,但如果数据本身的特征簇完全分离,KNN确实能做到全对,但新数据的特征分布和训练集差异大,导致模型无法泛化到小类别。

结合你说的“新数据总是把最小类别误分类为第二小的类别”,更倾向于模型在小类别上根本没学到有效特征——毕竟原始数据中小类别样本太少,KNN很难捕捉到它们的特征模式。

二、为什么SMOTEENN处理后,模型只识别出2个类别?

看你给出的分类报告,测试集的support只有类别0和1,说明你的测试集中根本没有其他两个类别!这大概率是拆分数据集时的低级错误:

  • 你处理完数据得到X_res和y_res后,是不是还在用之前针对原始X、y生成的train_index和test_index?这完全错误,因为X_res是重采样后的新数组,索引和原始数据不匹配,抽取的样本自然会混乱,甚至只包含部分类别。
  • 另外,你可能没有用分层抽样拆分重采样后的数据:即使数据平衡了,随机拆分也可能出现极端情况(虽然概率低),但分层抽样能强制保证训练集和测试集的类别分布与整体一致。

三、重采样后训练KNN前必须做的步骤

针对你的情况,这些步骤缺一不可:

1. 用分层抽样重新拆分数据集

重采样后的数据是平衡的,但必须用分层抽样确保训练/测试集都包含所有类别。替换你的拆分代码:

# 用train_test_split的stratify参数更简洁
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(X_res, y_res, test_size=0.2, stratify=y_res, random_state=42)

或者继续用StratifiedShuffleSplit,但要基于X_res和y_res生成新索引:

sss = StratifiedShuffleSplit(n_splits=5, test_size=0.2, random_state=42)
train_index, test_index = next(sss.split(X_res, y_res))  # 这里必须用重采样后的X_res和y_res
x_train, y_train = X_res[train_index], y_res[train_index]
x_test, y_test = X_res[test_index], y_res[test_index]

拆分后一定要验证测试集的类别分布:

from collections import Counter
print("测试集类别分布:", Counter(y_test))

正常情况下应该是每个类别各1500个样本(7500*0.2=1500)。

2. 对特征进行标准化/归一化

KNN是基于距离的模型,特征的尺度差异会严重影响距离计算——比如某个特征取值范围是0-1000,另一个是0-1,KNN会几乎只依赖前者。重采样后,SMOTE生成的样本基于特征空间,归一化后生成的样本更合理,模型效果也会更稳定:

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
x_train = scaler.fit_transform(x_train)
x_test = scaler.transform(x_test)  # 测试集必须用训练集的scaler拟合,避免数据泄露

如果你用欧氏距离,也可以用MinMaxScaler将特征归一化到0-1区间。

3. 调整KNN的参数

平衡数据后,原来的k=5可能不是最优选择:

  • 尝试更大的k值(比如k=10、15),减少噪声样本的影响;
  • 使用加权KNN:KNeighborsClassifier(weights='distance'),让距离更近的样本拥有更高权重,帮助模型更好捕捉小类别的特征;
  • 尝试不同的距离度量,比如曼哈顿距离(metric='manhattan'),对异常值更鲁棒。

4. 验证重采样后的数据有效性

虽然你看到SMOTEENN处理后四个类别各7500,但可以检查生成的样本是否合理:比如查看小类别生成的样本特征是否和原始小类别样本分布一致,避免SMOTE生成无意义的噪声样本。

最后

按上述步骤调整后,你的模型应该能识别所有四个类别了。另外,评价模型时不要只看准确率,重点关注小类别的recall和f1-score——这才是不平衡数据下模型性能的关键指标。

内容的提问来源于stack exchange,提问作者demeflac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:49:21