0

I would like to evaluate a string, eg x1, where x1 <- "disp", as the underlying value, i.e. disp, when x1 is the loop index.

A reproducible example, using the mtcars dataset as an example is below:


x1 <- "disp"
x2 <- "hp"

vars <- c("x1", "x2")

for (x in vars){
  print(x)
}

Which gives me

#> [1] "x1"
#> [1] "x2"

Desired Outcome:

What I'm trying to get is a loop that runs these commands:

print(x1)
print(x2)

resulting in:

#> [1] "disp"
#> [1] "hp"

I recognise that the simplest solution would be to bypass x1 and x2 completely:

vars <- c("disp", "hp")

for (x in vars){
  print(x)
}

But that's less helpful, as it will be very helpful to have x1, x2, etc, in my (unsimplified) problem.

Also, if purrr is a better way to do something like this, instead of a loop, I'd be very interested to understand that better.

If anyone has a suggestion on a better title for the question, I will also be very interested.

Deeper Question

I simplified my question above, hoping that would be enough to get what I needed, but for context, I'm trying to do something like this:

df <- mtcars

x1 <- "disp"
x2 <- "hp"

vars <- c("x1", "x2")

for (x in vars){
  lm(mpg ~ x, data = mtcars)
}

Created on 2019-07-11 by the reprex package (v0.2.1)

kath
  • 7,624
  • 17
  • 32
Jeremy K.
  • 1,710
  • 14
  • 35
  • 3
    you are looking for `get`. do `print(get(x))` in your `for` loop. – Ronak Shah Jul 11 '19 at 07:06
  • @RonakShah. Wonderful. The question above is a simplication: I'm actually trying to do something more like: `for (x in vars){ lm(mpg ~ get(x), data = mtcars) }`. For some reason the `get()` there doesn't work for me. – Jeremy K. Jul 11 '19 at 07:10

3 Answers3

2

The answer to your original question is to use get. However, since you want to do something beyond that and want to use vars as it is we can use get with as.formula

lst <- vector("list", length(vars))
for (x in seq_along(vars)) { 
   lst[[x]] <- lm(as.formula(paste0("mpg ~", get(vars[x]))), mtcars)
}

#[[1]]

#Call:
#lm(formula = as.formula(paste0("mpg ~", get(vars[.x]))), data = mtcars)

#Coefficients:
#(Intercept)         disp  
#    29.5999      -0.0412  


#[[2]]

#Call:
#lm(formula = as.formula(paste0("mpg ~", get(vars[.x]))), data = mtcars)

#Coefficients:
#(Intercept)           hp  
#    30.0989      -0.0682  

Using purrr you can do that with map

purrr::map(seq_along(vars), ~lm(as.formula(paste0("mpg ~", get(vars[.x]))), mtcars))
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • 2
    And using `%>%`, you could make it more explicit: `vars %>% map_chr(get) %>% paste0("mpg ~ ", .) %>% map(as.formula) %>% map(~ lm(., data=mtcars))` – January Jul 11 '19 at 07:30
  • @RonakShah Thank you. I'm not familiar with initialising a list this way: `lst <- vector("list", length(vars))`; I've only used `list()` rather than `vector()`. I tried Googling to see if I can find more out about this, but couldn't find a clear explanation. Is there a name or term for what you're doing in that line? – Jeremy K. Jul 11 '19 at 08:19
  • 1
    @RAndStata Whenever you are initialising anything usually it's a good practice to do it with fixed length. So `n <- numeric(10)` is better than only `n <- numeric()`, same goes with lists. There are different ways to initialise a list I showed one way. I had learned it from second answer of this post https://stackoverflow.com/questions/19340079/how-to-declare-list-object-with-m-elements – Ronak Shah Jul 11 '19 at 08:26
2

We can use lapply from base R and reformulate

lapply(mget(vars), function(x) 
       lm(reformulate(response = "mpg", termlabels = x), data = mtcars))
#$x1

#Call:
#lm(formula = reformulate(response = "mpg", termlabels = x), data = mtcars)

#Coefficients:
#(Intercept)         disp  
#   29.59985     -0.04122  


#$x2

#Call:
#lm(formula = reformulate(response = "mpg", termlabels = x), data = mtcars)

#Coefficients:
#(Intercept)           hp  
#   30.09886     -0.06823  
akrun
  • 874,273
  • 37
  • 540
  • 662
1

Already answered, but:

library(rlang)
library(tidyverse)

vars <- exprs(disp, hp) # without "character-quotes"
map(seq_along(vars), ~eval(expr(lm(mpg ~ !!vars[[.x]], mtcars))))

# or
vars <- c("disp", "hp")
map(vars, ~exec("lm", str_c("mpg ~ ", .x), data = mtcars))
r.user.05apr
  • 5,356
  • 3
  • 22
  • 39