随机森林训练测试准确率98%,新样本始终预测同一类求助
首先,我完全理解你花30小时调试却毫无头绪的挫败感——这种“训练测试表现完美,但新数据彻底拉胯”的问题,往往出在数据一致性偏差或不平衡数据集的模型倾斜上,而非单纯的参数调优。结合你的描述,我给你梳理几个关键排查方向和落地解决方案:
一、优先排查:新数据与训练集的特征一致性
哪怕你说“数据处理方式一致”,也极可能存在细节偏差,这是此类问题的头号元凶:
1. 核对特征列的完全匹配
Random Forest对输入特征的维度、列名是严格绑定的,哪怕差一列都会导致预测逻辑混乱。你可以运行以下代码快速对比:
# 提取训练集和新数据的特征列集合 train_cols = set(X_train.columns) new_data_cols = set(df.columns) print("训练集有但新数据缺失的列:", train_cols - new_data_cols) print("新数据有但训练集没有的列:", new_data_cols - train_cols)
- 如果有缺失的列:给新数据补上这些列并填充0(训练集独热编码时这些类别不存在,对应值本就是0);
- 如果有新增的列:直接删除,模型训练时从未见过这些特征,无法做出有效判断。
2. 验证特征值的分布差异
训练集和新数据的特征分布漂移,会让模型彻底“看不懂”新数据。你可以:
- 对连续特征:对比训练集和新数据的统计量,比如:
print("训练集某连续特征统计:\n", X_train['feature_name'].describe()) print("新数据对应特征统计:\n", df['feature_name'].describe()) - 对类别特征:检查新数据的类别是否都在训练集的类别范围内(比如训练集某特征只有
['a','b'],新数据却出现'c',独热编码后会新增列导致特征不匹配); - 量化差异:用PSI(群体稳定性指标)衡量特征分布变化,PSI>0.2就说明分布差异极大,需要重新处理数据。
3. 确认缺失值填充逻辑一致
你在新数据中用了df.fillna(-1),那训练集的缺失值是否也是用-1填充的?如果训练集是用均值、中位数或其他方式填充,新数据用-1会导致特征分布完全偏离,模型自然无法正确预测。
二、针对不平衡数据集的模型偏差调整
你的数据集class 0(15万)和class 1(60万)比例为1:4,属于中度不平衡,训练时的高准确率其实是被多数类(class 1)拉高的,模型可能对少数类的泛化能力极差——但你说新数据全预测为class 0,需要先明确真实概率情况:
1. 查看预测概率而非直接类别
别只用predict(),改用predict_proba()查看模型对新样本的真实概率输出:
probs = model.predict_proba(df) # 查看前10个样本的class 0和class 1概率 print(probs[:10])
- 如果所有样本的class 0概率显著高于0.5:要么新数据确实都是class 0(可以人工验证几个样本),要么新数据特征和训练集的class 0完全重合;
- 如果概率接近0.5但被默认阈值(0.5)划到class 0:可以调整阈值,比如把class 1的预测阈值调低,提升对多数类的敏感度;
- 如果概率极端偏向class 0:大概率是预处理导致新数据特征与训练集class 0特征完全一致。
2. 重新评估模型的真实性能
训练集和测试集的98%-99%准确率没有参考价值——哪怕模型全预测class 1,准确率也有80%。你需要查看混淆矩阵和分类报告:
from sklearn.metrics import classification_report, confusion_matrix print("训练集分类报告:") print(classification_report(y_train, model.predict(X_train))) print("训练集混淆矩阵:") print(confusion_matrix(y_train, model.predict(X_train)))
重点看class 0的召回率:如果召回率很低,说明模型根本没学会识别class 0;如果召回率很高,那问题还是出在新数据的预处理上。
3. 调整模型的类别权重
给少数类更高的权重,强迫模型关注少数类的特征:
model = RandomForestClassifier( n_estimators=N_ESTIMATORS, max_depth=MAX_DEPTH, random_state=RANDOM_STATE, oob_score=True, class_weight='balanced' # 自动调整类别权重,反比于类别频率 )
也可以用class_weight='balanced_subsample',它会在每个决策树采样时调整权重,更适配随机森林的特性。
4. 尝试重采样方法
如果调整权重效果不好,可以对数据集进行重采样:
- 过采样:对class 0的样本进行复制或用SMOTE合成新样本,让两类样本数量接近;
- 欠采样:对class 1的样本随机删除,减少多数类样本数量;
- 注意:重采样要在划分训练集和测试集之后进行,避免数据泄露。
三、其他排查点
- 检查特征重要性:运行
model.feature_importances_,看看哪些特征是模型最关注的。如果这些关键特征在新数据中的分布和训练集差异极大,会直接导致预测偏差; - 验证OOB分数的真实性:OOB分数同样会被多数类拉高,你可以手动计算OOB的混淆矩阵,看看模型对少数类的OOB表现;
- 反向验证新数据:把少量新数据加入训练集重新训练,看模型是否能正确识别这些样本。如果还是不行,说明新数据的特征确实和训练集存在本质差异。
按照这个顺序排查,应该能快速定位问题。如果还是解决不了,可以提供新数据的特征统计量、模型的分类报告,或者几个新样本的特征值,方便进一步分析。
内容的提问来源于stack exchange,提问作者DL_Engineer




