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

使用LeaveOneOut()的cross_val_score为何出现NaN验证分数?

问题原因分析与解决方案

核心原因

你遇到的全NaN问题,本质是LinearRegression默认的R²评分指标在单样本测试集上无法计算。

R²(决定系数)的计算公式是:

R² = 1 - (Σ(y_true - y_pred)² / Σ(y_true - y_mean)²)

其中y_mean是测试集真实值的平均值。当使用LeaveOneOut时,每次的测试集只有1个样本,此时y_mean就等于这个样本的真实值,导致分母Σ(y_true - y_mean)² = 0,除法运算直接返回NaN。不管是用cross_val_score还是手动实现交叉验证,只要测试集是单样本,用R²评分都会出现这个问题。

解决方案

1. 更换适合单样本的评分指标

放弃默认的R²,改用不需要计算样本均值的回归指标,比如均方误差(MSE)、平均绝对误差(MAE)。在cross_val_score中通过scoring参数指定即可:

from sklearn.model_selection import LeaveOneOut
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
import numpy as np

iris = load_iris()
kfindex = LeaveOneOut()
model = LinearRegression()
# 使用负均方误差(sklearn中回归指标默认返回负值,方便统一最大化逻辑)
scores = cross_val_score(model, iris.data, iris.target, cv=kfindex, scoring='neg_mean_squared_error')
# 取绝对值后计算均值
print(np.abs(scores).mean(), scores.shape, scores)

手动实现的版本也可以替换成对应指标:

i = 0
scores = []
for train_x_indices, test_x_indeces in kfindex.split(iris.data):
    xtrain, xtest = iris.data[train_x_indices], iris.data[test_x_indices]
    ytrain, ytest = iris.target[train_x_indices], iris.target[test_x_indices]
    i += 1

    model.fit(xtrain, ytrain)
    y_pred = model.predict(xtest)
    # 计算均方误差
    mse = np.mean((y_pred - ytest)**2)
    scores.append(mse)
print(i)
print(scores, np.mean(scores))

2. 改用多样本的交叉验证策略

如果一定要用R²评分,可以换成K-Fold(比如k=5或10),这样每次测试集有多个样本,y_mean不会等于单个样本值,R²可以正常计算:

from sklearn.model_selection import KFold

kfindex = KFold(n_splits=10, shuffle=True, random_state=42)
scores = cross_val_score(model, iris.data, iris.target, cv=kfindex)
print(scores.mean(), scores.shape, scores)

3. 自定义评分函数(可选)

如果坚持要在LeaveOneOut场景下用类似R²的逻辑,可以自定义评分函数处理单样本情况,比如当测试集只有1个样本时,直接比较预测值和真实值的差异:

from sklearn.metrics import make_scorer

def custom_r2(y_true, y_pred):
    if len(y_true) == 1:
        # 单样本时,预测值等于真实值则返回1,否则返回0
        return 1.0 if np.isclose(y_pred[0], y_true[0]) else 0.0
    # 多样本时用默认R²计算
    ss_res = np.sum((y_true - y_pred)**2)
    ss_tot = np.sum((y_true - np.mean(y_true))**2)
    return 1 - (ss_res / ss_tot)

# 转换为sklearn可用的评分器
custom_scorer = make_scorer(custom_r2)
scores = cross_val_score(model, iris.data, iris.target, cv=kfindex, scoring=custom_scorer)
print(scores.mean(), scores.shape, scores)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:47:42