Home > database >  (R) How can a bigger expression be written by combining shorter variable expressions?
(R) How can a bigger expression be written by combining shorter variable expressions?

Time:05-15

Brief introduction, I have multiple data file that can be fitted by models based in mathematical equations that are a combination (by sum, mutiplication, etc...) of other shorter mathematical equations.

As an example I have three short equations:

expression1 <- exp(x)
expression2 <- exp(x^2)
expression3 <- exp(1/x)

Because each data file has it's own bigger expression that produce a better fit, I want to be able to generate these larger expressions as a combitaion of the shorter expressions.

What I want is to be able to write something like this:

expression1(1) expression1(2) * expression2(3) expression2(1)

And get:

x1 x2 * x3^2 1/x1

Later I will use this larger equations to find the values x1, x2, x3 that better fits one data file.

CodePudding user response:

1) Presumably you meant expression rather than exp. Making that change we define e1, e2, e3 and e. esub is a function which replaces a variable name with another in an expression. gsubfn in the package of the same name is like gsub except the second argument can be a function (possibly expressed using formula notation as we do here) which takes the capture groups in the pattern as arguments and replaces the entire pattern with the output of the function. We deparse e, use gsubfn and parse it back.

library(gsubfn)

e1 <- expression(x)
e2 <- expression(x^2)
e3 <- expression(1/x)
e <- expression(e1(1)   e1(2) * e2(3)   e2(1))

esub <- function(expr, env) do.call("substitute", list(expr, env))
g <- gsubfn("(\\w )[(](\\w )[)]", 
  ~ deparse(esub(get(x)[[1]], list(x = as.name(paste0("x", y))))), 
  deparse(e))
parse(text = g)[[1]]
## expression(x1   x2 * x3^2   x1^2)

2) If it were desired to use strings instead of expressions it is even shorter:

library(gsubfn)

s1 <- "x"
s2 <- "x^2"
s3 <- "1/x"
s <- "s1(1)   s1(2) * s2(3)   s2(1)"

gsubfn("(\\w )[(](\\w )[)]", x   y ~ gsub("\\bx\\b", paste0("x", y), get(x)), s)
## [1] "x1   x2 * x3^2   x1^2"

CodePudding user response:

exp is the exponential function, so your code doesn't do what you think it does. To get something like this to work probably needs the creation of a new S3 class with print and Ops methods:

make_exp <- function(expr) {
  expr <- match.call()$expr
  function(x) structure(list(val = do.call(substitute, list(expr))), 
                        class = "ex")
}

print.ex <- function(x, ...) print(x$val)

Ops.ex <- function(e1, e2) structure(list(val = call(.Generic, e1$val, e2$val)),
                                      class = "ex")

This allows

expression1 <- make_exp(x)
expression2 <- make_exp(x^2)
expression3 <- make_exp(1/x)

expression1(x1)   expression2(x2) * expression3(x3)
#> x1   x2^2 * (1/x3)
  • Related