我在尝试在R
中使用多变量响应时遇到了该死的公式,并且出现了各种意想不到的行为,主要是在函数和包内使用它们时。这是一个双重问题
我可以输入一个多变量响应,并在之后使用模型进行预测吗?
这个MVE使用rpart
包作为示例。这里y
是一个两列的矩阵(响应),我想使用x
来预测y
,即x
中的每一列(在这个MVE中是两列)。请注意,method
本身以及y
中每一列的含义无关紧要,这只是一个用于重现问题的MVE:
library(rpart)set.seed(1)y <- rpois(10, lambda = 1.25)y <- cbind(c(1,4,10,11,12, 14,16,17,20, 21), y)print(y)x <- matrix(1:20, ncol = 2) # 只是两个虚拟预测变量print(x)mymodel <- rpart(y ~ x, method = "poisson", minbucket = 1)newx <- matrix(11:20, ncol = 2) # 只是几个虚拟测试预测变量,请注意我们有更少的行predict(mymodel, newdata = data.frame(newx))# 输出: 1 2 3 4 5 6 7 8 9 10 0.12500000 0.12500000 0.12500000 0.20000000 0.04761905 0.17948718 0.17948718 0.11538462 0.04000000 0.04000000 警告信息: 'newdata' 有5行,但找到的变量有10行
如您所见,我无法预测新数据集。我一直在摆弄列名和行名,但无法使其工作。
此外,
我如何创建一个“安全”的包装器?
例如,在这个MVE中:
mywrapper <- function(y, x){ mymodel <- rpart(y ~ x, method = "poisson", minbucket = 1) return(mymodel)}
并且提供了R文档中的帮助:
一个公式对象有一个关联的环境,这个环境(而不是父环境)被
model.frame
用来评估在提供的数据参数中未找到的变量。使用~
操作符创建的公式使用它们被创建的环境。使用as.formula
创建的公式将使用env
参数作为它们的环境。
我并不完全理解这意味着什么。据我所知,不输入y
或x
到mywrapper()
中会导致错误(这是预期行为)。我问这个问题是因为我在处理R包和包内的函数,我希望确保公式没有意外行为。
回答:
一般来说,R中的公式与数据框配合得很好。rpart
可以处理矩阵,而虽然数据框可以包含矩阵,但它们往往会被转换为单独的列。为了避免这种情况,请用I()
包装矩阵:
# 与您的代码开始部分相同...然后是这个:predict(mymodel, newdata = data.frame(x = I(newx)))#> 1 2 3 4 5 #> 0.04 0.04 0.04 0.04 0.04
在您问题的第二部分,您在mywrapper
函数中创建了一个公式,所以如果变量不在newdata
数据框中,它将在那里寻找变量。R中的“环境”类似于其他语言中的“堆栈框架”;主要区别在于环境只有一个父级,如果在原始环境中找不到对象,搜索将转到那里进行。
一般来说,父级不是调用者的框架,而是创建环境的框架,或者特别列为父级的某物。
因此,如果您在mywrapper
返回的值上运行predict
,它会查看公式以找到所需的变量。预测只需要右侧的变量,所以这就是x
。如果您在predict
的newdata
参数中提供x
,一切都会像以前一样进行,但如果您不提供,情况就会不同。
由于在newdata
中未找到x
,它会转到公式的环境中。那是mywrapper
的评估框架,它会在那里看到x
,因为它是该函数的一个参数。
如果它在寻找z
,它在那里找不到。下一个查找的地方是父环境,即创建mywrapper
时生效的环境,即全局环境。如果那里没有z
,它会搜索由search()
列出的环境链,这些通常是包的导出。search()
列表是连在一起的,每个条目是它前一个条目的父级。
希望这些信息不会太多……