Я сравниваю KFlold и RepeatedKFold, используя sklearn версии 0.22. Согласно документации : RepeatedKFold " Повторяет K-Fold n раз с различной рандомизацией в каждом повторении ." Можно было бы ожидать, что результаты запуска RepeatedKFold только с 1 повтором (n_repeats = 1) будут в значительной степени идентичны KFold.
Я провел простое сравнение:
import numpy as np
from sklearn.linear_model import SGDClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import StratifiedKFold, KFold, RepeatedKFold, RepeatedStratifiedKFold
from sklearn import metrics
X, y = load_digits(return_X_y=True)
classifier = SGDClassifier(loss='hinge', penalty='elasticnet', fit_intercept=True)
scorer = metrics.accuracy_score
results = []
n_splits = 5
kf = KFold(n_splits=n_splits)
for train_index, test_index in kf.split(X, y):
x_train, y_train = X[train_index], y[train_index]
x_test, y_test = X[test_index], y[test_index]
classifier.fit(x_train, y_train)
results.append(scorer(y_test, classifier.predict(x_test)))
print ('KFold')
print('mean = ', np.mean(results))
print('std = ', np.std(results))
print()
results = []
n_repeats = 1
rkf = RepeatedKFold(n_splits=n_splits, n_repeats = n_repeats)
for train_index, test_index in rkf.split(X, y):
x_train, y_train = X[train_index], y[train_index]
x_test, y_test = X[test_index], y[test_index]
classifier.fit(x_train, y_train)
results.append(scorer(y_test, classifier.predict(x_test)))
print ('RepeatedKFold')
print('mean = ', np.mean(results))
print('std = ', np.std(results))
Вывод
KFold
mean = 0.9082079851439182
std = 0.04697225962068869
RepeatedKFold
mean = 0.9493562364593006
std = 0.017732595698953055
Я повторил этот эксперимент достаточно много раз, чтобы увидеть, что разница статистически значима.
Я пытался прочитать и перечитать документацию, чтобы увидеть, что я что-то упустил, но безрезультатно .
Кстати, то же самое верно для StraifiedKFold и RepeatedStratifiedKFold:
StratifiedKFold
mean = 0.9159935004642525
std = 0.026687786392525545
RepeatedStratifiedKFold
mean = 0.9560476632621479
std = 0.014405630805910506
Для этого набора данных StratifiedKFold согласуется с KFold; RepeatedStratifiedKFold согласуется с RepeatedSKFold.
ОБНОВЛЕНИЕ По предложению @Dan и @SergeyBushmanov я включил shuffle и random_state
def run_nfold(X,y, classifier, scorer, cv, n_repeats):
results = []
for n in range(n_repeats):
for train_index, test_index in cv.split(X, y):
x_train, y_train = X[train_index], y[train_index]
x_test, y_test = X[test_index], y[test_index]
classifier.fit(x_train, y_train)
results.append(scorer(y_test, classifier.predict(x_test)))
return results
kf = KFold(n_splits=n_splits)
results_kf = run_nfold(X,y, classifier, scorer, kf, 10)
print('KFold mean = ', np.mean(results_kf))
kf_shuffle = KFold(n_splits=n_splits, shuffle=True, random_state = 11)
results_kf_shuffle = run_nfold(X,y, classifier, scorer, kf_shuffle, 10)
print('KFold Shuffled mean = ', np.mean(results_kf_shuffle))
rkf = RepeatedKFold(n_splits=n_splits, n_repeats = n_repeats, random_state = 111)
results_kf_repeated = run_nfold(X,y, classifier, scorer, rkf, 10)
print('RepeatedKFold mean = ', np.mean(results_kf_repeated)
производит
KFold mean = 0.9119255648406066
KFold Shuffled mean = 0.9505304859176724
RepeatedKFold mean = 0.950754100897555
Более того, использование теста Колмогорова-Смирнова:
print ('Compare KFold with KFold shuffled results')
ks_2samp(results_kf, results_kf_shuffle)
print ('Compare RepeatedKFold with KFold shuffled results')
ks_2samp(results_kf_repeated, results_kf_shuffle)
показывает, что KFold shuffled и RepeatedKFold (который выглядит как тасованный по умолчанию, вы правы @Dan) статистически одинаковы, тогда как по умолчанию -Fuffled KFold дает статистически значимый более низкий результат:
Compare KFold with KFold shuffled results
Ks_2sampResult(statistic=0.66, pvalue=1.3182765881237494e-10)
Compare RepeatedKFold with KFold shuffled results
Ks_2sampResult(statistic=0.14, pvalue=0.7166468440414822)
Теперь обратите внимание, что я использовал Different random_state для KFold и RepeatedKFold. Таким образом, ответ, или, скорее, частичный ответ, заключается в том, что разница в результатах происходит из-за перетасовки против не-перетасовки. Это имеет смысл, поскольку использование различных random_state может изменить точное разделение, и оно не должно изменять статистические свойства, например, среднее значение для нескольких прогонов.
Теперь меня смущает, почему тасование вызывает этот эффект. Я изменил название вопроса, чтобы отразить эту путаницу (надеюсь, он не нарушает никаких правил стекопотока, но я не хочу создавать другой вопрос).
ОБНОВЛЕНИЕ Я согласен с предложением @ SergeyBushmanov. Я отправил это как новый вопрос