Is it possible to assign a string containing variable names to a variable in R?
For example imagine I have the string "log(p_n) + log((1 - p_n)) + log(p_n * p_b) + log(p_n * (1 - p_b)) + log((1 - p_n) * p_g)"
. I'd like to make this function:
formula_function = function(p_n, p_b, p_g){
x <- log(p_n) + log((1 - p_n)) + log(p_n * p_b) + log(p_n * (1 - p_b)) + log((1 - p_n) * p_g)
return(x)
}
I have a function which generates the formula strings and I'm just copy-pasting them by hand at the moment, is there a more 'program-y' way of doing it?
1) body Assuming you know the parameters:
x <- "log(p_n) + log((1 - p_n)) + log(p_n * p_b) + log(p_n * (1 - p_b)) + log((1 - p_n) * p_g)"
f <- function(p_n, p_b, p_g) {}
body(f) <- parse(text = x)
f
## function (p_n, p_b, p_g)
## log(p_n) + log((1 - p_n)) + log(p_n * p_b) + log(p_n * (1 - p_b)) +
## log((1 - p_n) * p_g)
2) as.function The gsubfn package has a function for converting formulas to functions. The order of the formal arguments will be in the order encountered in x or you can specify the order. Convert the string to a formula using reformulate and then use as.function.
library(gsubfn)
# args are in order encountered
f <- as.function(reformulate(x))
f
## function (p_n, p_b, p_g)
## log(p_n) + log((1 - p_n)) + log(p_n * p_b) + log(p_n * (1 - p_b)) +
## log((1 - p_n) * p_g)
# specify order of args
f <- as.function(reformulate(x, "p_n + p_g + p_b"))
f
## function (p_n, p_g, p_b)
## log(p_n) + log((1 - p_n)) + log(p_n * p_b) + log(p_n * (1 - p_b)) +
## log((1 - p_n) * p_g)
3) match.funfn gsubfn also has match.funfn that is like match.fun in R except it also translates arguments passed as formulas to functions. e.g.
library(gsubfn)
myfun <- function(a, b, c, fun) {
f <- match.funfn(fun)
f(a, b, c)
}
myfun(0.1, 0.1, 0.1, reformulate(x, "p_n + p_g + p_b"))
## [1] -11.82901
4) fn$ gsubfn also provides fn which when prefixed to an arbitrary function will interpret formulas as functions. See the help file ?fn
for details. Note that sapply was not specially written for this but it works anyways.
library(gsubfn)
fn$sapply(1:3, ~ x^2)
## [1] 1 4 9