用于公式的eval解析的包装函数

时间:2015-04-03 17:18:56

标签: r

我有一个输入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 parse组合,所以我决定编写一个包装函数:

#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 parse组合时不会发生这种情况,因为它会在lm()环境中发生,其中所选变量不会丢失。

这个问题有一些聪明的解决方案吗?在lm()中使用动态公式的更好方法是什么?否则我将不得不输入 eval(parse(text = object))

1 个答案:

答案 0 :(得分:5)

只要您尝试执行修改公式内容的操作,就应该使用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

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