Разница между cross_val_score и cross_val_predict

Я хочу оценить построение регрессионной модели с помощью scikitlearn с использованием перекрестной проверки и путаницы, какую из двух функций cross_val_score и cross_val_predict я должен использовать. Один из вариантов:

cvs = DecisionTreeRegressor(max_depth = depth)
scores = cross_val_score(cvs, predictors, target, cv=cvfolds, scoring='r2')
print("R2-Score: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

Другой, чтобы использовать cv-предсказания со стандартным r2_score:

cvp = DecisionTreeRegressor(max_depth = depth)
predictions = cross_val_predict(cvp, predictors, target, cv=cvfolds)
print ("CV R^2-Score: {}".format(r2_score(df[target], predictions_cv)))

Я бы предположил, что оба метода действительны и дают аналогичные результаты. Но это имеет место только при малых k-краях. В то время как r ^ 2 примерно одинаково для 10-кратного-cv, он становится все ниже для более высоких k-значений в случае первой версии с использованием "cross_vall_score". Вторая версия в основном не подвержена влиянию изменения количества складок.

Ожидается ли такое поведение, и мне не хватает понимания CV в SKLearn?

Ответ 1

cross_val_score возвращает оценку тестовой складки, где cross_val_predict возвращает предсказанные значения y для тестового сгиба.

Для cross_val_score() вы используете среднее значение вывода, на которое будет влиять количество сгибов, потому что тогда у него могут быть некоторые складки, которые могут иметь высокую ошибку (не соответствуют).

В то время как cross_val_predict() возвращает для каждого элемента на входе предсказание, которое было получено для этого элемента, когда оно находилось в тестовом наборе. [Обратите внимание, что могут использоваться только стратегии перекрестной проверки, которые назначают все элементы тестовому набору ровно один раз]. Таким образом, увеличение количества сгибов увеличивает только учебные данные для тестового элемента, и, следовательно, его результат может не сильно повлиять.

Надеюсь, это поможет. Не стесняйтесь задавать любые сомнения.

Изменить: ответ на вопрос в комментарии

Пожалуйста, посмотрите следующий ответ о том, как работает cross_val_predict:

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

Ответ 2

Я думаю, что разницу можно прояснить, проверив их результаты. Рассмотрите этот фрагмент:

# Last column is the label
print(X.shape)  # (7040, 133)

clf = MLPClassifier()

scores = cross_val_score(clf, X[:,:-1], X[:,-1], cv=5)
print(scores.shape)  # (5,)

y_pred = cross_val_predict(clf, X[:,:-1], X[:,-1], cv=5)
print(y_pred.shape)  # (7040,)

Обратите внимание на формы: почему это так? scores.shape имеет длину 5, потому что это оценка, рассчитанная с перекрестной проверкой в 5 раз (см. аргумент cv=5). Следовательно, для каждого сгиба вычисляется одно действительное значение. Это значение является оценкой классификатора:

учитывая истинные метки и предсказанные метки, сколько ответов предсказатель был прав в определенном сгибе?

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

С другой стороны, y_pred.shape имеет длину 7040, которая является формой набора данных. Это длина входного набора данных. Это означает, что каждое значение - это не оценка, рассчитанная для нескольких значений, а одно значение: прогноз классификатора:

исходя из входных данных и их меток, каков прогноз классификатора на конкретном примере, который был в тестовом наборе определенного сгиба?

Обратите внимание, что вы не знаете, какой фолд использовался: каждый выход вычислялся на тестовых данных определенного сгиба, но вы не можете определить, какой (по крайней мере, из этого вывода).

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

Ответ 3

Таким образом, этот вопрос также беспокоил меня, и хотя другие высказали хорошие замечания, они не ответили на все аспекты OP-вопроса.

Правильный ответ: расхождение в оценках для увеличения k связано с выбранной метрикой R2 (коэффициент детерминации). Например, MSE, MSLE или MAE не будет никакой разницы в использовании cross_val_score или cross_val_predict.

См. определение R2:

R ^ 2 = 1 - (MSE (основная правда, прогноз)/MSE (основная правда, среднее (основная правда)))

Жирная часть объясняет, почему оценка начинает различаться при увеличении k: чем больше у нас расколов, тем меньше выборок в тестовом сгибе и чем выше дисперсия среднего значения тестового сгиба. И наоборот, для малых k среднее значение тестового сгиба не будет сильно отличаться от истинного среднего значения, так как размер выборки все еще достаточно велик, чтобы иметь небольшую дисперсию.

Доказательство:

import numpy as np
from sklearn.metrics import mean_absolute_error as mae
from sklearn.metrics import mean_squared_log_error as msle, r2_score

predictions = np.random.rand(1000)*100
groundtruth = np.random.rand(1000)*20

def scores_for_increasing_k(score_func):
    skewed_score = score_func(groundtruth, predictions)
    print(f'skewed score (from cross_val_predict): {skewed_score}')
    for k in (2,4,5,10,20,50,100,200,250):
        fold_preds = np.split(predictions, k)
        fold_gtruth = np.split(groundtruth, k)
        correct_score = np.mean([score_func(g, p) for g,p in zip(fold_gtruth, fold_preds)])

        print(f'correct CV for k={k}: {correct_score}')

for name, score in [('MAE', mae), ('MSLE', msle), ('R2', r2_score)]:
    print(name)
    scores_for_increasing_k(score)
    print()

Вывод будет:

MAE
skewed score (from cross_val_predict): 42.25333901481263
correct CV for k=2: 42.25333901481264
correct CV for k=4: 42.25333901481264
correct CV for k=5: 42.25333901481264
correct CV for k=10: 42.25333901481264
correct CV for k=20: 42.25333901481264
correct CV for k=50: 42.25333901481264
correct CV for k=100: 42.25333901481264
correct CV for k=200: 42.25333901481264
correct CV for k=250: 42.25333901481264

MSLE
skewed score (from cross_val_predict): 3.5252449697327175
correct CV for k=2: 3.525244969732718
correct CV for k=4: 3.525244969732718
correct CV for k=5: 3.525244969732718
correct CV for k=10: 3.525244969732718
correct CV for k=20: 3.525244969732718
correct CV for k=50: 3.5252449697327175
correct CV for k=100: 3.5252449697327175
correct CV for k=200: 3.5252449697327175
correct CV for k=250: 3.5252449697327175

R2
skewed score (from cross_val_predict): -74.5910282783694
correct CV for k=2: -74.63582817089443
correct CV for k=4: -74.73848598638291
correct CV for k=5: -75.06145142821893
correct CV for k=10: -75.38967601572112
correct CV for k=20: -77.20560102267272
correct CV for k=50: -81.28604960074824
correct CV for k=100: -95.1061197684949
correct CV for k=200: -144.90258384605787
correct CV for k=250: -210.13375041871123

Конечно, здесь есть еще один эффект, о котором упоминали другие. С увеличением k появляется больше моделей, обученных на большем количестве образцов и проверенных на меньшем количестве образцов, что повлияет на окончательные оценки, но это не обусловлено выбором между cross_val_score и cross_val_predict.