scikit-learn中GridSearchCV结合LeaveOneOut时如何用全局F1评估KNN参数?
问题描述
我想用GridSearchCV寻找KNeighborsClassifier的最优n_neighbors参数,指定采用f1_score指标与LeaveOneOut验证策略,但运行以下代码时出现错误:
clf = GridSearchCV(KNeighborsClassifier(), {'n_neighbors': [1, 2, 3]}, cv=LeaveOneOut(), scoring='f1') clf.fit(x_train, y_train)
错误提示:
UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 due to no true nor predicted samples. Use `zero_division` parameter to control this behavior.
由于LeaveOneOut的每个交叉验证测试折仅包含单个样本,无法计算F1分数,因此我希望基于整个迭代集计算对应n_neighbors参数的F1分数,而非每个折的F1。请问是否可以通过GridSearchCV实现?
解决方法
可以实现,核心是自定义一个评分器,让GridSearchCV在完成所有LeaveOneOut折的预测后,用整个验证集的真实标签和预测标签计算F1分数,而非逐个折计算。
具体步骤与代码示例:
- 导入所需模块
- 定义全局F1评分函数:遍历
LeaveOneOut的所有折,得到每个样本的预测值,再用全局真实标签和预测值计算F1 - 用
make_scorer将自定义函数包装为GridSearchCV可识别的评分器 - 在
GridSearchCV中使用该自定义评分器
from sklearn.model_selection import GridSearchCV, LeaveOneOut from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import make_scorer, f1_score import numpy as np def global_f1_scorer(model, X, y): # 通过LeaveOneOut生成所有样本的预测结果 y_pred = [] loo = LeaveOneOut() for train_idx, test_idx in loo.split(X): X_train_fold, X_test_fold = X[train_idx], X[test_idx] y_train_fold = y[train_idx] model.fit(X_train_fold, y_train_fold) y_pred.append(model.predict(X_test_fold)[0]) y_pred = np.array(y_pred) # 计算全局F1分数 return f1_score(y, y_pred) # 创建自定义评分器 custom_scorer = make_scorer(global_f1_scorer) # 初始化GridSearchCV并训练 clf = GridSearchCV(KNeighborsClassifier(), {'n_neighbors': [1, 2, 3]}, cv=LeaveOneOut(), scoring=custom_scorer) clf.fit(x_train, y_train) # 查看结果 print("最优参数:", clf.best_params_) print("最优全局F1分数:", clf.best_score_)
注意事项:
- 这种方式会增加计算量,因为每个参数组合都要重新执行一遍
LeaveOneOut的完整预测流程 - 若数据集规模较大,
LeaveOneOut本身计算耗时就长,该方法会进一步延长运行时间;如果非必要,可考虑改用KFold等其他交叉验证策略
内容的提问来源于stack exchange,提问作者Arseniy Maryin
相关产品推荐
相关产品推荐

