我正在尝试在sklearn中设置一个自定义评分器(使用make_scorer)以在交叉验证过程中使用。具体来说,我想为多类分类示例计算Top2准确率。
在这里,从技术上讲,我的问题是我需要评估概率(使用needs_proba=True),并且需要类列表来理解概率矩阵。
我已经在下面编写了一个示例。虽然我可以通过在make_scorer调用中提供类来为非cv示例设置自定义评分函数,但我无法为cv情况正确设置它,在这种情况下,类将被动态确定,因此我需要仅在评估期间读取它们。
我知道有许多类似的问题,但我没有看到适合我特定用例的有效解决方案,因此如果有人能帮助我将不胜感激(如果这个问题在某处已解决,请原谅我的无知)。
非常感谢!@
附注:如果我没有记错的话,对于所有涉及概率的make_scorer用例,实际上类标签应该至关重要,因此我认为这是一个通用问题。
from sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import make_scorerfrom sklearn.metrics import accuracy_scorefrom sklearn.model_selection import StratifiedKFoldfrom sklearn.model_selection import cross_validatedata = load_iris()X = data.datay = data.target# 直接使用自定义评分器 ################################################################################### 简单测试训练分割X_train, X_test, y_train, y_test = train_test_split(X, y)# 定义模型并拟合它model = LogisticRegression()model.fit(X = X_train, y = y_train)# 函数返回具有最高可能性的预测或正确的预测,# 如果它在概率的Top n 内def top_n_consolidation(y_label, y_prob, class_names, n=2): top_recs = class_names[[i[0] for i in sorted(enumerate(y_prob), key=lambda x:x[1], reverse=True)][0:n]] if any([i == y_label for i in top_recs]): return y_label else: return top_recs[0]# 基于Top n预测计算准确率# --> 注意:此函数依赖于class_names以利用概率def accuracy_top_n_function(y_labels, y_probs, class_names, n=2): cons_preds = [top_n_consolidation(y_labels[i], y_probs[i,:], class_names, n) for i in range(y_probs.shape[0])] return accuracy_score(y_true=y_labels, y_pred=cons_preds)# 为Top 2分类创建自定义评分器accuracy_2 = make_scorer(accuracy_top_n_function, class_names = model.classes_, n=2, needs_proba = True)# --> 注意:这是有效的,因为model.fit已经执行# 计算Top 2准确率accuracy_2(clf=model, X=X_test, y=y_test)# 为交叉验证使用自定义评分器 ##################################################################### 定义一个新模型以确保我们与上面的情况区分开model_cv = LogisticRegression()# 为cv情况定义自定义评分器accuracy_2_cv = make_scorer(accuracy_top_n_function, class_names = model_cv.classes_, n=2, needs_proba = True)# 注意:这不起作用,因为model_cv.classes_尚未知!# 定义要使用的自定义分数custom_scoring = {'acc' : 'accuracy', 'acc2' : accuracy_2_cv}cross_validate(model_cv, X, y, cv=3, scoring = custom_scoring, return_train_score=True)
回答:
您可以使用用户指南中描述的自定义评分方法,其签名如下:
func(estimator, X, y)
这里estimator
是使用交叉验证分割的训练数据拟合的估计器,因此estimator.classes_
将有效。
def accuracy_2_cv(estimator, X, y_labels): n=2 y_probs = estimator.predict_proba(X) class_names = estimator.classes_ cons_preds = [top_n_consolidation(y_labels[i], y_probs[i,:], class_names, n) for i in range(y_probs.shape[0])] return accuracy_score(y_true=y_labels, y_pred=cons_preds)
现在直接将此传递给custom_scoring
,而不需要用make_scorer
包装:
custom_scoring = {'acc' : 'accuracy', 'acc2' : accuracy_2_cv}