为什么交叉验证分数这么低?

数据挖掘 scikit-学习 随机森林 交叉验证 k-nn 网格搜索
2021-09-27 13:22:23

我正在使用 Scikit-Learn 来解决这个分类问题。该数据集有 3 个特征和 600 个带标签的数据点。

首先我使用Nearest Neighbor了分类器。我没有使用交叉验证,而是手动运行拟合 5 次,每次都将数据集 (80-20) 重新拆分为训练集和测试集。结果平均分是0.61

clf = KNeighborsClassifier(4)
score = 0
for i in range(5):
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
        clf.fit(X_train, y_train)
        score += clf.score(X_test, y_test)
print(scores / 5.0)

然而,当我进行交叉验证时,平均得分仅为0.45.

clf =  KNeighborsClassifier(4)
scores = cross_val_score(clf, X, y, cv=5)
scores.mean()

为什么交叉验证产生的分数明显低于手动重采样?

我也试过Random Forest分类器。这次使用Grid Search来调整参数:

param_grid = {
    'bootstrap': [True],
    'max_depth': [8, 10, 12],
    'min_samples_leaf': [3, 4, 5],
    'min_samples_split': [8, 10, 12],
    'n_estimators': [62, 64, 66, 68, 70]
}
clf_ = RandomForestClassifier()
grid_search = GridSearchCV(estimator = clf, param_grid = param_grid, 
                          cv = 5, n_jobs = -1, verbose = 2)
grid_search.fit(X, y)
grid_search.best_params_, grid_search.best_score_

最好的分数原来是0.508使用以下参数

({'bootstrap': True,
  'max_depth': 10,
  'min_samples_leaf': 4,
  'min_samples_split': 10,
  'n_estimators': 64},
 0.5081967213114754)

我继续对整个600个数据点进行预测,准确度很高0.7688

best_grid = grid_search.best_estimator_
y_pred = best_grid.predict(X)
accuracy_score(y, y_pred)

我知道.best_score_是“best_estimator 的平均交叉验证分数”。但我不明白为什么它看起来比整个集合的预测准确度低得多。

2个回答

在您的随机森林中,这是因为您的最终模型过度拟合。SklearnGridSearchCV有一个默认参数refit = True,它基于交叉验证采用具有最佳性能的模型,并在整个数据集中对其进行重新训练。accuracy score的值非常高,因为它仅根据您的训练数据进行测量,并且该best_score测量值包含了您的模型在它未见过的模型中的表现。

总而言之,在您的随机森林中,您的过度拟合非常严重,因为您的验证和训练错误之间存在很大差距。尝试使用refit = False,您将不会再看到这种差距(但您仍然遇到问题,因为您仍然使用此模型过度拟合您的训练集)。

我知道这个问题已经存在两年了,但是,cross_val_score在我的数据上使用时我遇到了同样的问题,我最终来到了这里。

从函数返回的结果与cross_val_score我手动使用 进行交叉验证时得到的结果非常不同train_test_split,就像您使用最近邻分类器所做的那样。显然,cross_val_score按照原始顺序拆分数据而不进行改组。因此,当我使用手动交叉验证对数据进行洗牌时,sklearn.utils.shuffle我得到了更一致的结果。

我是 scikitlearn 的新手,所以如果上面有问题,请原谅我。