R回归中的动态变量名

13

我意识到使用动态变量名的风险,因此我正在尝试循环遍历各种回归模型,其中选择不同的变量规范。通常情况下,!!rlang::sym() 可以很好地解决这种问题,但在回归中它会失败。一个最简示例如下:

y= runif(1000) 
x1 = runif(1000) 
x2 = runif(1000) 

df2= data.frame(y,x1,x2)
summary(lm(y ~ x1+x2, data=df2)) ## works

var = "x1"
summary(lm(y ~ !!rlang::sym(var)) +x2, data=df2) # gives an error

我的理解是,!!rlang::sym(var)) 会取出 var 的值(即 x1),并以 R 认为这是一个变量而不是字符的方式放入代码中。但我似乎是错了。有人能启发我一下吗?


3
你不能使用类似这样的东西吗:formula(paste0("y", "~", var, "+x2")) - RLave
1
确实是一个聪明的解决方案,我本来也可以想到。不过还是很有趣去了解为什么 !!rlang::sym() 没有按照我预期的方式运行。但还是感谢 @RLave。 - safex
4
如果按照以下方式使用,它就会起作用:summary(lm(expr(y ~ !!sym(var) + x2), data=df2)) - Dan
2
另一种可能性是 summary(lm(y ~ eval(as.symbol(var)) + x2, data=df2)) - tmfmnk
5
我会使用 var <- as.symbol(var); eval(bquote(summary(lm(y ~ .(var)+x2, data=df2))))。请将输出中的公式与其他解决方案得到的结果进行比较。 - Roland
3个回答

10

个人而言,我喜欢在语言上进行一些计算。对我来说,使用bquoteeval的结合最简单(易于记忆)。

var <- as.symbol(var)
eval(bquote(summary(lm(y ~ .(var) + x2, data = df2))))
#Call:
#lm(formula = y ~ x1 + x2, data = df2)
#
#Residuals:
#     Min       1Q   Median       3Q      Max 
#-0.49298 -0.26248 -0.00046  0.24111  0.51988 
#
#Coefficients:
#            Estimate Std. Error t value Pr(>|t|)    
#(Intercept)  0.50244    0.02480  20.258   <2e-16 ***
#x1          -0.01468    0.03161  -0.464    0.643    
#x2          -0.01635    0.03227  -0.507    0.612    
#---
#Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#
#Residual standard error: 0.2878 on 997 degrees of freedom
#Multiple R-squared:  0.0004708,    Adjusted R-squared:  -0.001534 
#F-statistic: 0.2348 on 2 and 997 DF,  p-value: 0.7908

我认为这种方法比不显示同样调用的任何方法都要好,如 summary(lm(y ~ x1+x2, data=df2))


这正是我一直想要的!谢谢! - kaz_yos

5

1) 只需使用lm(df2),如果lm除了问题中显示的列外还有其他列,但我们只想对x1x2进行回归,则可以使用此方法。

df3 <- df2[c("y", var, "x2")]
lm(df3)

以下是可选项,仅在重要时需要将公式显示为显式给定的形式。 使用下面的第一行计算公式fo,然后像第二行那样运行lm
fo <- formula(model.frame(df3))
fm <- do.call("lm", list(fo, quote(df3)))

或者只需像下面第一行那样运行lm,然后像第二行那样将公式写入其中:

fm <- lm(df3)
fm$call <- formula(model.frame(df3))

任何一个都会给出这个结果:
> fm
Call:
lm(formula = y ~ x1 + x2, data = df3)

Coefficients:
(Intercept)           x1           x2  
    0.44752      0.04278      0.05011  

2) 字符串 lm 接受一个字符字符串作为公式,所以这也是可行的。 fn$ 使得在字符参数中发生了替换。

library(gsubfn)

fn$lm("y ~ $var + x2", quote(df2))

或者通过更复杂的代码实现,而不使用gsubfn:

do.call("lm", list(sprintf("y ~ %s + x2", var), quote(df2)))

或者如果你不在意公式显示时没有替换var,那么就直接这样:

lm(sprintf("y ~ %s + x2", var), df2)

4
!! 这个双感叹号运算符只能与“整洁”的函数一起使用。它不是 R 语言的核心部分。像 lm() 这样的基本 R 函数无法扩展这种运算符。相反,您需要将其包装在可以进行扩展的函数中。例如,rlang::expr 就是其中之一。
rlang::expr(summary(lm(y ~ !!rlang::sym(var) + x2, data=df2)))
# summary(lm(y ~ x1 + x2, data = df2))

那么你需要使用 rlang::eval_tidy 来真正评估它。
rlang::eval_tidy(rlang::expr(summary(lm(y ~ !!rlang::sym(var) + x2, data=df2))))

# Call:
# lm(formula = y ~ x1 + x2, data = df2)
# 
# Residuals:
#     Min       1Q   Median       3Q      Max 
# -0.49178 -0.25482  0.00027  0.24566  0.50730 
# 
# Coefficients:
#               Estimate Std. Error t value Pr(>|t|)    
# (Intercept)  0.4953683  0.0242949  20.390   <2e-16 ***
# x1          -0.0006298  0.0314389  -0.020    0.984    
# x2          -0.0052848  0.0318073  -0.166    0.868    
# ---
# Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#
# Residual standard error: 0.2882 on 997 degrees of freedom
# Multiple R-squared:  2.796e-05,   Adjusted R-squared:  -0.001978 
# F-statistic: 0.01394 on 2 and 997 DF,  p-value: 0.9862

您可以看到,此版本保留了模型对象中的扩展公式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接