make_scorer是必须的,因为scikit-learn评估接口仅接受符合其调用协议的标准scorer对象,它将自定义函数包装为接收estimator、x、y_true等参数并返回标量的对象,并处理方向、proba/threshold等细节。

自定义 scorer 时为什么 make_scorer 是必须的?
Scikit-learn 的评估接口(如 cross_val_score、GridSearchCV)只认标准 scorer 对象,不接受裸函数。直接传入一个返回 float 的函数会报错:TypeError: scoring must be a string or callable,但即使 callable 也得满足 scorer 协议:接收 estimator、X、y_true、y_pred(或 y_score)等参数,并返回标量。
make_scorer 就是干这个转换的:它把你的逻辑包装成符合 sklearn 内部调用约定的对象,并处理方向(比如越小越好还是越大越好)、是否需要预测概率等细节。
实操要点:
- 必须用
make_scorer包装,不能直接传函数 - 如果自定义函数接收的是
y_true和y_pred(分类),设greater_is_better=True;如果是损失类(如 MAE),设greater_is_better=False - 若需用预测概率(如 AUC),加
needs_proba=True;若需决策函数输出(如 SVM 的 raw decision),加needs_threshold=True
怎么写一个带参数的自定义得分函数?
常见需求:比如只对某类样本(如正例)计算 F1,或给误分类加权重。这时函数本身要支持参数,而 make_scorer 允许你通过 **kwargs 透传。
例如,实现“仅在正样本上计算准确率”:
def positive_accuracy(y_true, y_pred):
mask = (y_true == 1)
if mask.sum() == 0:
return 0.0
return (y_true[mask] == y_pred[mask]).mean()
pos_acc_scorer = make_scorer(positive_accuracy, greater_is_better=True)
注意坑:
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
- 函数内部要做边界检查(如全负样本时
mask.sum() == 0),否则cross_val_score遇到空切片会报ZeroDivisionError或 NaN - 不要在函数里做 fit 或数据变换——scorer 只负责评估,所有拟合已在外部完成
- 参数不能是 estimator 实例或训练数据,只能是超参类静态值(如
beta=2、class_weight={0:1,1:5})
为什么 y_pred 和 y_score 容易混淆?
很多自定义 scorer 写错,是因为没分清模型输出类型。y_pred 是硬标签(0/1),y_score 是概率或决策值(如 predict_proba[:, 1] 或 decision_function)。scorer 默认传 y_pred,但像 roc_auc_score 必须用 y_score。
正确做法:
- 用
roc_auc_score时,必须设needs_proba=True(对predict_proba)或needs_threshold=True(对decision_function) - 别在 scorer 里手动调
model.predict_proba()——sklearn 会根据 flag 自动选方法并传入 - 验证时可临时打印
type(y_score)和y_score.shape确认输入是否符合预期
GridSearchCV 中多个自定义 scorer 怎么共存?
scoring 参数支持字典,键是 scorer 名,值是 scorer 对象。但要注意:只有第一个 scorer 用于早停和最佳模型选择,其余仅记录。
示例:
scoring = {
'f1_pos': make_scorer(f1_score, pos_label=1),
'balanced_acc': make_scorer(balanced_accuracy_score),
'custom_loss': make_scorer(custom_mse_loss, greater_is_better=False)
}
grid = GridSearchCV(clf, param_grid, scoring=scoring, refit='f1_pos')
关键点:
-
refit必须指定字典里的某个 key(如'f1_pos'),否则报错 - 结果中
cv_results_会为每个 scorer 生成mean_test_{key}列,但best_score_只等于best_scores_['mean_test_f1_pos'] - 别试图在同一个 scorer 里混用
y_pred和y_score—— 一次调用只提供其中一种
needs_proba 没开,或者模型根本没实现 predict_proba 方法。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










