首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >cross_val_score与cross_val_predict的区别

cross_val_score与cross_val_predict的区别
EN

Stack Overflow用户
提问于 2017-04-25 22:25:32
回答 3查看 40K关注 0票数 30

我想使用交叉验证和混淆来评估使用scikitlearn构建的回归模型,我应该使用两个函数cross_val_scorecross_val_predict中的哪一个。一种选择是:

代码语言:javascript
复制
cvs = DecisionTreeRegressor(max_depth = depth)
scores = cross_val_score(cvs, predictors, target, cv=cvfolds, scoring='r2')
print("R2-Score: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

另一种方法是将cv预测与标准r2_score一起使用。

代码语言:javascript
复制
cvp = DecisionTreeRegressor(max_depth = depth)
predictions = cross_val_predict(cvp, predictors, target, cv=cvfolds)
print ("CV R^2-Score: {}".format(r2_score(df[target], predictions_cv)))

我假设这两种方法都是有效的,并给出类似的结果。但这只是小k折的情况。虽然10倍cv的r^2大致相同,但在使用"cross_vall_score“的第一个版本中,k值越高,r^2越低。第二个版本基本上不受折叠数量变化的影响。

这是意料之中的行为吗?我对SKLearn中的CV缺乏一些理解吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-04-25 22:45:25

cross_val_score返回测试文件夹的分数,其中cross_val_predict返回测试文件夹的预测y值。

对于cross_val_score(),您使用的是输出的平均值,这将受到折叠数量的影响,因为它可能有一些折叠,这些折叠可能具有很高的误差(不能正确拟合)。

然而,对于输入中的每个元素,cross_val_predict()将返回该元素在测试集中时获得的预测。请注意,只有将所有元素恰好分配给测试集一次的交叉验证策略才能使用。因此,增加折叠的数量只会增加测试元素的训练数据,因此其结果可能不会受到太大影响。

编辑(注释后)

关于cross_val_predict的工作原理,请看下面的答案:

How is scikit-learn cross_val_predict accuracy score calculated?

我认为cross_val_predict将是过度拟合的,因为随着折叠的增加,更多的数据将用于训练,而更少的数据将用于测试。因此,生成的标签更依赖于训练数据。另外,如上所述,对一个样本的预测只进行一次,因此它可能会更容易受到数据分裂的影响。这就是为什么大多数地方或教程推荐使用cross_val_score进行分析的原因。

票数 36
EN

Stack Overflow用户

发布于 2019-07-26 19:41:19

因此,这个问题也困扰着我,虽然另一个人提出了很好的观点,但他们并没有回答OP问题的所有方面。

真正的答案是:增加k的分数的差异是由于选择的指标R2 (决定系数)。例如,对于MSE、MSLE或MAE,使用cross_val_scorecross_val_predict没有任何区别。

请参阅definition of R2

R^2 =1-(MSE(地面实况,预测)/MSE(地面实况,mean(地面实况)__))

粗体部分解释了为什么分数开始随着k的增加而不同:我们拥有的拆分越多,测试折叠中的样本就越少,测试折叠均值的方差就越高。相反,对于较小的k,测试折叠的平均值将不会与完整的地面真实平均值相差太多,因为样本大小仍然足够大,以具有较小的方差。

证明:

代码语言:javascript
复制
import numpy as np
from sklearn.metrics import mean_absolute_error as mae
from sklearn.metrics import mean_squared_log_error as msle, r2_score

predictions = np.random.rand(1000)*100
groundtruth = np.random.rand(1000)*20

def scores_for_increasing_k(score_func):
    skewed_score = score_func(groundtruth, predictions)
    print(f'skewed score (from cross_val_predict): {skewed_score}')
    for k in (2,4,5,10,20,50,100,200,250):
        fold_preds = np.split(predictions, k)
        fold_gtruth = np.split(groundtruth, k)
        correct_score = np.mean([score_func(g, p) for g,p in zip(fold_gtruth, fold_preds)])

        print(f'correct CV for k={k}: {correct_score}')

for name, score in [('MAE', mae), ('MSLE', msle), ('R2', r2_score)]:
    print(name)
    scores_for_increasing_k(score)
    print()

输出将为:

代码语言:javascript
复制
MAE
skewed score (from cross_val_predict): 42.25333901481263
correct CV for k=2: 42.25333901481264
correct CV for k=4: 42.25333901481264
correct CV for k=5: 42.25333901481264
correct CV for k=10: 42.25333901481264
correct CV for k=20: 42.25333901481264
correct CV for k=50: 42.25333901481264
correct CV for k=100: 42.25333901481264
correct CV for k=200: 42.25333901481264
correct CV for k=250: 42.25333901481264

MSLE
skewed score (from cross_val_predict): 3.5252449697327175
correct CV for k=2: 3.525244969732718
correct CV for k=4: 3.525244969732718
correct CV for k=5: 3.525244969732718
correct CV for k=10: 3.525244969732718
correct CV for k=20: 3.525244969732718
correct CV for k=50: 3.5252449697327175
correct CV for k=100: 3.5252449697327175
correct CV for k=200: 3.5252449697327175
correct CV for k=250: 3.5252449697327175

R2
skewed score (from cross_val_predict): -74.5910282783694
correct CV for k=2: -74.63582817089443
correct CV for k=4: -74.73848598638291
correct CV for k=5: -75.06145142821893
correct CV for k=10: -75.38967601572112
correct CV for k=20: -77.20560102267272
correct CV for k=50: -81.28604960074824
correct CV for k=100: -95.1061197684949
correct CV for k=200: -144.90258384605787
correct CV for k=250: -210.13375041871123

当然,还有其他人提到的这里没有显示的另一种影响。随着k的增加,有更多的模型在更多的样本上训练,在更少的样本上验证,这将影响最终分数,但这不是由cross_val_scorecross_val_predict之间的选择引起的。

票数 8
EN

Stack Overflow用户

发布于 2018-10-24 16:19:40

我认为,通过检查他们的输出,可以清楚地看出其中的区别。考虑下面这段代码:

代码语言:javascript
复制
# Last column is the label
print(X.shape)  # (7040, 133)

clf = MLPClassifier()

scores = cross_val_score(clf, X[:,:-1], X[:,-1], cv=5)
print(scores.shape)  # (5,)

y_pred = cross_val_predict(clf, X[:,:-1], X[:,-1], cv=5)
print(y_pred.shape)  # (7040,)

注意这些形状:为什么是这样?scores.shape的长度为5,因为它是通过交叉验证超过5次计算得到的分数(请参阅参数cv=5)。因此,为每个折叠计算一个实值。该值是分类器的分数:

给定真实标签和预测标签,预测器在特定文件夹中有多少答案是正确的?

在这种情况下,输入中给出的y标签被使用了两次:从数据中学习和评估分类器的性能。

另一方面,y_pred.shape的长度为7040,这是数据集的形状。这是输入数据集的长度。这意味着每个值不是在多个值上计算的分数,而是单个值:分类器的预测:

给定输入数据及其标签,分类器对特定文件夹的测试集中的特定示例的预测是什么?

请注意,您不知道使用了哪个文件夹:每个输出都是根据某个文件夹的测试数据计算的,但是您不能分辨出是哪一个(至少从这个输出)。

在这种情况下,标签只使用一次:训练分类器。您的工作是将这些输出与真实输出进行比较,以计算分数。如果你只是对它们进行平均,就像你做的那样,输出不是分数,而是平均预测值。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43613443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档