在scikit-learn中,cross_val_score, cross_val_predict, cross_validate均可以用来做交叉验证,不会将数据顺序打乱(除非指定fold的参数shuffle=True,默认为False),并且赋值给cv,如:
cv=KFold(n_splits=5,shuffle=True,random_state=0)
在不打乱的情况下遵循官网图,如图1的切片方式。
即所有的数据都一次机会被成块的作为测试集,所有的数据都有n-1次被用作训练集。
cross_val_score与cross_validate
在最新的版本sklearn 0.21中cross_val_score与cross_validate被统一,cross_val_score仅仅为调用cross_validate返回字典的结果。
cross_val_score,和cross_val_predict
cross_val_score,和cross_val_predict 的分片方式相同,区别就是cross_val_predict的返回值不能直接用于计算得分评价!官网已经注明:
意思是说,cross_val_predict返回的预测y值,是由分片的test y组合起来的,而这样y值的各个部分来源于不同的输入的学习器。
查看源代码可以看到:
把这些test y放在一起,看看预测值没问题,放在一起,评价得分,不合适!
为什么呢?
对比cross_val_score,我们发现道理很简单。
当我们使用cross_val_predict计算得分时候,将采用与cross_val_score不同的计算策略,即:
cross_val_score为先分片计算得分,后平均:
score = np.mean(cross_val_score(estimator, data_x, y, cv=5))
cross_val_predict为所有统一计算:
predict_y = cross_val_predict(estimator, data_x, y, cv=5)
score = r2_score(true_y,predict_y)
cross_val_score分片计算后平均的这种方式,可以认为是不同模型的平均结果,cross_val_predict计算得分没有道理可言。
而且,这两种计算结果在数据量小的时候差别很大,所以遵循官网警告,谢绝使用cross_val_predict计算得分。
那我一定要使用cross_val_predict计算得分怎么办呢?
也很简单,使用相同的fold,把y划分计算再平均就好了.
cv = KFold(n_splits=5, shuffle=False, random_state=0)
predict_y = cross_val_predict(estimator, data_x, y, cv=cv)
cv = KFold(n_splits=5, shuffle=False, random_state=0) # 这是个generator,用完就没了,所以再来一遍
test_index = [i[1] for i in cv.split(data_x)]
y_true_all = [y[_] for _ in test_index]
y_predict_all = [predict_y[_] for _ in test_index]
score = np.mean([r2_score(i, j) for i, j in zip(y_true_all, y_predict_all)])
这样结果是和cross_val_score完全统一的,等价于cross_val_score。
-----------------------------------------------------------------------------------------------
ps : 重点来了,为什么要写这个短文,因为这个狗东西:
r2_score注意事项
sklearn.metrics.r2_score(y_true,y_pred,sample_weight=None)
它用来衡量两列数值之间的趋势近似程度,如果按照感性的理解y_true,y_pred的位置应该是可以相互替换的,而且它的好朋友Pearsonr 系数的两个输入也是可以相互取代的。
所以我就没有在乎输入顺序的问题,反正放进去就好了,从来没有关注过谁在前面。
并且顺序弄反后,它不会报错,计算得分也看起来像那么回事,也在0-1之间。
但是它不行!顺序不同,计算值得分是不同的!
因为这个脑残的感性理解,我在发现代码结果与想象不同的时候,一度把矛头指向了GridSearch,cross_validate,cross_val_predict,cross_val_score。
在查看一些stackoverflow上骗孩子(我)的解说后,怀疑这是cross_val_predict的切片方式和cross_val_score不同。
然后从我自己的代码,一步一步debug到GridSearch, 到cross_val_predict,cross_val_score......