SKLearn与ElasticNet:使用Accuracy作为指标时交叉验证失败
问题:ElasticNet交叉验证用accuracy评分报错的原因及解决
我在二分类任务中用交叉验证优化ElasticNet参数时,遇到了奇怪的问题:只有将roc_auc作为评分方法时模型能正常运行,换成accuracy就抛出错误:
ValueError: Classification metrics can't handle a mix of binary and continuous targets
但我的y标签确实是二值化后的0/1,用威斯康星乳腺癌数据集复现问题的代码如下:
import numpy as np import pandas as pd from sklearn.preprocessing import LabelBinarizer from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split, GridSearchCV, StratifiedKFold from sklearn.metrics import make_scorer, recall_score, accuracy_score, precision_score, confusion_matrix from sklearn.linear_model import LogisticRegression from sklearn.linear_model import ElasticNet data = pd.read_csv('data 2.csv') # 默认将多数类(良性)设为负类 lb = LabelBinarizer() data['diagnosis'] = lb.fit_transform(data['diagnosis'].values) targets = data['diagnosis'] data.drop(['id', 'diagnosis', 'Unnamed: 32'], axis=1, inplace=True) X_train, X_test, y_train, y_test = train_test_split(data, targets, stratify=targets) # ElasticNet 尝试 lr = ElasticNet(max_iter=2000) scorer = 'accuracy' param_grid = { 'alpha': [1e-4, 1e-3, 1e-2, 0.01, 0.1, 1, 5, 10], 'l1_ratio': np.arange(0.2, 0.9, 0.1) } skf = StratifiedKFold(n_splits=10) clf = GridSearchCV(lr, param_grid, scoring=scorer, cv=skf, return_train_score=True, n_jobs=-1) clf.fit(X_train.values, y_train.values)
我尝试过以下操作:
- 以为ElasticNet是回归模型,换成带ElasticNet惩罚的LogisticRegression:
lr = LogisticRegression(penalty='elasticnet', l1_ratios=[0.1, 0.5, 0.9], solver='saga'),但问题依旧 - 换成RandomForestClassifier用accuracy评分,完全正常
- 只要把评分指标换回
roc_auc,ElasticNet和LogisticRegression都能正常运行
原因分析
- ElasticNet本质是回归模型:它的
predict方法输出的是连续数值(不是二分类标签或概率)。roc_auc指标可以直接处理连续的预测得分(只关注样本排序),但accuracy需要离散的0/1标签,连续预测值和二值标签类型不匹配,就会触发报错。 - LogisticRegression参数错误:你写的
l1_ratios是错误的参数名,正确的是l1_ratio(单数),这个错误导致ElasticNet惩罚没有生效,进而影响了后续的评分计算。
解决办法
1. 给ElasticNet自定义accuracy评分器
如果一定要用ElasticNet做二分类,需要先把它的连续预测值转换成二值标签,再计算accuracy:
from sklearn.metrics import make_scorer, accuracy_score def custom_accuracy(y_true, y_pred): # 用0.5作为阈值,将连续预测值转成二值标签 y_pred_bin = (y_pred >= 0.5).astype(int) return accuracy_score(y_true, y_pred_bin) # 使用自定义评分器 scorer = make_scorer(custom_accuracy)
把原代码中的scorer = 'accuracy'替换成上面的自定义scorer即可。
2. 正确使用带ElasticNet惩罚的LogisticRegression
修正参数名错误,确保模型是正确的二分类器:
# 正确初始化LogisticRegression(注意l1_ratio是单数) lr = LogisticRegression(penalty='elasticnet', solver='saga', max_iter=2000) param_grid = { 'C': [1e-4, 1e-3, 1e-2, 0.1, 1, 5, 10], # LogisticRegression用C控制正则化强度,和ElasticNet的alpha作用相反 'l1_ratio': np.arange(0.2, 0.9, 0.1) } # 后续GridSearchCV代码不变,直接用scorer='accuracy'即可
LogisticRegression是原生分类器,predict方法直接输出0/1标签,和y标签类型匹配,用accuracy评分不会报错。
内容的提问来源于stack exchange,提问作者pd441
相关产品推荐
相关产品推荐

