小数据集回归交叉验证R²值差异极大的原因及解决办法
小数据集交叉验证R²波动大的原因与解决办法
你的判断是否正确?
你的推测有一定道理,但核心原因并非“训练集未覆盖全部特征”,而是小数据集下K折划分的样本分布波动过大:10折交叉验证时,每折仅含10个测试样本、90个训练样本,一旦某折的测试集包含了偏离整体分布的异常点,或者训练集恰好缺失了关键的数据模式,模型的泛化能力会暴跌,直接导致R²值极低。另外你代码中对R²取绝对值的操作,会掩盖模型表现极差(R²为负,说明模型不如直接预测均值)的情况,也放大了“差异大”的观感。
无法扩充数据集的可行解决办法
- 改用留一交叉验证(LOOCV):针对小数据集,LOOCV每次仅用1个样本做测试,结果的方差远低于K折,稳定性更强。在sklearn中可以直接用
LeaveOneOut()替换KFold作为cv参数。 - 停止对R²取绝对值:真实的R²值能反映模型的实际表现,负R²是重要的失效信号,不要人为掩盖。
- 简化模型+正则化:你当前测试到10阶多项式,小数据集下高阶多项式极易过拟合。先从1-3阶多项式入手,替换普通线性回归为Ridge/Lasso回归,通过正则化限制模型复杂度,避免在小训练集中学习到噪声。
- 调整K折参数:如果坚持用K折,可减小K值(比如5折),让每折的训练集规模更大,数据分布更接近整体,降低结果波动;同时设置
random_state固定随机种子,保证结果可复现。 - 检查数据质量:小数据集中异常值的影响会被放大,先通过箱线图、Z-score等方法检测并处理异常值,确认归一化操作正确无误。
你的代码与输出整理
代码
from sklearn.model_selection import cross_val_score from sklearn.model_selection import KFold from sklearn.metrics import r2_score import numpy as np # 假设lin_regressor、X_normalized、y_for_normalized已提前定义 crossvalidation_poly = KFold(n_splits=10, shuffle=True) for i in range(1,11): poly_cross_validation = PolynomialFeatures(degree=i) # 修正代码笔误:使用当前循环定义的poly_cross_validation对象 X_current = poly_cross_validation.fit_transform(X_normalized) model = lin_regressor.fit(X_current, y_for_normalized) scores = cross_val_score(model, X_current, y_for_normalized, scoring='r2', cv=crossvalidation_poly, n_jobs=1) print(f"\n\nDegree-{i} polynomial: R^2 for every fold: {scores}") print(f"Degree-{i} polynomial: Average R^2 for all the folds: {np.mean(scores)}, STD: {np.std(scores)}")
输出(Degree-1示例)
Degree-1 polynomial: R^2 for every fold: [0.4211881 0.1594833 0.330413 0.33658905 0.85793866 0.46608985 0.83313018 0.01226627 0.12584021 0.88849593] Degree-1 polynomial: Average R^2 for all the folds: 0.4431434552827308, STD: 0.41377024559244985
内容的提问来源于stack exchange,提问作者Z47
相关产品推荐
相关产品推荐

