eply

William Michael Landau

2017-01-26

The eply package processes batches of quoted expressions. Just as apply() acts on data frames of function arguments, eply() acts on data frames of quoted expressions that return arguments. The package also has evals(), which simply evaluates a character vector of quoted expressions, plus some nice utilities.

Function eply()

library(eply)

eply() applies a function over a data frame of quoted expressions.

Begin with a function.

.fun = example.fun
.fun
## function (x, y) 
## {
##     mean(x/y)
## }
## <environment: namespace:eply>

Then, make a data frame of quoted expressions that return arguments to .fun.

.expr = example.expr()
.expr
##                                  x y rep
## 1 subset(mtcars, cyl == 4, mpg, T) a   A
## 2  subset(mtcars, cyl == 4, wt, T) a   A
## 3 subset(mtcars, cyl == 4, mpg, T) b   A
## 4  subset(mtcars, cyl == 4, wt, T) b   A
## 5 subset(mtcars, cyl == 4, mpg, T) a   B
## 6  subset(mtcars, cyl == 4, wt, T) a   B
## 7 subset(mtcars, cyl == 4, mpg, T) b   B
## 8  subset(mtcars, cyl == 4, wt, T) b   B
# str(.expr) # The expressions are actually just characters.

Define the variables referenced in .expr.

a = 1
b = 2

For each row in .expr, eply() evaluates the expressions and feeds the results to .fun.

eply(.fun, .expr)
##         1         2         3         4         5         6         7 
## 26.663636  2.285727 13.331818  1.142864 26.663636  2.285727 13.331818 
##         8 
##  1.142864

Function evals()

evals() evaluates a character vector of quoted expressions.

evals(c("1+1", "2+2", "3+3"))
## 1+1 2+2 3+3 
##   2   4   6
evals(c("1+1", "2+2", "3+3"), .simplify = FALSE)
## $`1+1`
## [1] 2
## 
## $`2+2`
## [1] 4
## 
## $`3+3`
## [1] 6
a = 4
evals(c("subset(mtcars, cyl == a, mpg, TRUE)", "mtcars[1:2, 1:2]"))
## $`subset(mtcars, cyl == a, mpg, TRUE)`
##  [1] 22.8 24.4 22.8 32.4 30.4 33.9 21.5 27.3 26.0 30.4 21.4
## 
## $`mtcars[1:2, 1:2]`
##               mpg cyl
## Mazda RX4      21   6
## Mazda RX4 Wag  21   6

Control the evaluation environment

Use the .with argument to control the environment in which the expressions are evaluated. .with can be a list, data frame, or environment. Data in the calling environment may be used as well, so take care to avoid ambiguities.

.fun = function(x) return(x)
.expr = data.frame(x = c("1+a", "1+b"))
rownames(.expr) = c("expr1", "expr2")
a = b = 0
.with = list(a = 1, b = 2)
eply(.fun, .expr, .with)
## expr1 expr2 
##     2     3
evals(.expr$x, .with)
## 1+a 1+b 
##   2   3

The .with argument is especially important if you wish to pass eply() or evals() to an iteration function like lapply().

.expr2 = split(.expr, f = .expr$x) # list of rows of .expr
lapply(.expr2, eply, .fun = .fun, .with = .with)
## $`1+a`
## expr1 
##     2 
## 
## $`1+b`
## expr2 
##     3
lapply(c("1+X", "2+Y"), evals, .with = list(X = 1, Y = 2))
## [[1]]
## 1+X 
##   2 
## 
## [[2]]
## 2+Y 
##   4

Parallel execution

Eply does not implement any special parallel computing functionality. However, the parallel package may be used on non-Windows machines to distribute subsets of .expr across parallel processes. The output of parallel::mclapply() is a list, so take care to simplify if necessary (say, to a data frame).

library(parallel)
.fun = example.fun
expr.dataframe = example.expr()
expr.list = split(expr.dataframe, f = expr.dataframe$rep) # split expr.dataframe by rep
.with = example.with()
mclapply(X = expr.list, FUN = eply, .fun = .fun, .with = .with, mc.cores = 2)

The parallelization of evals() with mclapply() is similar. For an alternative, consider the plyr package to parallelize eply() over chunks of .expr. See the “Parallel processing” section of the linked guide.

Character vector manipulation

If you want some quoted expressions to evaluate to character strings, enclosed them with literal escaped quotes.

.expr = data.frame(
  string = quotes(c("a", "b")),
  variable = c("c", "d"))
.expr
##   string variable
## 1    "a"        c
## 2    "b"        d
.fun = function(string, variable) paste(string, variable)
.with = list(c = "C", d = "D")
eply(.fun, .expr, .with)
##     1     2 
## "a C" "b D"

You can use single or double quotes.

quotes(c("x", "y"))
## [1] "\"x\"" "\"y\""
quotes(c("x", "y"), single = FALSE)
## [1] "\"x\"" "\"y\""
quotes(c("x", "y"), single = TRUE)
## [1] "'x'" "'y'"

Undo with unquote().

.expr$string = unquote(.expr$string)
.expr
##   string variable
## 1      a        c
## 2      b        d
x = quotes(quotes(c("x", "y"), single = TRUE))
x
## [1] "\"'x'\"" "\"'y'\""
unquote(x, deep = TRUE)
## [1] "x" "y"
unquote(x, deep = FALSE)
## [1] "'x'" "'y'"

Turn valid expressions into strings with strings().

data.frame(
  arg1 = strings(a + b, sqrt(x) - 2), 
  arg2 = 1:2)
##          arg1 arg2
## 1       a + b    1
## 2 sqrt(x) - 2    2

More help

help_eply()
## The package vignette has a full tutorial, and it is available at the following webpages.
##     https://CRAN.R-project.org/package=eply/vignettes/eply.html
##     https://cran.r-project.org/web/packages/eply/vignettes/eply.html
## For troubleshooting, navigate to the link below.
##     https://github.com/wlandau-lilly/eply/blob/master/TROUBLESHOOTING.md
## To submit bug reports, usage questions, feature requests, etc., navigate to the link below.
##     https://github.com/wlandau/eply-lilly/issues