2

In short, I have a list of expressions that I want to apply to each row of a dataframe. This is very similar to this question, but there is a subtle difference in that I do not have a list of functions, but have a list of expressions. Here's what I am attempting:

I have a dataframe of equation terms that I pass to paste to form text strings of expressions:

# build a test dataframe
a <- c(10, 11, 12)
b <- c(0.5, 06, 0.7)
c <- c(300, 400, 500)
d <- c(1000, 2000, NA)
p <- c(1.32, 1.37, 1.43)
m <- c(0.45, .55, .65)
params <- data.frame(a, b, c, d, p, m)

# create vector of expressions
ff.txt <- paste(params$a, "*2 + ",
    params$b, "*3 + ",
    params$c, "*4 + ",
    params$d, "*5 * ",
    "x * ", 
    params$p, " * ",
    params$m, 
    sep = "")

This will return a vector of expressions stored as text, such as "10*2 + 0.5*3 + 300*4 + 1000*5 * x * 1.32 * 0.45".

I then wrote a function to convert the text expression to an R expression using parse:

funs.list <- lapply(funs.txt, function(x) parse(file = "", text = x))

... where funs.txt is the vector of expressions stored as text.

Now, this is where I'm having difficulty. Imagine funs.list contains two expressions. If I do something like:

lapply(funs.list, eval, envir = list(x=c(7, 60)))

... I get back a 2x2 matrix, where I only want the answers are on the diagonal. (Ultimately I'm going to have about 1,000 expressions that will be called repeatedly as part of an optimization, so do not want the additional computational effort.)

The other approach I've tried is:

mapply(do.call, funs.list, lapply(params, list))

... but I get an error message from do.call stating 'what' must be a character string or a function.

Any suggestions on where to go from here?

Community
  • 1
  • 1
Blue Otter Hat
  • 607
  • 3
  • 9
  • 19
  • Do you ultimately want the text expressions or the numerical results from those expressions based on inputs from the data frame? – Tim Biegeleisen Jun 23 '15 at 10:36
  • @Tim I'm after the numerical result. The idea is that I can pass in a vector of x's which which then be evaluated. The lapply statement with an envir argument gives an example of this, where numerical results are returned. – Blue Otter Hat Jun 23 '15 at 10:42

2 Answers2

2

If I understand correctly you want to evaluate the first expression with the first value of x, the second with the second etc.

You could do:

mapply(function(ex, x) eval(ex, envir = list(x = x)), funs.list[1:2], c(7, 60))
Nick Kennedy
  • 12,510
  • 2
  • 30
  • 52
2

I feel that it would be a better design decision to define a custom R function corresponding to your algebraic expression and make use of the apply() function in row mode (which you appear to have overlooked in your original problem). This function also takes x as an input, and so I also cbind the x vector to the original data frame.

exp <- function(a, b, c, d, p, m, x) {
           result <- 2*a + 3*b + 4*c + 5*d*x*p*m
           return(result)
       }

x <- c(1, 2, 3)
params <- cbind(params, x)

output <- apply(params, 1, function(x) {
                               exp(x['a']], x['b'], x['c'], x[["d"]],
                                   x['p'], x['m'], x['x'])
                           })
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360