如何为GridSearchCV编写可接收超参数的自定义scorer评分函数
解决方法
核心逻辑:scikit-learn的自定义评分函数默认接收三个参数(estimator, X, y_true),其中第一个参数就是当前待评估的、已经在训练折上拟合完成的模型,直接调用get_params()方法即可获取当前验证组的所有超参数,无需额外传参。
1. 定义自定义评分函数
from sklearn.metrics import mean_absolute_error def custom_scorer(estimator, X, y_true): # 计算预测值 y_pred = estimator.predict(X) # 计算平均绝对误差 mae = mean_absolute_error(y_true, y_pred) # 从当前模型中获取本次验证的max_depth取值 current_max_depth = estimator.get_params()["max_depth"] # 计算目标评分:GridSearchCV默认选择得分最高的参数组,因此如果目标是MAE*max_depth越小越好,需要返回负值 return -(mae * current_max_depth)
2. 替换GridSearchCV的scoring参数
将原来的scoring='neg_mean_absolute_error'替换为上面定义的自定义评分函数即可:
from sklearn import model_selection, ensemble params = {'max_depth' : [3, 5, 8, 10], 'max_features' : [3, 4, 5], 'min_samples_leaf' : [10, 20, 50]} model = model_selection.GridSearchCV(ensemble.RandomForestRegressor(n_estimators = 10, random_state = 100), params, cv = model_selection.KFold(n_splits = 3, shuffle = True, random_state = 2023), scoring = custom_scorer) # 后续fit、取最优参数逻辑和原来完全一致 model.fit(X, y) print(model.best_params_)
替代方案:后处理验证结果计算评分
如果不想修改评分逻辑,也可以先按原始MAE完成网格搜索,再从结果表中自行计算目标指标选择最优参数:
# 先按原始指标跑网格搜索 model = model_selection.GridSearchCV(ensemble.RandomForestRegressor(n_estimators = 10, random_state = 100), params, cv = model_selection.KFold(n_splits = 3, shuffle = True, random_state = 2023), scoring = 'neg_mean_absolute_error', return_train_score=False) model.fit(X, y) # 转换结果为DataFrame,计算目标指标 import pandas as pd res_df = pd.DataFrame(model.cv_results_) # 把负MAE转成正的MAE,乘以对应max_depth得到目标值 res_df["target_metric"] = (-res_df["mean_test_score"]) * res_df["param_max_depth"] # 选目标值最小的行对应的参数 best_row = res_df.loc[res_df["target_metric"].idxmin()] print(best_row["params"])
注意事项
- 若使用Pipeline封装模型,参数名会带步骤前缀,比如随机森林步骤命名为
rf,则需要通过estimator.get_params()["rf__max_depth"]获取对应参数 - 自定义评分的返回值需符合scikit-learn的规则:得分越高代表模型效果越好,如果你的目标指标是越小越好(比如误差类指标),需要返回负值,否则GridSearchCV会选出效果最差的参数组合
内容的提问来源于stack exchange,提问作者fds001
相关产品推荐
相关产品推荐

