2

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

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

之后,我可以使用以下命令打印出准确度,例如 R2 或 RMSE:

R2(pls.fa,ncomp=1:xcomp)

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

Intercept)      1 comps      2 comps      3 comps      4 comps      5 comps      6 comps      7 comps      8 comps      9 comps  
  -0.009828     0.551053     0.570584     0.574790     0.580414     0.583354     0.585812     0.580690     0.581536     0.595441  
   10 comps  
   0.596096  

我的问题是:这个交叉验证产生的 R2 是什么,是 10 倍的平均值吗?

谢谢

4

1 回答 1

4

我进行了一些测试,看起来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)

library(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

现在平均超过折叠更乐观

因此,一种方法并不总是更乐观。

于 2018-04-23T06:18:19.757 回答