Имена динамических переменных в регрессиях R - PullRequest
0 голосов
/ 05 декабря 2018

Зная об опасности использования динамических имен переменных, я пытаюсь перебрать регрессионные модели переменных, где выбираются различные спецификации переменных.Обычно !!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 ]

0 голосов
/ 05 декабря 2018

Оператор bang-bang !! работает только с функциями "tidy".Это не часть основного языка R.Базовая R-функция, такая как lm(), не знает, как расширить такие операторы.Вместо этого вам нужно обернуть те функции, которые могут выполнять расширение.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

Вы можете видеть, что эта версия сохраняет расширенную формулу в объекте модели.

0 голосов
/ 06 декабря 2018

Лично мне нравится делать это с некоторыми вычислениями на языке.Для меня комбинация bquote с eval является самой легкой (чтобы запомнить).

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)).

0 голосов
/ 05 декабря 2018

1) Просто используйте lm(df2) или, если lm имеет дополнительные столбцы сверх того, что показано в вопросе, но мы просто хотим регрессировать на x1 и x2, затем

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...