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

如何在GridSearchCV中传递自定义迭代器参数至自定义评分函数?

问题:如何在GridSearchCV中向自定义评分函数传递交叉验证迭代的元数据?

相关依赖导入

from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import PredefinedSplit
from sklearn.base import clone
from sklearn.metrics import make_scorer
from mlxtend.evaluate import bias_variance_decomp
from sklearn.neighbors import KNeighborsRegressor
import numpy as np

原实现代码

自定义交叉验证迭代器(不符合sklearn规范)

原代码尝试直接返回fold数据和克隆的估计器,但sklearn的CV组件仅接受返回(train_index, test_index)的迭代器:

knn = KNeighborsRegressor()
X_train_len = int(round(len(X_train_knn)*0.8, 0))
test_fold = np.hstack([-1 * np.ones(X_train_len), np.zeros(len(X_train_knn)-X_train_len)])
ps = PredefinedSplit(test_fold)

def custom_iterator(X_train_knn, Y_train_ar, estimator, ps=ps):
    for train_index, test_index in ps.split():
        X_train_fold, X_test_fold = X_train_knn[train_index], X_train_knn[test_index]
        y_train_fold, y_test_fold = Y_train_ar[train_index], Y_train_ar[test_index]
        estimator1 = clone(estimator)
        yield X_train_fold, X_test_fold, y_train_fold, y_test_fold, estimator1

iterator = custom_iterator(X_train_knn, Y_train_ar, estimator=knn, ps=ps )

自定义评分函数

原函数需要接收fold数据和估计器来计算偏差-方差分解的期望损失:

def custom_loss_func(y_true, y_pred, estimator1, X_train_fold, X_test_fold, y_train_fold, y_test_fold):
    avg_expected_loss, avg_bias, avg_var = bias_variance_decomp(
        estimator1, X_train_fold, y_train_fold, X_test_fold, y_test_fold,
        loss='mse', random_seed=0
    )
    return avg_expected_loss

score = make_scorer(custom_loss_func, greater_is_better=False).set_score_request(
    estimator1=True, X_train_fold=True, X_test_fold=True, y_train_fold=True, y_test_fold=True
)

GridSearchCV配置

knn = KNeighborsRegressor()
param_grid = dict(
    n_neighbors=np.arange(1,21,1),
    weights=['uniform', 'distance'],
    p=np.arange(1,4,1)
)
scoring_metrics = {
    'neg_root_mean_squared_error': 'neg_root_mean_squared_error',
    'r2': 'r2',
    'score_func': score
}

grid = GridSearchCV(
    knn, param_grid, cv=custom_iterator,
    scoring=scoring_metrics, refit=score, verbose=2, n_jobs=-1
)

核心问题:如何在每次交叉验证迭代中,将X_train_fold, X_test_fold, y_train_fold, y_test_fold, estimator1传递给自定义评分函数?已尝试用set_score_request声明参数,但不知道如何在迭代中传递,是否可以通过Metadata Routing实现?


解决方案

1. 遵循sklearn CV接口规范

sklearn的CV迭代器必须返回(train_index, test_index),而非直接返回fold数据。我们可以直接使用PredefinedSplit作为cv参数,无需自定义迭代器。

2. 利用Metadata Routing传递元数据

sklearn的Metadata Routing允许评分函数请求额外的上下文数据(如当前估计器、训练/测试索引、完整训练集等)。调整评分函数,通过索引提取当前fold的数据:

修改自定义评分函数

def custom_loss_func(y_true, y_pred, estimator, X, y, train_indices, test_indices):
    # 通过索引提取当前fold的训练/测试数据
    X_train_fold = X[train_indices]
    y_train_fold = y[train_indices]
    X_test_fold = X[test_indices]
    y_test_fold = y[test_indices]
    
    # 克隆估计器用于偏差-方差分解(避免影响GridSearchCV中的拟合实例)
    cloned_estimator = clone(estimator)
    avg_expected_loss, _, _ = bias_variance_decomp(
        cloned_estimator, X_train_fold, y_train_fold, X_test_fold, y_test_fold,
        loss='mse', random_seed=0
    )
    return avg_expected_loss

# 声明评分函数需要的元数据
score = make_scorer(custom_loss_func, greater_is_better=False).set_score_request(
    estimator=True, X=True, y=True, train_indices=True, test_indices=True
)

配置并运行GridSearchCV

# 初始化PredefinedSplit
X_train_len = int(round(len(X_train_knn)*0.8, 0))
test_fold = np.hstack([-1 * np.ones(X_train_len), np.zeros(len(X_train_knn)-X_train_len)])
ps = PredefinedSplit(test_fold)

# 启用估计器的Metadata Routing
knn = KNeighborsRegressor()
knn.set_fit_request(X=True, y=True)
knn.set_score_request(X=True, y=True)

# 配置GridSearchCV
param_grid = dict(
    n_neighbors=np.arange(1,21,1),
    weights=['uniform', 'distance'],
    p=np.arange(1,4,1)
)
scoring_metrics = {
    'neg_root_mean_squared_error': 'neg_root_mean_squared_error',
    'r2': 'r2',
    'score_func': score
}

grid = GridSearchCV(
    knn, param_grid, cv=ps,
    scoring=scoring_metrics, refit='score_func', verbose=2, n_jobs=-1
)

# 执行网格搜索
grid.fit(X_train_knn, Y_train_ar)

关键说明

  • 无需自定义迭代器:PredefinedSplit已经满足交叉验证划分需求,GridSearchCV会自动处理索引传递。
  • 元数据请求:通过set_score_request声明评分函数需要的参数,GridSearchCV会自动在每次迭代中传递这些元数据。
  • 克隆估计器:bias_variance_decomp需要多次训练模型,克隆当前参数的估计器可以避免干扰GridSearchCV内部的拟合流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:34:56