为什么我的交叉验证始终比训练测试拆分表现更好?
Why does my cross-validation consistently perform better than train-test split?
我有下面的代码(使用 sklearn),它首先使用训练集进行交叉验证,最后使用测试集进行检查。然而,交叉验证始终表现得更好,如下所示。我是否过度拟合训练数据?如果是这样,最好调整哪个超参数来避免这种情况?
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
#Cross validation
rfc = RandomForestClassifier()
cv = RepeatedKFold(n_splits=10, n_repeats=5)
scoring = {'accuracy', 'precision', 'recall', 'f1', 'roc_auc' }
scores = cross_validate(rfc, X_train, y_train, scoring=scoring, cv=cv)
print(mean(scores['test_accuracy']),
mean(scores['test_precision']),
mean(scores['test_recall']),
mean(scores['test_f1']),
mean(scores['test_roc_auc'])
)
这给了我:
0.8536558341101569 0.8641939667622551 0.8392201023654705 0.8514895113569482 0.9264002192260914
现在使用整个训练+验证集重新训练模型,并使用前所未见的测试集
对其进行测试
RFC = 随机森林分类器()
RFC.fit(X_train, y_train)
y_pred = RFC.predict(X_test)
精度 = accuracy_score(y_test, y_pred)
精度 = precision_score(y_test, y_pred)
召回 = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
y_pred_proba = RFC.predict_proba(X_test)[::,1]
auc = roc_auc_score(y_test, y_pred_proba)
打印(准确性,
精确,
记起,
f1,
拍卖会
)
现在它给了我下面的数字,这些数字显然更糟:
0.7809788654060067 0.5113236034222446 0.5044687189672294 0.5078730317420644 0.7589037004728368
我可以用 Pima Indians Diabetes Dataset 重现您的场景。
您在预测指标中看到的差异不是一致性,在某些 运行 中您甚至可能注意到相反的情况,因为它取决于拆分期间 X_test 的选择 - 有些的案例将更容易预测,并将提供更好的指标,反之亦然。虽然交叉验证 运行 对你轮换的整个集合的预测并聚合了这种影响,但单个 X_test 集合将受到随机拆分的影响。
为了更好地了解这里发生的事情,我修改了您的实验并分为两个步骤:
1。交叉验证步骤:
我使用整个 X 和 y 集和 运行 其余代码
rfc = RandomForestClassifier()
cv = RepeatedKFold(n_splits=10, n_repeats=5)
# cv = KFold(n_splits=10)
scoring = {'accuracy', 'precision', 'recall', 'f1', 'roc_auc'}
scores = cross_validate(rfc, X, y, scoring=scoring, cv=cv)
print(mean(scores['test_accuracy']),
mean(scores['test_precision']),
mean(scores['test_recall']),
mean(scores['test_f1']),
mean(scores['test_roc_auc'])
)
输出:
0.768257006151743 0.6943032069967433 0.593436328663432 0.6357667086829574 0.8221242747913622
2。经典训练测试步骤:
接下来我 运行 普通的训练测试步骤,但我用不同的 train_test 分割做了 50 次,并对指标进行平均(类似于交叉验证步骤)。
accuracies = []
precisions = []
recalls = []
f1s = []
aucs = []
for i in range(50):
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
RFC = RandomForestClassifier()
RFC.fit(X_train, y_train)
y_pred = RFC.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
y_pred_proba = RFC.predict_proba(X_test)[::, 1]
auc = roc_auc_score(y_test, y_pred_proba)
accuracies.append(accuracy)
precisions.append(precision)
recalls.append(recall)
f1s.append(f1)
aucs.append(auc)
print(mean(accuracies),
mean(precisions),
mean(recalls),
mean(f1s),
mean(aucs)
)
输出:
0.7606926406926405 0.7001931059992001 0.5778712922956755 0.6306501622080503 0.8207846633339568
正如预期的那样,预测指标相似。但是,交叉验证 运行 的速度要快得多,并且使用整个数据集的每个数据点进行给定次数的测试(轮流)。
我有下面的代码(使用 sklearn),它首先使用训练集进行交叉验证,最后使用测试集进行检查。然而,交叉验证始终表现得更好,如下所示。我是否过度拟合训练数据?如果是这样,最好调整哪个超参数来避免这种情况?
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
#Cross validation
rfc = RandomForestClassifier()
cv = RepeatedKFold(n_splits=10, n_repeats=5)
scoring = {'accuracy', 'precision', 'recall', 'f1', 'roc_auc' }
scores = cross_validate(rfc, X_train, y_train, scoring=scoring, cv=cv)
print(mean(scores['test_accuracy']),
mean(scores['test_precision']),
mean(scores['test_recall']),
mean(scores['test_f1']),
mean(scores['test_roc_auc'])
)
这给了我:
0.8536558341101569 0.8641939667622551 0.8392201023654705 0.8514895113569482 0.9264002192260914
现在使用整个训练+验证集重新训练模型,并使用前所未见的测试集
对其进行测试 RFC = 随机森林分类器() RFC.fit(X_train, y_train) y_pred = RFC.predict(X_test) 精度 = accuracy_score(y_test, y_pred) 精度 = precision_score(y_test, y_pred) 召回 = recall_score(y_test, y_pred) f1 = f1_score(y_test, y_pred) y_pred_proba = RFC.predict_proba(X_test)[::,1] auc = roc_auc_score(y_test, y_pred_proba) 打印(准确性, 精确, 记起, f1, 拍卖会 )
现在它给了我下面的数字,这些数字显然更糟:
0.7809788654060067 0.5113236034222446 0.5044687189672294 0.5078730317420644 0.7589037004728368
我可以用 Pima Indians Diabetes Dataset 重现您的场景。
您在预测指标中看到的差异不是一致性,在某些 运行 中您甚至可能注意到相反的情况,因为它取决于拆分期间 X_test 的选择 - 有些的案例将更容易预测,并将提供更好的指标,反之亦然。虽然交叉验证 运行 对你轮换的整个集合的预测并聚合了这种影响,但单个 X_test 集合将受到随机拆分的影响。
为了更好地了解这里发生的事情,我修改了您的实验并分为两个步骤:
1。交叉验证步骤:
我使用整个 X 和 y 集和 运行 其余代码
rfc = RandomForestClassifier()
cv = RepeatedKFold(n_splits=10, n_repeats=5)
# cv = KFold(n_splits=10)
scoring = {'accuracy', 'precision', 'recall', 'f1', 'roc_auc'}
scores = cross_validate(rfc, X, y, scoring=scoring, cv=cv)
print(mean(scores['test_accuracy']),
mean(scores['test_precision']),
mean(scores['test_recall']),
mean(scores['test_f1']),
mean(scores['test_roc_auc'])
)
输出:
0.768257006151743 0.6943032069967433 0.593436328663432 0.6357667086829574 0.8221242747913622
2。经典训练测试步骤:
接下来我 运行 普通的训练测试步骤,但我用不同的 train_test 分割做了 50 次,并对指标进行平均(类似于交叉验证步骤)。
accuracies = []
precisions = []
recalls = []
f1s = []
aucs = []
for i in range(50):
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
RFC = RandomForestClassifier()
RFC.fit(X_train, y_train)
y_pred = RFC.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
y_pred_proba = RFC.predict_proba(X_test)[::, 1]
auc = roc_auc_score(y_test, y_pred_proba)
accuracies.append(accuracy)
precisions.append(precision)
recalls.append(recall)
f1s.append(f1)
aucs.append(auc)
print(mean(accuracies),
mean(precisions),
mean(recalls),
mean(f1s),
mean(aucs)
)
输出:
0.7606926406926405 0.7001931059992001 0.5778712922956755 0.6306501622080503 0.8207846633339568
正如预期的那样,预测指标相似。但是,交叉验证 运行 的速度要快得多,并且使用整个数据集的每个数据点进行给定次数的测试(轮流)。