Подтвердить что ты не робот

Sklearn - Перекрестная проверка с несколькими баллами

Я хотел бы вычислить отзыв, точность и 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

Он в основном суммирует значения матрицы путаницы, и как только у вас есть ложные положительные, ложные отрицательные и т.д. вы можете легко вычислить отзыв, точность и т.д. Но мне все равно не нравится это решение:)

4b9b3361

Ответ 1

Решение, которое вы представляете, представляет собой точно функциональность cross_val_score, отлично адаптированную к вашей ситуации. Кажется, это правильный путь.

cross_val_score принимает аргумент n_jobs=, делая оценку параллелизуемой. Если это то, что вам нужно, вы должны изучить замену цикла for на параллельный цикл, используя sklearn.externals.joblib.Parallel.

В более общем примечании обсуждается проблема множественных оценок в трекер-проблеме изучения scikit. Репрезентативный поток можно найти здесь. Так что, похоже, что будущие версии scikit-learn позволят делать несколько выходов scorers, на данный момент это невозможно.

A hacky (отказ от ответственности!), чтобы обойти это, это немного изменить код в cross_validation.py, удалив проверку состояния, является ли ваш счет числом. Однако это предложение очень зависит от версии, поэтому я представлю его для версии 0.14.

1) В IPython введите from sklearn import cross_validation, а затем cross_validation??. Обратите внимание на отображаемое имя файла и откройте его в редакторе (возможно, вам потребуются root priviliges).

2) Вы найдете этот код, где я уже пометил соответствующую строку (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

Теперь в scikit-learn: cross_validate - это новая функция, которая может оценивать модель по нескольким метрикам. Эта функция также доступна в GridSearchCV и RandomizedSearchCV (doc). Это было недавно объединено в master и будет доступно в v0.19.

Из scikit-learn doc:

Функция 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)

См. также этот пример.

Ответ 3

Вы можете использовать следующий код для вычисления точности, точности, повторного вызова и любых других показателей путем подбора вашей оценки только один раз за шаг перекрестной проверки.

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, чтобы вычислить множественную статистику вообще. Вы можете изменить показатели качества по желаемому.

Ответ 4

Вы можете использовать это:

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]) )

Источник мультиискателя находится на Github