【问题标题】:Wrapper function for eval parse for use in formulas用于 eval 解析的包装函数,用于公式
【发布时间】:2015-04-03 17:18:55
【问题描述】:

我有一个函数,它输入一个 data.frame 并输出它的残差版本,其中一些选定的变量作为预测器。

residuals.DF = function(data, resid.var, suffix="") {
  lm_f = function(x) {
    x = residuals(lm(data=data, formula= x ~ eval(parse(text=resid.var))))
  }
  resid = data.frame(apply(data,2,lm_f))
  colnames(resid) = paste0(colnames(data),suffix)
  return(resid)
}

set.seed(31233)
df = data.frame(Age = c(1,3,6,7,3,8,4,3,2,6),
                Var1 = c(19,45,76,34,83,34,85,34,27,32),
                Var2 = round(rnorm(10)*100))

df.res = residuals.DF(df, "Age", ".test")
df.res
        Age.test   Var1.test  Var2.test
1  -1.696753e-17 -25.1351351  -90.20582
2  -1.318443e-19  -0.8108108   31.91892
3  -5.397735e-18  27.6756757   84.10603
4  -5.927747e-18 -15.1621622 -105.83160
5  -3.807699e-18  37.1891892  -57.08108
6  -6.457759e-18 -16.0000000  -25.76923
7   5.117344e-17  38.3513514  -65.01871
8  -3.807699e-18 -11.8108108   35.91892
9  -3.277687e-18 -17.9729730   97.85655
10 -5.397735e-18 -16.3243243   94.10603

这很好用,但是,在处理 lm() 的变量输入时,我经常需要使用 eval 解析组合,所以我决定编写一个包装函数:

#Wrapper function for convenience for evaluating strings
evalparse = function(string) {
  eval(parse(text=string))
}

单独使用时效果很好,例如:

> evalparse("5+5")
[1] 10

但是,如果在上述函数中使用它,则会得到:

> df.res = residuals.DF(df, "Age", ".test")
Error in eval(expr, envir, enclos) : object 'Age' not found 

我认为这是因为包装函数意味着字符串在其自己的环境中被评估,其中所选变量缺失。使用 eval 解析组合时不会发生这种情况,因为它随后会发生在不缺少所选变量的 lm() 环境中。

这个问题有什么巧妙的解决办法吗?在 lm() 中使用动态公式的更好方法?否则我将不得不继续输入 eval(parse(text=object))

【问题讨论】:

  • 你试过用mget()代替eval(parse())吗?
  • get() 在上面的例子中有效,mget() 没有(返回错误的类型列表)。
  • 啊,是的,对不起,我的意思是get()。您可以使用mget(),但您需要mget()[[1]] 从列表中获取项目。如果get() 适合您,我会将其作为答案而不是评论发布。
  • 如果xy 是数据框DF 中两列的名称,那么这会在x 上回归y(带有截距) :lm(DF[c(y, x)]) 不使用parseeval、公式等。

标签: r


【解决方案1】:

当您尝试执行修改公式内容的操作时,您应该使用update,因为它就是为此目的而设计的。

在你的情况下,你想修改你的功能如下:

residuals.DF = function(data, resid.var, suffix="") {
  lm_f = function(x) {
    x = residuals(lm(data=data, formula= update(x ~ 0, paste0("~",resid.var))))
  }
  resid = data.frame(apply(data,2,lm_f))
  colnames(resid) = paste0(colnames(data),suffix)
  return(resid)
}

基本上,update(或特别是update.formula method)将公式作为其第一个参数,然后允许根据其第二个参数进行修改。要了解它,请查看以下示例:

f <- y ~ x
f
# y ~ x
update(f, ~ z)
# y ~ z
update(f, x ~ y)
# x ~ y
update(f, "~ x + y")
# y ~ x + y
update(f, ~ . + z + w)
# y ~ x + z + w
x <- "x"
update(f, paste0("~",x))
# y ~ x

如您所见,第二个参数可以是包含一个或多个变量的公式或字符串。这极大地简化了动态修改公式的创建,您只需尝试更改公式的一部分。

【讨论】:

  • 这很整洁,是的。之前有人基于as.formula()发布了一个解决方案,但显然决定将其删除。像这样:x = residuals(lm(data=data, formula= as.formula(paste0("x ~ ",resid.var, collapse=""))))
  • 另外,不要忘记?reformulate 处理这些类型的任务。
猜你喜欢
  • 1970-01-01
  • 2021-05-06
  • 2014-05-30
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多