如何将自定义拆分的DataFrame作为训练集与验证集传入GridSearchCV?
自定义时间拆分验证集的GridSearchCV参数调优问题
问题背景
我是一名刚涉足机器学习领域的程序员,现有2010-2019年的数据,需对梯度提升回归(GradientBoostingRegressor)模型进行参数调优,计划采用60%数据训练、20%验证、20%测试的方案。根据研究需求,我已按时间维度拆分出:train_df(2010-2014年)、evaluate_df(2015-2017年)、test_df(2018-2019年)。期望用train_df训练模型,evaluate_df作为验证集调参,最终用最优模型在test_df上测试。
我的代码如下:
p_test3 = {'learning_rate':[0.1,0.05,0.01,0.005], 'n_estimators':[500,750,1000,1250,1500]} tuning = GridSearchCV(estimator =GradientBoostingRegressor( min_samples_split=2, min_samples_leaf=1, subsample=1,max_features='sqrt', random_state=10), param_grid = p_test3, scoring='r2',n_jobs=-1, cv=evaluate_df) tuning.fit(train_df[[col1]],train_df['col2']) tuning.cv_results_, tuning.best_params_, tuning.best_score_
运行后出现报错:
ValueError: too many values to unpack (expected 2)
错误原因
GridSearchCV的cv参数不支持直接传入DataFrame。该参数的合法输入包括:
- 整数(表示K折交叉验证的折数)
- 交叉验证生成器/迭代器
PredefinedSplit对象- 包含
(train_idx, val_idx)索引对的列表
直接传入evaluate_df会导致内部解析时无法正确拆分成训练/验证索引对,因此抛出too many values to unpack错误。
解决方案
针对固定时间拆分的验证集需求,有两种可行实现方式:
方式1:使用PredefinedSplit
将训练集和验证集合并后,通过标记区分训练/验证样本,再传入PredefinedSplit对象:
import numpy as np import pandas as pd from sklearn.model_selection import GridSearchCV, PredefinedSplit from sklearn.ensemble import GradientBoostingRegressor # 合并训练集与验证集的特征和目标变量 X = pd.concat([train_df[[col1]], evaluate_df[[col1]]], axis=0) y = pd.concat([train_df['col2'], evaluate_df['col2']], axis=0) # 生成拆分标记:-1表示属于训练集,0表示属于验证集 test_fold = np.concatenate([ np.full(len(train_df), -1), np.full(len(evaluate_df), 0) ]) ps = PredefinedSplit(test_fold) # 定义参数网格 p_test3 = {'learning_rate':[0.1,0.05,0.01,0.005], 'n_estimators':[500,750,1000,1250,1500]} # 初始化GridSearchCV,传入PredefinedSplit作为cv参数 tuning = GridSearchCV( estimator=GradientBoostingRegressor( min_samples_split=2, min_samples_leaf=1, subsample=1, max_features='sqrt', random_state=10 ), param_grid=p_test3, scoring='r2', n_jobs=-1, cv=ps ) # 拟合数据 tuning.fit(X, y) # 查看调参结果 print("交叉验证结果:", tuning.cv_results_) print("最优参数:", tuning.best_params_) print("最优R2分数:", tuning.best_score_)
方式2:手动构建索引对
直接定义训练集和验证集的索引列表,组成(train_idx, val_idx)的元组传入cv参数:
import pandas as pd from sklearn.model_selection import GridSearchCV from sklearn.ensemble import GradientBoostingRegressor # 合并训练集与验证集 X = pd.concat([train_df[[col1]], evaluate_df[[col1]]], axis=0) y = pd.concat([train_df['col2'], evaluate_df['col2']], axis=0) # 手动生成训练/验证索引 train_indices = list(range(len(train_df))) val_indices = list(range(len(train_df), len(train_df) + len(evaluate_df))) cv_splits = [(train_indices, val_indices)] # 初始化GridSearchCV tuning = GridSearchCV( estimator=GradientBoostingRegressor( min_samples_split=2, min_samples_leaf=1, subsample=1, max_features='sqrt', random_state=10 ), param_grid=p_test3, scoring='r2', n_jobs=-1, cv=cv_splits ) # 拟合数据并查看结果 tuning.fit(X, y) print(tuning.best_params_, tuning.best_score_)
后续测试
调参完成后,使用最优模型在test_df上测试:
best_model = tuning.best_estimator_ test_r2 = best_model.score(test_df[[col1]], test_df['col2']) print("测试集R2分数:", test_r2)
内容的提问来源于stack exchange,提问作者Mostafa Bouzari
相关产品推荐
相关产品推荐

