Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can eval be called within a data frame with variables defined in that data frame?

Tags:

dataframe

r

eval

Consider:

quotes<-alist(x, x+1, x+2)
data.frame(x=c(5, 10, 15), lapply(quotes, eval))

This does not work because eval cannot find x. Is there any way to get eval to recognize the variables that were defined in the data frame? I know that I could assign the data frame to some variables and then build it up with functions like transform, but I'm looking to do all of this within my call to data.frame.

For a possible version of the intended outputs, we can use this:

quotes<-alist(x, x+1, x+2)
x=c(5, 10, 15)
data.frame(x, lapply(quotes, eval))
like image 234
J. Mini Avatar asked Nov 18 '25 02:11

J. Mini


2 Answers

Have you noticed that the simpler call data.frame(x, y = x) wouldn't work either ?

data.frame() uses standard evaluation so in your case they'll be evaluated in the global environment.

If you name your quotes elements you'll be able to do tibble(x, !!!quotes) though, because tibble works differently.

Technically the following might be acceptable to you, we cheat by creating a temp value in the global environment, which we then remove on exit.

(I use evalq only to be able to use on.exit)

quotes<-alist(x, x+1, x+2)

df <- data.frame(
  x = c(5, 10, 15) ->> .t.e.m.p., 
  evalq({
    on.exit(rm(.t.e.m.p., envir = .GlobalEnv))
    lapply(quotes, eval, list(x= .t.e.m.p.))
  }))

df
#>    x c.5..10..15. c.6..11..16. c.7..12..17.
#> 1  5            5            6            7
#> 2 10           10           11           12
#> 3 15           15           16           17

ls(all.names = TRUE)
#> [1] "df"     "quotes"

Created on 2021-05-11 by the reprex package (v0.3.0)

This looks of course horrible, and using transform, within or tibble is probably a wiser choice.

like image 190
Moody_Mudskipper Avatar answered Nov 19 '25 18:11

Moody_Mudskipper


In case you don't mind when x is created in .GlobalEnv, and potentially overwriting it, you can use <- inside data.frame.

quotes<-alist(x, x+1, x+2)

data.frame(x=x <- c(5, 10, 15), lapply(quotes, eval))
#   x c.5..10..15. c.6..11..16. c.7..12..17.
#1  5            5            6            7
#2 10           10           11           12
#3 15           15           16           17

rm(x)

You can call it inside local but then x is not created in the .GlobalEnv and eval needs to be told to look in current environment.

local(data.frame(x=x <- c(5, 10, 15), lapply(quotes, eval, environment())))
#   x c.5..10..15. c.6..11..16. c.7..12..17.
#1  5            5            6            7
#2 10           10           11           12
#3 15           15           16           17

It is also possible to assign the values to a different name but here eval needs a list with the name x. Note that in this case TMP would be first created or overwritten and if needed, afterwards removed with rm from the .GlobalEnv.

data.frame(x=TMP <- c(5, 10, 15), lapply(quotes, eval, list(x=TMP)))
#   x c.5..10..15. c.6..11..16. c.7..12..17.
#1  5            5            6            7
#2 10           10           11           12
#3 15           15           16           17

rm(TMP)

Other (but not asked/wanted) possibilities might be using transform:

transform(data.frame(x=c(5, 10, 15)), y=lapply(quotes, eval, environment()))
#   x y.c.5..10..15. y.c.6..11..16. y.c.7..12..17.
#1  5              5              6              7
#2 10             10             11             12
#3 15             15             16             17

within:

within(data.frame(x=c(5, 10, 15)), y <- lapply(quotes, eval, environment()))
#   x         y
#1  5 5, 10, 15
#2 10 6, 11, 16
#3 15 7, 12, 17

or tibble:

tibble::tibble(x=c(5, 10, 15), y=sapply(quotes, eval, environment()))
## A tibble: 3 x 2
#      x y[,1]  [,2]  [,3]
#  <dbl> <dbl> <dbl> <dbl>
#1     5     5     6     7
#2    10    10    11    12
#3    15    15    16    17

And finally (for reference) the intended output from the question:

x <- c(5, 10, 15)
data.frame(x, lapply(quotes, eval))
#   x c.5..10..15. c.6..11..16. c.7..12..17.
#1  5            5            6            7
#2 10           10           11           12
#3 15           15           16           17

rm(x)
like image 30
GKi Avatar answered Nov 19 '25 16:11

GKi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!