我有一个输入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))。
答案 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
如您所见,第二个参数可以是包含一个或多个变量的公式或字符串。这极大地简化了动态修改公式的创建,您只需要尝试更改公式的一部分。