【问题标题】:PLS in R: Predicting new observations returns Fitted values insteadR 中的 PLS:预测新观察值改为返回拟合值
【发布时间】:2016-01-04 09:04:27
【问题描述】:

在过去的几天里,我在 R 中开发了多个 PLS 模型,用于光谱数据(波段作为解释变量)和各种植被参数(作为个体响应变量)。数据集总共包含 56 个。前 28 个(训练集)已用于模型校准,现在我要做的就是预测测试集中剩余 28 个观察值的响应值。然而,出于某种原因,R 继续返回给定数量的组件的校准集的拟合值,而不是独立测试集的预测。简而言之,模型如下所示。

# first simulate some data
set.seed(123)
bands=101
data <- data.frame(matrix(runif(56*bands),ncol=bands))
colnames(data) <- paste0(1:bands)
data$height <- rpois(56,10)
data$fbm <- rpois(56,10)
data$nitrogen <- rpois(56,10)
data$carbon <- rpois(56,10)
data$chl <- rpois(56,10)
data$ID <- 1:56

data <- as.data.frame(data)
caldata <- data[1:28,] # define model training set
valdata <- data[29:56,] # define model testing set

# define explanatory variables (x)
spectra <- caldata[,1:101]

# build PLS model using training data only
library(pls)
refl.pls <- plsr(height ~ spectra, data = caldata, ncomp = 10, validation = 
"LOO", jackknife = TRUE)

然后确定由 3 个组件组成的模型在没有过度拟合的情况下产生了最佳性能。因此,以下命令用于使用上述校准的 3 个分量的 PLS 模型预测测试集中 28 个观测值的值:

predict(refl.pls, ncomp = 3, newdata = valdata)

虽然输出看起来很明智,但我很快发现,所有这段代码生成的都是 PLS 模型对校准/训练数据的拟合值,而不是预测。我发现了这一点,因为下面的代码,其中 newdata = 被省略,产生相同的结果。

predict(refl.pls, ncomp = 3)

肯定有什么地方出了问题,尽管我似乎无法找出具体是什么。有没有人可以并且愿意帮助我朝着正确的方向前进?

【问题讨论】:

  • 请尽量让您的代码可重现,因为我们无权访问您的数据。
  • 您确定valdata 的数据格式正确吗?拆分数据集后,您会进行大量数据转换(并且不要在任何地方使用 caldata 数据框)。正如 Pascal 所说,请让您的示例可重现。
  • 我现在添加了一些数据模拟,希望这就足够了。我确实做了各种拆分,首先将训练与测试数据分开(按行)。然后我将 X 与 Y 变量(按列)分开,一个数据框包含所有光谱数据列 (X) 和各种数据框,每个数据框都包含一列响应变量 (Y)。在 PLS 模型构建的实际代码中,我指的是“spectra”,它实际上是指 caldata 数据框。我也指 HEIGHT,它也指 caldata 数据框。
  • 我猜你的问题中不再需要data &lt;- read.table("CALVAL_FWHM30_indices+spectra.txt", header=TRUE) data &lt;- as.data.frame(data)。此外,plsr 函数将 data.frame 作为输入。您可能可以避免创建HEIGHT、FBM...等等
  • 我可以以某种方式看到您试图到达的位置,但是如何在不调用整个数据帧的情况下调用 plsr 函数中数据帧中的光谱数据?我需要在 plsr 函数之前进行一些拆分,以将 X 与 Y 变量分开。

标签: r regression


【解决方案1】:

我认为问题在于输入数据的性质。查看示例中的?plsr 和str(yarn),plsr 需要一个非常具体的数据框,我觉得很难使用它。输入数据框应该有一个矩阵作为它的元素之一(在你的情况下是光谱数据)。我认为以下工作正常(注意我更改了训练集的大小,使其不是原始数据的一半,以便进行故障排除):

library("pls")
set.seed(123)
bands=101
spectra = matrix(runif(56*bands),ncol=bands)
DF <- data.frame(spectra = I(spectra),
        height = rpois(56,10),
        fbm = rpois(56,10),
        nitrogen = rpois(56,10),
        carbon = rpois(56,10),
        chl = rpois(56,10),
        ID = 1:56)
class(DF$spectra) <- "matrix" # just to be certain, it was "AsIs"
str(DF)

DF$train <- rep(FALSE, 56)
DF$train[1:20] <- TRUE

refl.pls <- plsr(height ~ spectra, data = DF, ncomp = 10, validation = 
"LOO", jackknife = TRUE, subset = train)

res <- predict(refl.pls, ncomp = 3, newdata = DF[!DF$train,])

请注意,我通过使用I(相当于AsIs)将光谱数据作为矩阵保存到数据框中。可能有一种更标准的方法可以做到这一点,但它确实有效。正如我所说,对我而言,数据框内的矩阵并不完全直观,也不易于理解。

至于为什么您的版本不能正常工作,我认为最好的解释是所有内容都需要在您传递给plsr 的一个数据框中,以便数据源完全明确。

【讨论】:

  • 亲爱的 Bryan,感谢您提供广泛而全面的回答。我试图将您建议的代码调整为我的(非模拟)数据,该数据已经存储在单个数据框中,并在一段时间后设法让代码运行。然而,奇怪的是,与我仅使用由前 28 个条目组成的数据框构建模型时相比,PLS 模型校准发现了不同的最佳模型组件数量和各种统计数据(例如 R2、RMSE、PRESS 等)的不同值.
  • 我确实设法为预测问题创建了一些解决方法。我定义了spectra 两次,一次是spectra &lt;- caldata[,8:ncol(caldata)],第二次是spectra &lt;- valdata[,8:ncol(valdata)]。我首先只运行了第一段代码并构建了 PLS 模型,然后我运行了第二段代码来重新定义验证集的光谱。然后,使用原始预测函数,我能够使用验证集的光谱数据和校准中发现的因子载荷/系数来检索不同参数的预测。
  • 听起来你正在解决它。只需不断检查并再次检查您的结果,以便您知道您可以相信最终答案。 plsr的作者有一本很好的书,涵盖了这个主题,我想我在网上免费看到过。
猜你喜欢
  • 2020-07-24
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
  • 2016-10-15
  • 1970-01-01
  • 2021-06-06
  • 2018-11-26
  • 1970-01-01
相关资源
最近更新 更多