多线性回归中cross_val_score返回异常R²值的问题排查
问题描述
使用cross_val_score评估多元线性回归模型时,指定scoring='r2',但返回的评分并非正常R²值(正常范围[-1,1]),反而出现类似RMSE或负均方误差的极端负值(均值-5076.400,标准差12227.956)。但通过简单的Train Test Split验证,不同测试集下R²值在0.14-0.97之间,预测年龄结果合理,散点图也显示预测值与实际值有相关性,交叉验证结果完全不符合R²取值逻辑,请求排查原因。
训练测试拆分验证代码与结果
# 使用训练测试拆分验证模型精度与过拟合情况 from sklearn.model_selection import cross_val_score, train_test_split X_train, X_test, y_train, y_test = train_test_split(dftotal_ni, dfy_ni, test_size=0.12, random_state=42) score = lm_ni.score(X_test, y_test) print(score)
输出:0.5729935257330477
预测值与实际年龄散点图

交叉验证代码与结果
from sklearn import datasets from sklearn.metrics import r2_score as r2 from sklearn.metrics import root_mean_squared_error as rms from sklearn.model_selection import KFold from numpy import mean, std from sklearn.preprocessing import MinMaxScaler # 为交叉验证创建新模型 lm_ni_val = LinearRegression() scoring = 'r2' # 用KFold评估模型 scores = cross_val_score( lm_ni_val, dftotal_ni, dfy_ni, scoring=scoring, cv=8, n_jobs=-1) # 输出评分均值与标准差 print('Accuracy: %.3f ,\nStandard Deviations :%.3f' % (mean(scores), std(scores)))
输出:
Accuracy: -5076.400 , Standard Deviations :12227.956
排查与解决方法
- 特征未做标准化处理:线性回归对特征尺度极度敏感,若不同特征数值范围差异极大(比如部分特征是0-1,部分是上万级),会导致部分交叉验证fold中模型拟合彻底失效,R²出现极端负值。你已导入
MinMaxScaler但未实际使用,建议用Pipeline封装预处理与模型,避免数据泄露:from sklearn.pipeline import Pipeline pipeline = Pipeline([ ('scaler', MinMaxScaler()), ('model', LinearRegression()) ]) scores = cross_val_score(pipeline, dftotal_ni, dfy_ni, scoring='r2', cv=8, n_jobs=-1) - 交叉验证fold数据分布异常:检查各fold的测试集数据分布,是否存在某一fold的测试集样本与整体数据偏差极大(比如极端年龄样本集中在单个fold),导致模型完全无法预测。可手动拆分KFold查看各fold统计特征:
kf = KFold(n_splits=8, shuffle=True, random_state=42) for fold, (train_idx, test_idx) in enumerate(kf.split(dftotal_ni)): y_test_fold = dfy_ni.iloc[test_idx] print(f"第{fold+1}折测试集年龄统计:均值{y_test_fold.mean()}, 标准差{y_test_fold.std()}") - 特征存在严重多重共线性:若特征间高度线性相关,会导致线性回归参数估计不稳定,部分fold中出现拟合崩溃。可通过方差膨胀因子(VIF)检测:
若VIF值大于5(或10),说明存在严重多重共线性,需移除相关特征或进行降维处理。from statsmodels.stats.outliers_influence import variance_inflation_factor import pandas as pd vif_data = pd.DataFrame() vif_data["特征名"] = dftotal_ni.columns vif_data["VIF值"] = [variance_inflation_factor(dftotal_ni.values, i) for i in range(dftotal_ni.shape[1])] print(vif_data)
内容的提问来源于stack exchange,提问作者Mike Coggins
相关产品推荐
相关产品推荐

