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

使用LOGO/LOO交叉验证时Grid Search的best_score为nan问题排查

Grid Search搭配LOGO/LOO交叉验证时R2评分为NaN的问题排查与解决

问题重现

使用XGBoost结合Grid Search做回归任务时,10折交叉验证可正常输出R2分数,但切换为**LeaveOneGroupOut (LOGO)或LeaveOneOut (LOO)**时,所有R2评分均为NaN。已确认训练集无缺失值,核心代码及运行输出如下:

核心代码

FDODB=pd.read_excel('Final Training Set for LOGO.xlsx')
array = FDODB.values
X = array[:,2:126]
Y = array[:,1]
Compd = array[:,0]

scaler = StandardScaler()
X = scaler.fit_transform(X)

params = {
    'max_depth': [5,7,9],
    'learning_rate': [0.03,0.05,0.07],
    'n_estimators': [200,300,400],
    'min_child_weight': [5,7,9],
    'subsample': [0.3, 0.5, 0.7],
    'base_score': [0.4, 0.5, 0.6]
}

xgb_reg = XGBRegressor(tree_method='hist', device='cuda')
logo = LeaveOneGroupOut()

grid_search = GridSearchCV(
    estimator=xgb_reg,
    param_grid=params,
    scoring='r2',
    error_score="raise",
    cv=logo,
    verbose=2,
    n_jobs=-1,
    return_train_score=True
)

grid_search.fit(X, Y, groups=Compd)

best_params = grid_search.best_params_
best_score = grid_search.best_score_

print('Best hyperparameters:', best_params)
print('Best R2 score:', best_score)

运行输出

c:\Anaconda\envs\machinelearning\Lib\site-packages\sklearn\model_selection_search.py:1102: UserWarning: One or more of the test scores are non-finite: [nan]
warnings.warn(
Best hyperparameters: {'base_score': 0.5, 'learning_rate': 0.03, 'max_depth': 8, 'min_child_weight': 6, 'n_estimators': 200, 'subsample': 0.3}
Best R2 score: nan

原因分析

  • 测试集标签方差为0:LOGO/LOO的某一轮验证中,测试组的Y值完全相同(方差为0)。R2计算依赖分母var(y_true),当分母为0时会直接返回NaN,这种情况在分组后单组样本量极小(如单样本组)时极易出现。
  • 分组逻辑异常:Compd分组可能存在仅含1个样本的组,或部分组内所有样本的Y值完全一致,导致验证时触发R2计算的无效场景。

解决方法

  • 检查并修正分组数据:
    统计每个分组的样本量及Y值方差,定位问题分组:

    import pandas as pd
    FDODB['Compd'] = FDODB.iloc[:,0]
    FDODB['Y'] = FDODB.iloc[:,1]
    group_stats = FDODB.groupby('Compd')['Y'].agg(['count', 'var'])
    # 输出方差为0的分组
    print(group_stats[group_stats['var'] == 0])
    

    对这类分组可选择合并同类型组,或直接从数据集中移除。

  • 替换为鲁棒性评分指标:
    改用对无方差样本更友好的指标,比如MSE、MAE,或自定义鲁棒版R2:

    from sklearn.metrics import make_scorer
    import numpy as np
    
    def robust_r2(y_true, y_pred):
        var_true = np.var(y_true)
        if var_true == 0:
            # 若真实值无波动,预测完全匹配则得1分,否则0分
            return 1.0 if np.allclose(y_true, y_pred) else 0.0
        # 加极小值避免分母为0
        return 1 - np.sum((y_true - y_pred)**2) / (np.sum((y_true - np.mean(y_true))**2) + 1e-10)
    
    # 在GridSearch中使用自定义评分器
    grid_search = GridSearchCV(
        estimator=xgb_reg,
        param_grid=params,
        scoring=make_scorer(robust_r2),
        error_score="raise",
        cv=logo,
        verbose=2,
        n_jobs=-1,
        return_train_score=True
    )
    
  • 调整交叉验证策略:
    若分组样本量差异过大,可改用GroupKFold,将每组拆分为多份参与验证,避免单组全量作为测试集导致的方差为0问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:43:27