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

如何使用sklearn的cross_validate仅在评分阶段对样本加权?

解决Sklearn交叉验证中仅基于真实样本评分的问题

问题原因

你遇到的ValueError是因为直接将全局的100个样本权重arr_weight传给make_scorer,但交叉验证时每个折的测试集只有20个样本,权重数组维度与测试集不匹配,导致报错。

解决方案

推荐手动实现交叉验证循环,这种方式直观且能精确控制训练/测试流程,完全匹配你的需求:

  1. 训练时使用所有训练样本(真实+增强),不区分权重;
  2. 评分时仅用测试集中的真实样本(增强样本权重设为0)。

修正后的代码

from sklearn import model_selection
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score, mean_squared_error
import numpy as np

# 生成模拟数据(修正回归任务的target为一维数组)
n_smpl, n_feats = 100, 5
arr_source = np.random.random((n_smpl, n_feats))
arr_target = np.random.random(n_smpl)  # 回归任务target应为一维
arr_weight = np.random.randint(0, 2, n_smpl)  # 0=增强样本,1=真实样本

model = RandomForestRegressor()
kfold_splitter = model_selection.KFold(n_splits=5, random_state=7, shuffle=True)

# 存储各折的评分结果
cv_r2_scores = []
cv_mse_scores = []

# 遍历每个交叉验证折
for train_idx, test_idx in kfold_splitter.split(arr_source):
    # 拆分训练/测试集
    X_train, X_test = arr_source[train_idx], arr_source[test_idx]
    y_train, y_test = arr_target[train_idx], arr_target[test_idx]
    
    # 训练模型:训练集包含所有样本,权重默认全为1
    model.fit(X_train, y_train)
    
    # 预测测试集
    y_pred = model.predict(X_test)
    
    # 获取当前测试集对应的权重(仅真实样本权重为1)
    test_weights = arr_weight[test_idx]
    
    # 计算加权评分
    r2 = r2_score(y_test, y_pred, sample_weight=test_weights)
    mse = mean_squared_error(y_test, y_pred, sample_weight=test_weights)
    
    cv_r2_scores.append(r2)
    cv_mse_scores.append(mse)

# 输出交叉验证结果
print(f"交叉验证平均R2: {np.mean(cv_r2_scores):.4f} ± {np.std(cv_r2_scores):.4f}")
print(f"交叉验证平均MSE: {np.mean(cv_mse_scores):.4f} ± {np.std(cv_mse_scores):.4f}")

关键说明

  • 手动拆分train_idx和test_idx,确保每个折的权重数组test_weights与测试集维度完全匹配;
  • 训练时未传入sample_weight,默认所有训练样本权重为1,符合你“训练不区分样本来源”的需求;
  • 评分时仅对测试集中的真实样本(test_weights=1)计算指标,增强样本(test_weights=0)不影响评分结果。

替代方案(不推荐)

如果坚持使用cross_validate,可以通过闭包传递权重数组,但需注意样本无重复值的前提:

from sklearn import model_selection
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score, mean_squared_error, make_scorer
import numpy as np

n_smpl, n_feats = 100, 5
arr_source = np.random.random((n_smpl, n_feats))
arr_target = np.random.random(n_smpl)
arr_weight = np.random.randint(0, 2, n_smpl)

# 自定义评分函数,通过闭包获取原始权重
def weighted_r2(y_true, y_pred):
    test_idx = np.where(np.in1d(arr_target, y_true))[0]
    return r2_score(y_true, y_pred, sample_weight=arr_weight[test_idx])

def weighted_mse(y_true, y_pred):
    test_idx = np.where(np.in1d(arr_target, y_true))[0]
    # MSE需取负值,因为sklearn评分默认越大越好
    return -mean_squared_error(y_true, y_pred, sample_weight=arr_weight[test_idx])

model = RandomForestRegressor()
kfold_splitter = model_selection.KFold(n_splits=5, random_state=7, shuffle=True)
my_scorers = {
    "r2_weighted": make_scorer(weighted_r2),
    "mse_weighted": make_scorer(weighted_mse)
}

cv_results = model_selection.cross_validate(model, arr_source, arr_target, scoring=my_scorers, cv=kfold_splitter)
print(f"平均R2: {np.mean(cv_results['test_r2_weighted']):.4f}")
print(f"平均MSE: {-np.mean(cv_results['test_mse_weighted']):.4f}")

注意:该方法依赖arr_target无重复值,否则会出现索引匹配错误,因此优先推荐手动循环的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 05:54:51