使用cross_val_predict和cross_val_score

时间:2020-06-04 18:21:18

标签: python machine-learning scikit-learn cross-validation

我希望这两种方法都返回类似的错误,有人可以指出我的错误吗?

正在计算RMSE ...

rf = RandomForestRegressor(random_state=555, n_estimators=100, max_depth=8)
rf_preds = cross_val_predict(rf, train_, targets, cv=7, n_jobs=7) 
print("RMSE Score using cv preds: {:0.5f}".format(metrics.mean_squared_error(targets, rf_preds, squared=False)))

scores = cross_val_score(rf, train_, targets, cv=7, scoring='neg_root_mean_squared_error', n_jobs=7)
print("RMSE Score using cv_score: {:0.5f}".format(scores.mean() * -1))

RMSE Score using cv preds: 0.01658
RMSE Score using cv_score: 0.01073

1 个答案:

答案 0 :(得分:1)

这里有两个问题,cross_val_predict的文档中都提到了这两个问题:

除非所有测试集的大小均相等并且度量标准在样本上分解,否则结果可能与cross_validatecross_val_score不同。

第一种是在两种情况下都使所有集合(训练和测试)相同,在您的示例中情况并非如此。为此,我们需要使用kfold方法来定义我们的CV折叠,然后在两种情况下都使用相同的折叠。这是虚拟数据的示例:

from sklearn.datasets import make_regression
from sklearn.model_selection import KFold, cross_val_score, cross_val_predict
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error

X, y = make_regression(n_samples=2000, n_features=4, n_informative=2,
                      random_state=42, shuffle=False)

rf = RandomForestRegressor(max_depth=2, random_state=0)
kf = KFold(n_splits=5)

rf_preds = cross_val_predict(rf, X, y, cv=kf, n_jobs=5) 
print("RMSE Score using cv preds: {:0.5f}".format(mean_squared_error(y, rf_preds, squared=False)))

scores = cross_val_score(rf, X, y, cv=kf, scoring='neg_root_mean_squared_error', n_jobs=5)
print("RMSE Score using cv_score: {:0.5f}".format(scores.mean() * -1))

上述代码段的结果(完全可重复,因为我们已经明确设置了所有必需的随机种子)的结果是:

RMSE Score using cv preds: 15.16839
RMSE Score using cv_score: 15.16031

因此,我们可以看到两个分数确实相似,但仍然不相同

那是为什么?答案在于上面引用的句子中相当隐秘的第二部分,即RMSE分数不会在样本上分解(老实说,我不知道它会得到任何ML分数)。

简而言之,cross_val_predict严格根据其定义(即(伪代码))计算RMSE:

RMSE = square_root([(y[1] - y_pred[1])^2 + (y[2] - y_pred[2])^2 + ... + (y[n] - y_pred[n])^2]/n)

其中n是样本数,cross_val_score方法不能做到这一点;相反,它的作用是为k个CV折叠中的每一个计算RMSE,然后平均这些k值,即(再次为伪代码):

RMSE = (RMSE[1] + RMSE[2] + ... + RMSE[k])/k

正是由于RMSE在样本中不可分解,所以这两个值虽然很接近,但不相同

我们可以通过手动执行CV程序并仿真cross_val_score并如上所述仿真RMSE计算来证明确实是这种情况,

import numpy as np
RMSE__cv_score = []

for train_index, val_index in kf.split(X):
    rf.fit(X[train_index], y[train_index])
    pred = rf.predict(X[val_index])
    err = mean_squared_error(y[val_index], pred, squared=False)
    RMSE__cv_score.append(err)

print("RMSE Score using manual cv_score: {:0.5f}".format(np.mean(RMSE__cv_score)))

结果是:

RMSE Score using manual cv_score: 15.16031

即与上面cross_val_score返回的相同。

因此,如果我们想非常精确,则事实是正确的RMSE(即完全根据其定义计算)是cross_val_predict返回的那个; cross_val_score返回它的近似值。但是在实践中,我们经常发现差异并不大,因此如果方便的话,我们也可以使用cross_val_score