在 sklearn cross_val_score 上评估多个分数

Posted

技术标签:

【中文标题】在 sklearn cross_val_score 上评估多个分数【英文标题】:Evaluate multiple scores on sklearn cross_val_score 【发布时间】:2016-06-22 22:29:59 【问题描述】:

我正在尝试使用 sklearn 评估多个机器学习算法的几个指标(准确度、召回率、精度等)。

根据我从文档here 和源代码(我使用的是 sklearn 0.17)中了解到的内容,cross_val_score 函数每次执行只接收一个记分器。所以为了计算多个分数,我必须:

    多次执行

    实现我的(耗时且容易出错的)记分器

    我已经用这段代码执行了多次:

    from sklearn.svm import SVC
    from sklearn.naive_bayes import GaussianNB
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.cross_validation import  cross_val_score
    import time
    from sklearn.datasets import  load_iris
    
    iris = load_iris()
    
    models = [GaussianNB(), DecisionTreeClassifier(), SVC()]
    names = ["Naive Bayes", "Decision Tree", "SVM"]
    for model, name in zip(models, names):
        print name
        start = time.time()
        for score in ["accuracy", "precision", "recall"]:
            print score,
            print " : ",
            print cross_val_score(model, iris.data, iris.target,scoring=score, cv=10).mean()
        print time.time() - start
    

我得到这个输出:

Naive Bayes
accuracy  :  0.953333333333
precision  :  0.962698412698
recall  :  0.953333333333
0.0383198261261
Decision Tree
accuracy  :  0.953333333333
precision  :  0.958888888889
recall  :  0.953333333333
0.0494720935822
SVM
accuracy  :  0.98
precision  :  0.983333333333
recall  :  0.98
0.063080072403

这没关系,但我自己的数据很慢。如何衡量所有分数?

【问题讨论】:

我会尝试手动实现 cross_val_score 正在做的事情 使用 Python 3.6 此示例不起作用,因为目标数据是多类的,但 cross_val_score 的平均值设置为“二进制”。您收到以下错误:“ValueError: Target is multiclass but average='binary'。请选择另一个平均设置。”我将如何解决这个问题?真的不能二值化,可以吗? 我使用的是 Python 2.7。和 sklearn 0.17。我认为这个错误发生在 0.18 中。你用的是什么 sklearn 版本? 这个问题似乎与那个问题重复:***.com/questions/23339523/… 从 scikit-learn 0.19.0 开始,cross_validate 函数中允许使用多个指标。我在下面更新了我接受的答案以反映这一点。 【参考方案1】:
from sklearn import model_selection

def error_metrics(model, train_data, train_targ, kfold):
    scoring = ["accuracy","roc_auc","neg_log_loss","r2",
             "neg_mean_squared_error","neg_mean_absolute_error"] 

    error_metrics = pd.DataFrame()
    error_metrics["model"] = model
    for scor in scoring:
        score = []
        for mod in model:
           
            result = model_selection.cross_val_score(estimator= mod, X=train_data, y=train_targ,cv=kfold,scoring=scor )
            score.append(result.mean())
            
        error_metrics[scor] =pd.Series(score)
        
    return error_metrics

【讨论】:

虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。【参考方案2】:

我遇到了同样的问题,我在cross_val_score 中创建了一个可以支持多个指标的模块。 为了用这个模块完成你想要的,你可以写:

from multiscorer import MultiScorer
import numpy as np
from sklearn.metrics import accuracy_score, precision_score, recall_score          
from sklearn.model_selection import cross_val_score
from numpy import average

scorer = MultiScorer(
    'Accuracy'  : (accuracy_score , ),
    'Precision' : (precision_score, 'pos_label': 3, 'average':'macro'),
    'Recall'    : (recall_score   , 'pos_label': 3, 'average':'macro')
)

for model, name in zip(models, names):
    print name
    start = time.time()

    _ = cross_val_score(model, iris.data, iris.target,scoring=scorer, cv=10) # Added assignment of the result to `_` in order to illustrate that the return value will not be used
    results = scorer.get_results()

    for metric_name in results.keys():
        average_score = np.average(results[metric_name])
        print('%s : %f' % (metric_name, average_score))

    print 'time', time.time() - start, '\n\n'

您可以从GitHub查看和下载此模块。 希望对您有所帮助。

【讨论】:

【参考方案3】:

自从写这篇文章 scikit-learn 已经更新并且我的答案已经过时了,请看下面更简洁的解决方案


