В чем разница между cross_val_score и scoring = 'roc_auc' и roc_auc_score?

Меня смущает разница между метрикой оценки cross_val_score 'roc_auc' и roc_auc_score, которую я могу просто импортировать и вызывать напрямую.

Документация (http://scikit-learn.org/stable/modules/model_evaluation.html#scoring-parameter) указывает, что при указании scoring = 'roc_auc' будет использоваться sklearn.metrics.roc_auc_score. Однако, когда я реализую GridSearchCV или cross_val_score с scoring = 'roc_auc', я получаю совсем другие числа, чем когда я вызываю roc_auc_score напрямую.

Вот мой код, чтобы продемонстрировать то, что я вижу:

# score the model using cross_val_score

rf = RandomForestClassifier(n_estimators=150,
                            min_samples_leaf=4,
                            min_samples_split=3,
                            n_jobs=-1)

scores = cross_val_score(rf, X, y, cv=3, scoring='roc_auc')

print scores
array([ 0.9649023 ,  0.96242235,  0.9503313 ])

# do a train_test_split, fit the model, and score with roc_auc_score

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33)
rf.fit(X_train, y_train)

print roc_auc_score(y_test, rf.predict(X_test))
0.84634039111363313 # quite a bit different than the scores above!

Я чувствую, что здесь не хватает чего-то очень простого - скорее всего, это ошибка в том, как я реализую / интерпретирую один из показателей оценки.

Может ли кто-нибудь пролить свет на причину расхождения между двумя оценочными показателями?


person MichaelHood    schedule 11.11.2015    source источник
comment
Меня также совершенно смущает эта разница. Я также пробовал использовать стандартную функцию make_scorer (), которая превращает функцию оценки в правильный объект Scorer для cross_val_score, но результаты те же. make_scorer () дает тот же результат, что и моя ручная реализация, в то время как roc_auc дает более высокие оценки. К счастью, в моем примере разница составила несколько%, в отличие от вашего, но все же: какой функции мне следует доверять?   -  person Anton Fetisov    schedule 15.03.2016


Ответы (3)


Это потому, что вы предоставили прогнозируемые y вместо вероятности в roc_auc_score. Эта функция принимает балл, а не классифицированную метку. Вместо этого попробуйте сделать это:

print roc_auc_score(y_test, rf.predict_proba(X_test)[:,1])

Он должен дать результат, аналогичный предыдущему результату cross_val_score. Дополнительные сведения см. в этом сообщении.

person George Liu    schedule 29.04.2016
comment
Вы совершенно правы! Я бы рассмеялся, если бы мог перестать плакать. Спасибо! - person MichaelHood; 05.05.2016

Я столкнулся с аналогичной проблемой здесь. Главный вывод заключался в том, что cross_val_score использует KFold стратегия с параметрами по умолчанию для разбиения поезда-теста, что означает разбиение на последовательные фрагменты, а не перемешивание. train_test_split, с другой стороны, выполняет перетасовку.

Решение состоит в том, чтобы сделать стратегию разделения явной и указать перемешивание, например:

shuffle = cross_validation.KFold(len(X), n_folds=3, shuffle=True)
scores = cross_val_score(rf, X, y, cv=shuffle, scoring='roc_auc')
person Aniket Schneider    schedule 11.11.2015
comment
Аникет, спасибо за ответ. Но указание складок и передача их в cross_val_score не устранили расхождения между показателями оценки. - person MichaelHood; 13.11.2015
comment
Я знаю, что очень опаздываю, но когда вы используете метод cross_val_score с roc_auc оценкой, почему вы передаете ему предсказанные метки класса вместо предсказанных вероятностей? Поскольку это AUC, разве ему не нужны вероятности, чтобы он мог тестировать разные пороговые значения? - person NeonBlueHair; 18.05.2017

Сам наткнулся на эту проблему и, немного покопавшись, нашел ответ. Делимся ради любви.

На самом деле есть две с половиной проблемы.

  1. вам нужно использовать один и тот же Kfold для сравнения результатов (то же разделение на тренировку / тест);
  2. вам нужно скормить вероятности в roc_auc_score (используя метод predict_proba()). НО, некоторые оценщики (например, SVC) не имеют метода predict_proba(), тогда вы используете метод decision_function().

Вот полный пример:

# Let's use the Digit dataset
digits = load_digits(n_class=4)
X,y = digits.data, digits.target
y[y==2] = 0 # Increase problem dificulty
y[y==3] = 1 # even more

Использование двух оценщиков

LR = LogisticRegression()
SVM = LinearSVC()

Разделите поезд / тестовый набор. Но оставьте его в переменной, которую мы можем использовать повторно.

fourfold = StratifiedKFold(n_splits=4, random_state=4)

Накормите GridSearchCV и сохраните результаты. Обратите внимание, что мы передаем fourfold.

gs = GridSearchCV(LR, param_grid={}, cv=fourfold, scoring='roc_auc', return_train_score=True)
gs.fit(X,y)
gs_scores = np.array([gs.cv_results_[k][0] for k in gskeys])

Подайте его на cross_val_score и сохраните результаты.

 cv_scores = cross_val_score(LR, X, y, cv=fourfold, scoring='roc_auc')

Иногда вам нужно выполнить цикл и вычислить несколько разных оценок, поэтому вы и используете это.

loop_scores = list()
for idx_train, idx_test in fourfold.split(X, y):
  X_train, y_train, X_test, y_test = X[idx_train], y[idx_train], X[idx_test], y[idx_test]
  LR.fit(X_train, y_train)
  y_prob = LR.predict_proba(X_test)
  auc = roc_auc_score(y_test, y_prob[:,1])
  loop_scores.append(auc)

У нас одинаковые оценки по всем направлениям?

print [((a==b) and (b==c)) for a,b,c in zip(gs_scores,cv_scores,loop_scores)]
>>> [True, True, True, True]


НО, иногда у нашего оценщика нет predict_proba() метода. Итак, согласно этому example, мы делаем следующее:

for idx_train, idx_test in fourfold.split(X, y):
  X_train, y_train, X_test, y_test = X[idx_train], y[idx_train], X[idx_test], y[idx_test]
  SVM.fit(X_train, y_train)
  y_prob = SVM.decision_function(X_test)
  prob_pos = (y_prob - y_prob.min()) / (y_prob.max() - y_prob.min())
  auc = roc_auc_score(y_test, prob_pos)
person rionbr    schedule 25.10.2016