如何在pls R的交叉验证中计算R2和RMSE

时间:2018-04-22 22:44:23

标签: r cross-validation pls

我正在使用Mevik的pls R包进行偏最小二乘回归(2007)。 具有10倍交叉验证的模型如下:

left join

之后,我可以使用以下方法打印出精度,例如R2或RMSE:

group by

其中xcomp是最佳组件数。 例如,R2的结果如下所示:

pls.fa <- plsr(FA ~ ., ncomp = xcomp,scale = TRUE, validation = "CV", segments = 10,jackknife =TRUE, data=train)

我的问题是:这种交叉验证产生的R2是10倍的平均值?

由于

1 个答案:

答案 0 :(得分:2)

我执行了一些测试,R2RMSE返回的pls::R2pls::RMSEP似乎不是10倍的平均值。通过从所有10个CV折叠中提取预测,并将它们与观察到的结果进行比较,一次性使用所有保留样本计算它们:

以下是一个例子:

library(pls)

使用内置纱线数据集拟合模型:

data(yarn)
pls.fa <- plsr(density ~ NIR,
               data = yarn,
               ncomp = 6,
               scale = TRUE,
               validation = "CV",
               segments = 10,
               jackknife = TRUE)

我将使用等效的caret函数进行比较

以下代码返回使用前1:6组件获得的RMSE:

pls::RMSEP(pls.fa, ncomp = 1:6, estimate = "CV", intercept = FALSE) 
#output
1 comps  2 comps  3 comps  4 comps  5 comps  6 comps  
 8.4692   2.5553   1.9430   1.0151   0.7399   0.5801  

以数字向量的形式提取RMSE:

unlist(lapply(1:6, function(x) pls::RMSEP(pls.fa,
                                          ncomp = 1:6,
                                          estimate = "CV",
                                          intercept = FALSE)$val[,,x]))

让我们使用所有数据将输出与caret::RMSE进行比较:

all.equal(
  unlist(lapply(1:6, function(x) caret::RMSE(pls.fa$validation$pred[,,x],
                                             yarn$density))),
  unlist(lapply(1:6, function(x) pls::RMSEP(pls.fa,
                                            ncomp = 1:6,
                                            estimate = "CV",
                                            intercept = FALSE)$val[,,x])))
#output  
TRUE

因此RMSEP是使用所有保留预测计算的。

等同于R2

all.equal(
  unlist(lapply(1:6, function(x) caret::R2(pls.fa$validation$pred[,,x],
                                           yarn$density,
                                           form = "traditional"))),
  unlist(lapply(1:6, function(x) pls::R2(pls.fa,
                                         ncomp = 1:6,
                                         estimate = "CV",
                                         intercept = FALSE)$val[,,x])))
#output  
TRUE

编辑:回答评论中的问题:

哪种方式更适合在折叠上平均RMSE,或者从折叠中提取所有预测并计算一个RMSE:

在我看来,无论哪种方式都是好的,在比较模型时,只需要在计算中加入。请考虑以下示例:

set.seed(1)
true <- rnorm(100)
fold <- sample(1:10, size = 100, replace = T)
pred <- rnorm(100)

z <- data.frame(true, pred, fold)

库(tidyverse)

z %>%
  group_by(fold) %>%
  summarise(rmse = caret::RMSE(true, pred)) %>%
  pull(rmse) %>%
  mean
#ouput
 1.479923

z %>%
  summarise(rmse = caret::RMSE(true, pred)) %>%
  pull(rmse) 
#ouput
1.441471
与拉动所有预测和计算RMSE相比,这里对折叠的平均值给出了更悲观的结果。

使用与set.seed(2)相同的代码:

平均折叠:1.442483 拉全部:1.500432

现在平均折叠更为乐观

所以一种方式并不总是更乐观。