您可以编写自己的评分函数来捕获所有三个信息,但是用于交叉验证的评分函数只能返回 scikit-learn 中的单个数字(这可能是出于兼容性原因)。下面是一个示例,其中每个交叉验证切片的每个分数都打印到控制台,返回值只是三个指标的总和。如果要返回所有这些值,则必须对 cross_val_score(cross_validation.py 的第 1351 行)和 _score(第 1601 行或同一文件)进行一些更改。

from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.cross_validation import  cross_val_score
import time
from sklearn.datasets import  load_iris
from sklearn.metrics import accuracy_score, precision_score, recall_score

iris = load_iris()

models = [GaussianNB(), DecisionTreeClassifier(), SVC()]
names = ["Naive Bayes", "Decision Tree", "SVM"]

def getScores(estimator, x, y):
    yPred = estimator.predict(x)
    return (accuracy_score(y, yPred), 
            precision_score(y, yPred, pos_label=3, average='macro'), 
            recall_score(y, yPred, pos_label=3, average='macro'))

def my_scorer(estimator, x, y):
    a, p, r = getScores(estimator, x, y)
    print a, p, r
    return a+p+r

for model, name in zip(models, names):
    print name
    start = time.time()
    m = cross_val_score(model, iris.data, iris.target,scoring=my_scorer, cv=10).mean()
    print '\nSum:',m, '\n\n'
    print 'time', time.time() - start, '\n\n'

给出:

Naive Bayes
0.933333333333 0.944444444444 0.933333333333
0.933333333333 0.944444444444 0.933333333333
1.0 1.0 1.0
0.933333333333 0.944444444444 0.933333333333
0.933333333333 0.944444444444 0.933333333333
0.933333333333 0.944444444444 0.933333333333
0.866666666667 0.904761904762 0.866666666667
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0

Sum: 2.86936507937 


time 0.0249638557434 


Decision Tree
1.0 1.0 1.0
0.933333333333 0.944444444444 0.933333333333
1.0 1.0 1.0
0.933333333333 0.944444444444 0.933333333333
0.933333333333 0.944444444444 0.933333333333
0.866666666667 0.866666666667 0.866666666667
0.933333333333 0.944444444444 0.933333333333
0.933333333333 0.944444444444 0.933333333333
1.0 1.0 1.0
1.0 1.0 1.0

Sum: 2.86555555556 


time 0.0237860679626 


SVM
1.0 1.0 1.0
0.933333333333 0.944444444444 0.933333333333
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
0.933333333333 0.944444444444 0.933333333333
0.933333333333 0.944444444444 0.933333333333
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0

Sum: 2.94333333333 


time 0.043044090271 

从 scikit-learn 0.19.0 开始,解决方案变得更加更容易

from sklearn.model_selection import cross_validate
from sklearn.datasets import  load_iris
from sklearn.svm import SVC

iris = load_iris()
clf = SVC()
scoring = 'acc': 'accuracy',
           'prec_macro': 'precision_macro',
           'rec_micro': 'recall_macro'
scores = cross_validate(clf, iris.data, iris.target, scoring=scoring,
                         cv=5, return_train_score=True)
print(scores.keys())
print(scores['test_acc'])  

这给出了:

['test_acc', 'score_time', 'train_acc', 'fit_time', 'test_rec_micro', 'train_rec_micro', 'train_prec_macro', 'test_prec_macro']
[ 0.96666667  1.          0.96666667  0.96666667  1.        ]

【讨论】:

需要注意的是,scikit-learn 0.19.0 的改进在于 cross_validate 方法,而不是 cross_val_score。这让我很困惑,我浪费了一些时间,直到我意识到这一点。因此,对于多重评分,请使用 cross_validate 而不是 cross_val_score。 它似乎还在重新训练它,并没有变得更快。 如何结合使用它,例如GridsearchCV? @Ben 看看 sklearn 文档中的这个例子:scikit-learn.org/stable/auto_examples/model_selection/… @huggie 我可以确认它更快(4 个指标快 4 倍),在 scikit-learn 0.24.2 上进行了测试。

以上是关于在 sklearn cross_val_score 上评估多个分数的主要内容,如果未能解决你的问题,请参考以下文章

使用joblib在sklearn中重用由cross_val_score拟合的模型

cross_val_score 与 sklearn 中的不同分类器的行为不同

为啥 xgboost.cv 和 sklearn.cross_val_score 给出不同的结果?

scikit-learn中的cross_val_score函数scoring参数设置

我从 GridSearchCV 获得的 R^2 分数与我从 cross_val_score 获得的分数非常不同,为啥? (sklearn,python)

sklearn中的cross_val_score交叉验证