我想为不同的分类器计算交叉验证测试的召回,精确度和 f-measure 。 scikit-learn 附带cross_val_score但很遗憾,此类方法不会返回多个值。
我可以通过调用三次 cross_val_score 来计算此类度量,但效率不高。有没有更好的解决方案?
到现在为止我写了这个函数:
from sklearn import metrics
def mean_scores(X, y, clf, skf):
cm = np.zeros(len(np.unique(y)) ** 2)
for i, (train, test) in enumerate(skf):
clf.fit(X[train], y[train])
y_pred = clf.predict(X[test])
cm += metrics.confusion_matrix(y[test], y_pred).flatten()
return compute_measures(*cm / skf.n_folds)
def compute_measures(tp, fp, fn, tn):
"""Computes effectiveness measures given a confusion matrix."""
specificity = tn / (tn + fp)
sensitivity = tp / (tp + fn)
fmeasure = 2 * (specificity * sensitivity) / (specificity + sensitivity)
return sensitivity, specificity, fmeasure
它基本上总结了混淆矩阵值,一旦你有误判,假阴性等,你就可以轻松计算召回率,精度等等......但我仍然是不喜欢这个解决方案:)
答案 0 :(得分:9)
现在在scikit-learn中:cross_validate
是一个新功能,可以评估多个指标的模型。
此功能也可在GridSearchCV
和RandomizedSearchCV
(doc)中使用。
它已经merged recently in master,将在v0.19中提供。
cross_validate
功能在两个方面与cross_val_score
不同:1。它允许指定多个评估指标。 2。 除了测试分数之外,它还会返回包含训练分数,适合次数和分数时间的字典。
典型的用例是:
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_validate
iris = load_iris()
scoring = ['precision', 'recall', 'f1']
clf = SVC(kernel='linear', C=1, random_state=0)
scores = cross_validate(clf, iris.data, iris.target == 1, cv=5,
scoring=scoring, return_train_score=False)
另见this example。
答案 1 :(得分:6)
您提供的解决方案恰好代表cross_val_score
的功能,完全适合您的情况。这似乎是正确的方法。
cross_val_score
接受参数n_jobs=
,使评估可并行化。如果这是您需要的,您应该使用sklearn.externals.joblib.Parallel
来考虑使用并行循环替换for循环。
更一般地说,正在讨论关于scikit learn的问题跟踪器中的多个分数的问题。可以找到代表性线程here。因此,虽然看起来scikit-learn的未来版本将允许得分者的多个输出,但截至目前,这是不可能的。
hacky (免责声明!)解决这个问题的方法是,通过删除条件检查您的分数是否为数字来更改cross_validation.py
中的代码。但是,此建议非常依赖于版本,因此我将其用于版本0.14
。
1)在IPython中,输入from sklearn import cross_validation
,然后输入cross_validation??
。记下显示的文件名并在编辑器中打开它(您可能需要root权限)。
2)你会找到this code,我已经在那里标记了相关的行(1066)。它说
if not isinstance(score, numbers.Number):
raise ValueError("scoring must return a number, got %s (%s)"
" instead." % (str(score), type(score)))
需要删除这些行。为了跟踪曾经有过的东西(如果你想要改回),请用下面的
替换它 if not isinstance(score, numbers.Number):
pass
# raise ValueError("scoring must return a number, got %s (%s)"
# " instead." % (str(score), type(score)))
如果得分者返回的内容并未使cross_val_score
在其他地方窒息,则应解决您的问题。如果是这种情况,请告诉我。
答案 2 :(得分:2)
您可以使用以下代码,通过每个交叉验证步骤仅为估算器拟合一次来计算准确度,精度,召回和任何其他指标。
def get_true_and_pred_CV(estimator, X, y, n_folds, cv, params):
ys = []
for train_idx, valid_idx in cv:
clf = estimator(**params)
if isinstance(X, np.ndarray):
clf.fit(X[train_idx], y[train_idx])
cur_pred = clf.predict(X[valid_idx])
elif isinstance(X, pd.DataFrame):
clf.fit(X.iloc[train_idx, :], y[train_idx])
cur_pred = clf.predict(X.iloc[valid_idx, :])
else:
raise Exception('Only numpy array and pandas DataFrame ' \
'as types of X are supported')
ys.append((y[valid_idx], cur_pred))
return ys
def fit_and_score_CV(estimator, X, y, n_folds=10, stratify=True, **params):
if not stratify:
cv_arg = sklearn.cross_validation.KFold(y.size, n_folds)
else:
cv_arg = sklearn.cross_validation.StratifiedKFold(y, n_folds)
ys = get_true_and_pred_CV(estimator, X, y, n_folds, cv_arg, params)
cv_acc = map(lambda tp: sklearn.metrics.accuracy_score(tp[0], tp[1]), ys)
cv_pr_weighted = map(lambda tp: sklearn.metrics.precision_score(tp[0], tp[1], average='weighted'), ys)
cv_rec_weighted = map(lambda tp: sklearn.metrics.recall_score(tp[0], tp[1], average='weighted'), ys)
cv_f1_weighted = map(lambda tp: sklearn.metrics.f1_score(tp[0], tp[1], average='weighted'), ys)
# the approach below makes estimator fit multiple times
#cv_acc = sklearn.cross_validation.cross_val_score(algo, X, y, cv=cv_arg, scoring='accuracy')
#cv_pr_weighted = sklearn.cross_validation.cross_val_score(algo, X, y, cv=cv_arg, scoring='precision_weighted')
#cv_rec_weighted = sklearn.cross_validation.cross_val_score(algo, X, y, cv=cv_arg, scoring='recall_weighted')
#cv_f1_weighted = sklearn.cross_validation.cross_val_score(algo, X, y, cv=cv_arg, scoring='f1_weighted')
return {'CV accuracy': np.mean(cv_acc), 'CV precision_weighted': np.mean(cv_pr_weighted),
'CV recall_weighted': np.mean(cv_rec_weighted), 'CV F1_weighted': np.mean(cv_f1_weighted)}
我经常使用这些函数而不是cross_val_score来计算多个统计信息。您可以根据需要更改质量指标。
答案 3 :(得分:2)
你可以用这个:
from sklearn import metrics
from multiscorer import MultiScorer
import numpy as np
scorer = MultiScorer({
'F-measure' : (f1_score, {...}),
'Precision' : (precision_score, {...}),
'Recall' : (recall_score, {...})
})
...
cross_val_score(clf, X, target, scoring=scorer)
results = scorer.get_results()
for name in results.keys():
print '%s: %.4f' % (name, np.average(results[name]) )
multiscorer 的来源位于http://verilog.renerta.com/source/vrg00016.htm
答案 4 :(得分:0)
如果您通过多个类别查找多个指标,这可能会有所帮助。在scikit中使用最新的doc,可学习0.19及更高版本;您可以将自己的字典与度量函数一起传递;
<commandlineArgs>${example-idl} ${basic-types-idl}</commandlineArgs>