Search code examples
rexpressioneval

combine multiple expressions in R into one big expression


I am new to R expression handling. I am stuck with below problem. Any input is appreciated.

I am trying to generate two individual equations and combine them into one expression and pass it to an algorithm to find optimal value.

   OLD_PRICE    ELAST      Units    
 1  59.98        1.3        151     
 2  59.98        1.3        230     

Code:

for(i in 1:nrow(df)){
    o[i] = df$OLD_PRICE[i]
    el[i] = df$ELAST[i]
    u[i] = df$Units[i]
    assign(paste0("l",i),(substitute((x)*(1-(x-o)*el/o)*u,     list(o=o[i],el=el[i],u=u[i]))))
}

I was able generate below two equations

l1 = (x) * (1 - (x - 59.98) * 1.3/59.98) * 151
l2 = (x) * (1 - (x - 59.98) * 1.3/59.98) * 230

And my objective function would look like this

eval_obj_f <- function(x){eval(l1)+eval(l2)}

I am trying to figure out how to do this dynamically. Like if I have a different dataset of 4 observations, how can I generate my objective function to be as below dynamically?

eval(l1)+eval(l2)+eval(l3)+eval(l4)

Solution

  • You need to be using real R expressions and at the moment those are not expressions but rather calls. (Check with is.expression or class). I don't like the name "df" for dataframes since it is a function name as well, so I used "prdat":

     o <- el <- u <- numeric(2)  # if they don't exist, then the loop errors out
     for(i in 1:nrow(prdat)){
         o[i] = prdat$OLD_PRICE[i]
         el[i] = prdat$ELAST[i]
         u[i] = prdat$Units[i]
         assign(paste0("l",i), as.expression(substitute(x*(1-(x-o)*el/o)*u, 
                                                       list(o=o[i],el=el[i],u=u[i]))))
                            }
    
    l1
    #expression(x * (1 - (x - 59.98) * 1.3/59.98) * 151) # how expressions appear when printed.
    l2
    #expression(x * (1 - (x - 59.98) * 1.3/59.98) * 230)
    exprlist <- list(l1,l2)
    
    eval_obj_f <- function(x){sum( sapply( exprlist, eval, envir=list(x=x) ) )}
    eval_obj_f(2)
    #[1] 1719.569
    

    This seems pretty clunky. I probably would have apply-ed a function over that dataframe and summed the results. I suppose it might be interesting to attempt the "compute on the language"-approach, but take alook at the code below which I think is more in keeping with the "R-way". Seems more compact ... and expressive:

    func <- function(x) {apply(prdat, 1, function(z) x*(1-
                                    (x-z["OLD_PRICE"])*z["ELAST"]/z["OLD_PRICE"])*z["Units"] )}
    > sum( func(x=2))
    [1] 1719.569
    

    This might be better than just using your code (but still a lot more clunky than the second method IMO):

    exprvec <- expression()
    o <- el <- u <- numeric(2)  
     for(i in 1:nrow(prdat)){
         o[i] = prdat$OLD_PRICE[i]
         el[i] = prdat$ELAST[i]
         u[i] = prdat$Units[i]
         exprvec[[i]] <- substitute(x*(1-(x-o)*el/o)*u, 
                                    list(o=o[i],el=el[i],u=u[i]))
                            }  #substitute-value gets coerced to mode-expression
    # Test
    > eval_obj_f <- function(x){sum( sapply( exprvec, eval, envir=list(x=x) ) )}
    > eval_obj_f(2)
    [1] 1719.569