为啥交叉验证 RF 分类的性能比没有交叉验证的差?

Posted

技术标签:

【中文标题】为啥交叉验证 RF 分类的性能比没有交叉验证的差?【英文标题】:Why does cross validation RF classification perform worse than without cross validation?为什么交叉验证 RF 分类的性能比没有交叉验证的差? 【发布时间】:2018-09-07 18:10:11 【问题描述】:

我很困惑,为什么没有交叉验证的随机森林分类模型的平均准确度得分为 0.996,但使用 5 折交叉验证时,模型的平均准确度得分为 0.687。

有 275,956 个样本。 0 类 = 217891,1 类 = 6073,2 类 = 51992

我正在尝试预测“TARGET”列,即 3 个类别 [0,1,2]:

data.head()
bottom_temperature  bottom_humidity top_temperature top_humidity    external_temperature    external_humidity   weight  TARGET  
26.35   42.94   27.15   40.43   27.19   0.0  0.0    1   
36.39   82.40   33.39   49.08   29.06   0.0  0.0    1   
36.32   73.74   33.84   42.41   21.25   0.0  0.0    1   

从文档中,数据分为训练和测试

# link to docs http://scikit-learn.org/stable/modules/cross_validation.html
from sklearn.model_selection import train_test_split
from sklearn import datasets
from sklearn import svm

# Create a list of the feature column's names
features = data.columns[:7]

# View features
features
Out[]: Index([u'bottom_temperature', u'bottom_humidity', u'top_temperature',
       u'top_humidity', u'external_temperature', u'external_humidity',
       u'weight'],
      dtype='object')


#split data
X_train, X_test, y_train, y_test = train_test_split(data[features], data.TARGET, test_size=0.4, random_state=0)

#build model
clf = RandomForestClassifier(n_jobs=2, random_state=0)
clf.fit(X_train, y_train)

#predict
preds = clf.predict(X_test)

#accuracy of predictions
accuracy = accuracy_score(y_test, preds)
print('Mean accuracy score:', accuracy)

('Mean accuracy score:', 0.96607267423425713)

#verify - its the same
clf.score(X_test, y_test)
0.96607267423425713

关于交叉验证:

from sklearn.model_selection import cross_val_score
scores = cross_val_score(clf, data[features], data.TARGET, cv=5)
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

Accuracy: 0.69 (+/- 0.07)

它要低得多!

并验证第二种方法:

#predict with CV
# http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_predict.html#sklearn.model_selection.cross_val_predict
from sklearn.model_selection import cross_val_predict
predicted = cross_val_predict(clf, data[features], data.queen3, cv=5)
metrics.accuracy_score(data.queen3, predicted) 

Out[]: 0.68741031178883594

根据我的理解,交叉验证不应该将预测的准确性降低这么多,而是提高模型的预测,因为模型已经看到了所有数据的“更好”表示。

【问题讨论】:

您的目标类(0,1 和 2)之间的大致划分是多少?你有多少样本? 另外,你的数据是按目标类排序的吗? 没有数据是按删除的两个列排序的:groupID和timestamp(它是一个纵向重复测量数据集,监控了大约80个单独的环境) StratifiedKFold(在cross_val_score中使用)默认情况下不会在拆分前洗牌。我的理解是,这意味着您在进行交叉验证时还试图预测数据的时间元素。与train_test_split 不同,后者从数据集中随机抽取。作为测试,尝试设置cv=ms.StratifiedKFold(n_splits=5, shuffle=True) 所以都修好了?如果是这样,那太好了,我会把它作为答案,因为人们了解这种行为很重要。 【参考方案1】:

通常我会同意 Vivek 并告诉你相信你的交叉验证。

但是,随机森林中存在一定程度的 CV,因为每棵树都是从自举样本中生长出来的,因此在运行交叉验证时,您不应该期望看到准确度有如此大的下降。我怀疑您的问题是由于数据排序中的某种时间或位置依赖性造成的。

当您使用train_test_split 时,数据是从数据集中随机抽取的,因此您的所有 80 个环境都可能出现在您的训练和测试数据集中。但是,当您使用 CV 的默认选项进行拆分时,我相信每个折叠都是按顺序绘制的,因此您的每个环境都不存在于每个折叠中(假设您的数据是按环境排序的)。这会导致准确性降低,因为您是在使用来自另一个环境的数据来预测一个环境。

简单的解决方法是设置cv=ms.StratifiedKFold(n_splits=5, shuffle=True)

我之前在使用级联数据集时曾多次遇到过这个问题,而且肯定有数百人已经意识到并且还没有意识到问题所在。默认行为的想法是保持时间序列中的顺序(从我在 GitHub 讨论中看到的)。

【讨论】:

【参考方案2】:

train_test_split 中,您仅将 60% 的数据用于训练 (test_size=0.4) 一次。但是在cross_val_score 中,数据将被分成 80% 的火车(cv = 5)5 次(每次 4 折将成为火车,剩下的 1 次作为测试)。

现在您应该认为 80% 的训练数据超过 60%,因此准确度不应降低。但这里还有一件事需要注意。

默认情况下train_test_split 不会对拆分进行分层,但在cross_val_score 中会这样做。分层是在每个折叠中保持类(目标)的比率相同。所以最有可能的情况是,train_test_split 中没有保持目标的比例,这导致分类器过拟合,因此得分很高。

我建议将 cross_val_score 作为最终分数。

【讨论】:

【参考方案3】:

您的数据可能有一些固有的顺序。做 CV 的时候把“shuffle”改成true。

【讨论】:

以上是关于为啥交叉验证 RF 分类的性能比没有交叉验证的差?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要在 multiSVM 方法中进行交叉验证来进行图像分类?

为啥我的交叉验证始终比训练测试分割表现更好?

为啥 scikit-learn SVM 分类器交叉验证这么慢?

为啥我的交叉验证错误分类错误率与测试数据集成功率相矛盾

神经网络中啥是交叉验证,为啥要进行交叉验证?

为啥 10 倍交叉验证的准确度得分比使用 sklearn 的 90-10 train_test_split 最差?