Hallo I'm having trouble figuring out how to evaluate an expression when one of the variables in the expression is defined separately as a sub expression. Here's a simplified example mat <- expression(0, f1*s1*g1) # vector of formulae g1 <- expression(1/Tm) # expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible values for variables before adding this sub expression I was using the following to evaluate "mat" sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is much longer, and the sub expression more complicated. Also, the subexpression is often adjusted for different scenarios. Is there a simple way of changing this or redefining "mat" so that I can define "g1" like a macro to be used in the expression vector. Thanks! Jennifer
evaluating expressions with sub expressions
13 messages · Baptiste Auguie, Gabor Grothendieck, William Dunlap +3 more
Hi, Would this do as an alternative syntax? g1 <- quote(1/Tm) mat <- list(0, bquote(f1*s1*.(g1))) vals <- data.frame(f1=1, s1=.5, Tm=2) sapply(mat, eval, vals) HTH, baptiste On 29 January 2010 17:51, Jennifer Young
<Jennifer.Young at math.mcmaster.ca> wrote:
Hallo I'm having trouble figuring out how to evaluate an expression when one of the variables in the expression is defined separately as a sub expression. Here's a simplified example mat <- expression(0, f1*s1*g1) ?# vector of formulae g1 <- expression(1/Tm) ? ? ? ? ?# expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible values for variables before adding this sub expression I was using the following to evaluate "mat" sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is much longer, and the sub expression more complicated. Also, the subexpression is often adjusted for different scenarios. ?Is there a simple way of changing this or redefining "mat" so that I can define "g1" like a macro to be used in the expression vector. Thanks! Jennifer
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
Hmm I *think* this will work, but may break in a further sub routine. It certainly works in this example, but my expression vector is used in many scenarios and it will take a while to check them all. For instance, I take the derivative of each element with respect to each variable using sapply(mat, deriv, names(vals)) This bit seems to still work, but I'd welcome a solution that doesn't change the structure of the expression vector to a list, just in case. Thanks for this solution.
Hi, Would this do as an alternative syntax? g1 <- quote(1/Tm) mat <- list(0, bquote(f1*s1*.(g1))) vals <- data.frame(f1=1, s1=.5, Tm=2) sapply(mat, eval, vals) HTH, baptiste On 29 January 2010 17:51, Jennifer Young <Jennifer.Young at math.mcmaster.ca> wrote:
Hallo I'm having trouble figuring out how to evaluate an expression when one of the variables in the expression is defined separately as a sub expression. Here's a simplified example mat <- expression(0, f1*s1*g1) ?# vector of formulae g1 <- expression(1/Tm) ? ? ? ? ?# expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible values for variables before adding this sub expression I was using the following to evaluate "mat" sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is much longer, and the sub expression more complicated. Also, the subexpression is often adjusted for different scenarios. ?Is there a simple way of changing this or redefining "mat" so that I can define "g1" like a macro to be used in the expression vector. Thanks! Jennifer
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
The following recursively walks the expression tree. The esub function is from this page (you may wish to read that entire thread): http://tolstoy.newcastle.edu.au/R/help/04/03/1245.html esub <- function(expr, sublist) do.call("substitute", list(expr, sublist)) proc <- function(e, env = parent.frame()) { for(nm in all.vars(e)) { if (exists(nm, env) && is.language(g <- get(nm, env))) { if (is.expression(g)) g <- g[[1]] g <- Recall(g, env) L <- list(g) names(L) <- nm e <- esub(e, L) } } e } mat <- expression(0, f1*s1*g1) g1 <- expression(1/Tm) vals <- data.frame(f1=1, s1=.5, Tm=2) e <- sapply(mat, proc) sapply(e, eval, vals) The last line should give:
sapply(e, eval, vals)
[1] 0.00 0.25 On Fri, Jan 29, 2010 at 11:51 AM, Jennifer Young
<Jennifer.Young at math.mcmaster.ca> wrote:
Hallo I'm having trouble figuring out how to evaluate an expression when one of the variables in the expression is defined separately as a sub expression. Here's a simplified example mat <- expression(0, f1*s1*g1) ?# vector of formulae g1 <- expression(1/Tm) ? ? ? ? ?# expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible values for variables before adding this sub expression I was using the following to evaluate "mat" sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is much longer, and the sub expression more complicated. Also, the subexpression is often adjusted for different scenarios. ?Is there a simple way of changing this or redefining "mat" so that I can define "g1" like a macro to be used in the expression vector. Thanks! Jennifer
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
Folks: Stripped to its essentials, Jennifer's request seemed simple: substitute a subexpression as a named variable for a variable name in an expression, also expressed as a named variable. A simple example is:
e <- expression(0,a*b) z1 <- quote(1/t) ## explained below
The task is to "substitute" the expression in z1, "1/t", for "b" in e, yielding the substituted expression as the result. Gabor provided a solution, but it seemed to me like trying to swat a fly with a baseball bat -- a lot of machinery for what should be a more straightforward task. Of course, just because I think it **should be** straightforward does not mean it actually is. But I fooled around a bit (guided by Gabor's approach and an old Programmer's Niche column of Bill Venables) and came up with:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z1)))})
f
[[1]] [1] 0 [[2]] a * (1/t)
## f is a list. Turn it back into an expression f <- as.expression(f) ## check that this works as intended f
expression(0, a * (1/t))
a <- 2 t <- 3 eval(f)
[1] 0.6666667 Now you'll note that to do this I explicitly used quote() to produce the variable holding the subexpression to be substituted. You may ask, why not use expression() instead, as in
z2 <- expression(1/t)
This doesn't work:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z2)))})
f
[[1]] [1] 0 [[2]] a * expression(1/t)
f <- as.expression(f)
## Yielding ...
f
expression(0, a * expression(1/t)) #### Not what we want! ## And sure enough ...
eval(f)
Error in a * expression(1/t) : non-numeric argument to binary operator I think I understand why the z <- expression() approach does not work; but I do not understand why the z <- quote() approach does! The mode of the return from both of these is "call", but they are different (because identical() tells me so). Could someone perhaps elaborate on this a bit more? And is there a yet simpler and more straightforward way to do the above than what I proposed? Cheers, Bert Gunter Genentech Nonclinical Statistics -----Original Message----- From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On Behalf Of Gabor Grothendieck Sent: Friday, January 29, 2010 11:01 AM To: Jennifer Young Cc: r-help at r-project.org Subject: Re: [R] evaluating expressions with sub expressions The following recursively walks the expression tree. The esub function is from this page (you may wish to read that entire thread): http://tolstoy.newcastle.edu.au/R/help/04/03/1245.html esub <- function(expr, sublist) do.call("substitute", list(expr, sublist)) proc <- function(e, env = parent.frame()) { for(nm in all.vars(e)) { if (exists(nm, env) && is.language(g <- get(nm, env))) { if (is.expression(g)) g <- g[[1]] g <- Recall(g, env) L <- list(g) names(L) <- nm e <- esub(e, L) } } e } mat <- expression(0, f1*s1*g1) g1 <- expression(1/Tm) vals <- data.frame(f1=1, s1=.5, Tm=2) e <- sapply(mat, proc) sapply(e, eval, vals) The last line should give:
sapply(e, eval, vals)
[1] 0.00 0.25 On Fri, Jan 29, 2010 at 11:51 AM, Jennifer Young
<Jennifer.Young at math.mcmaster.ca> wrote:
Hallo I'm having trouble figuring out how to evaluate an expression when one of the variables in the expression is defined separately as a sub expression. Here's a simplified example mat <- expression(0, f1*s1*g1) ?# vector of formulae g1 <- expression(1/Tm) ? ? ? ? ?# expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible values for variables before adding this sub expression I was using the following to evaluate
"mat"
sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is much longer, and the sub expression more complicated. Also, the subexpression is often adjusted for different scenarios. ?Is there a simple way of changing this or redefining "mat" so that I can define "g1" like a macro to be used in the expression vector. Thanks! Jennifer
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
You asked
And is there a yet simpler and more
straightforward way to do the
above than what I proposed?
You could use S+, whose substitute() function
(a) descends into expressions and functions
(b) has an argument (evaluate=TRUE) so you
don't need to use do.call when the first
argument is not a literal
E.g.,
> e <- expression(a*b, function(x)x+b, log(b))
> substitute(e, list(b=Quote(exp(1))), evaluate=TRUE)
expression(a * exp(1), function(x)
x + exp(1), log(exp(1)))
Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com
-----Original Message----- From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On Behalf Of Bert Gunter Sent: Friday, January 29, 2010 1:38 PM To: 'Gabor Grothendieck'; 'Jennifer Young' Cc: r-help at r-project.org Subject: Re: [R] evaluating expressions with sub expressions Folks: Stripped to its essentials, Jennifer's request seemed simple: substitute a subexpression as a named variable for a variable name in an expression, also expressed as a named variable. A simple example is:
e <- expression(0,a*b) z1 <- quote(1/t) ## explained below
The task is to "substitute" the expression in z1, "1/t", for "b" in e, yielding the substituted expression as the result. Gabor provided a solution, but it seemed to me like trying to swat a fly with a baseball bat -- a lot of machinery for what should be a more straightforward task. Of course, just because I think it **should be** straightforward does not mean it actually is. But I fooled around a bit (guided by Gabor's approach and an old Programmer's Niche column of Bill Venables) and came up with:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z1)))})
f
[[1]] [1] 0 [[2]] a * (1/t)
## f is a list. Turn it back into an expression f <- as.expression(f) ## check that this works as intended f
expression(0, a * (1/t))
a <- 2 t <- 3 eval(f)
[1] 0.6666667 Now you'll note that to do this I explicitly used quote() to produce the variable holding the subexpression to be substituted. You may ask, why not use expression() instead, as in
z2 <- expression(1/t)
This doesn't work:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z2)))})
f
[[1]] [1] 0 [[2]] a * expression(1/t)
f <- as.expression(f)
## Yielding ...
f
expression(0, a * expression(1/t)) #### Not what we want! ## And sure enough ...
eval(f)
Error in a * expression(1/t) : non-numeric argument to binary operator I think I understand why the z <- expression() approach does not work; but I do not understand why the z <- quote() approach does! The mode of the return from both of these is "call", but they are different (because identical() tells me so). Could someone perhaps elaborate on this a bit more? And is there a yet simpler and more straightforward way to do the above than what I proposed? Cheers, Bert Gunter Genentech Nonclinical Statistics -----Original Message----- From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On Behalf Of Gabor Grothendieck Sent: Friday, January 29, 2010 11:01 AM To: Jennifer Young Cc: r-help at r-project.org Subject: Re: [R] evaluating expressions with sub expressions The following recursively walks the expression tree. The esub function is from this page (you may wish to read that entire thread): http://tolstoy.newcastle.edu.au/R/help/04/03/1245.html esub <- function(expr, sublist) do.call("substitute", list(expr, sublist)) proc <- function(e, env = parent.frame()) { for(nm in all.vars(e)) { if (exists(nm, env) && is.language(g <- get(nm, env))) { if (is.expression(g)) g <- g[[1]] g <- Recall(g, env) L <- list(g) names(L) <- nm e <- esub(e, L) } } e } mat <- expression(0, f1*s1*g1) g1 <- expression(1/Tm) vals <- data.frame(f1=1, s1=.5, Tm=2) e <- sapply(mat, proc) sapply(e, eval, vals) The last line should give:
sapply(e, eval, vals)
[1] 0.00 0.25 On Fri, Jan 29, 2010 at 11:51 AM, Jennifer Young <Jennifer.Young at math.mcmaster.ca> wrote:
Hallo I'm having trouble figuring out how to evaluate an
expression when one of
the variables in the expression is defined separately as a
sub expression.
Here's a simplified example mat <- expression(0, f1*s1*g1) ?# vector of formulae g1 <- expression(1/Tm) ? ? ? ? ?# expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible
values for
variables before adding this sub expression I was using the following
to evaluate "mat"
sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is
much longer, and
the sub expression more complicated. Also, the
subexpression is often
adjusted for different scenarios. ?Is there a simple way of
changing this
or redefining "mat" so that I can define "g1" like a macro
to be used in
the expression vector. Thanks! Jennifer
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. ______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. ______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
If its good enough to have one level of substitution then esub in my post (originally due to Tony Plate -- see reference in my post) is all that is needed: esub(mat[[2]], list(g1 = g1[[1]])) but I think the real problem could require multiple levels of substitution in which case repeated application of esub is needed as you walk the expression tree which is what proc() in my post does. For example, suppose mat[[2]] is a function of g1 which is a function of Tm which is a function of z. Then continuing the example in the original post this does the repeated substitution needed (which would be followed by an eval, not shown here, as in my original post):
Tm <- expression(z^2) sapply(mat, proc)
[[1]] [1] 0 [[2]] f1 * s1 * (1/z^2) To answer your question, quote() produces a call object but expression produces a call wrapped in an expression which is why there is special handling of expression objects in the proc() function in my post.
On Fri, Jan 29, 2010 at 4:38 PM, Bert Gunter <gunter.berton at gene.com> wrote:
Folks: Stripped to its essentials, Jennifer's request seemed simple: substitute a subexpression as a named variable for a variable name in an expression, also expressed as a named variable. A simple example is:
e <- expression(0,a*b) z1 <- quote(1/t) ## explained below
The task is to "substitute" the expression in z1, "1/t", for "b" in e, yielding the substituted expression as the result. Gabor provided a solution, but it seemed to me like trying to swat a fly with a baseball bat -- a lot of machinery for what should be a more straightforward task. Of course, just because I think it **should be** straightforward does not mean it actually is. But I fooled around a bit (guided by Gabor's approach and an old Programmer's Niche column of Bill Venables) and came up with:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z1)))})
f
[[1]] [1] 0 [[2]] a * (1/t)
## f is a list. Turn it back into an expression f <- as.expression(f) ## check that this works as intended f
expression(0, a * (1/t))
a <- 2 t <- 3 eval(f)
[1] 0.6666667 Now you'll note that to do this I explicitly used quote() to produce the variable holding the subexpression to be substituted. You may ask, why not use expression() instead, as in
z2 <- expression(1/t)
This doesn't work:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z2)))})
f
[[1]] [1] 0 [[2]] a * expression(1/t)
f <- as.expression(f)
## Yielding ...
f
expression(0, a * expression(1/t)) #### Not what we want! ## And sure enough ...
eval(f)
Error in a * expression(1/t) : non-numeric argument to binary operator I think I understand why the z <- expression() approach does not work; but I do not understand why the z <- quote() approach does! The mode of the return from both of these is "call", but they are different (because identical() tells me so). Could someone perhaps elaborate on this a bit more? And is there a yet simpler and more straightforward way to do the above than what I proposed? Cheers, Bert Gunter Genentech Nonclinical Statistics -----Original Message----- From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On Behalf Of Gabor Grothendieck Sent: Friday, January 29, 2010 11:01 AM To: Jennifer Young Cc: r-help at r-project.org Subject: Re: [R] evaluating expressions with sub expressions The following recursively walks the expression tree. ?The esub function is from this page (you may wish to read that entire thread): http://tolstoy.newcastle.edu.au/R/help/04/03/1245.html esub <- function(expr, sublist) do.call("substitute", list(expr, sublist)) proc <- function(e, env = parent.frame()) { ? for(nm in all.vars(e)) { ? ? ?if (exists(nm, env) && is.language(g <- get(nm, env))) { ? ? ? ? if (is.expression(g)) g <- g[[1]] ? ? ? ? ? ?g <- Recall(g, env) ? ? ? ? ? ?L <- list(g) ? ? ? ? ? ?names(L) <- nm ? ? ? ? ? ? e <- esub(e, L) ? ? ? ? ?} ? ? ? ?} ? ? e } mat <- expression(0, f1*s1*g1) g1 <- expression(1/Tm) vals <- data.frame(f1=1, s1=.5, Tm=2) e <- sapply(mat, proc) sapply(e, eval, vals) The last line should give:
sapply(e, eval, vals)
[1] 0.00 0.25 On Fri, Jan 29, 2010 at 11:51 AM, Jennifer Young <Jennifer.Young at math.mcmaster.ca> wrote:
Hallo I'm having trouble figuring out how to evaluate an expression when one of the variables in the expression is defined separately as a sub expression. Here's a simplified example mat <- expression(0, f1*s1*g1) ?# vector of formulae g1 <- expression(1/Tm) ? ? ? ? ?# expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible values for variables before adding this sub expression I was using the following to evaluate
"mat"
sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is much longer, and the sub expression more complicated. Also, the subexpression is often adjusted for different scenarios. ?Is there a simple way of changing this or redefining "mat" so that I can define "g1" like a macro to be used in the expression vector. Thanks! Jennifer
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. ______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
Inline below... -----Original Message----- From: Gabor Grothendieck [mailto:ggrothendieck at gmail.com] Sent: Friday, January 29, 2010 2:12 PM To: Bert Gunter Cc: Jennifer Young; r-help at r-project.org Subject: Re: [R] evaluating expressions with sub expressions If its good enough to have one level of substitution then esub in my post (originally due to Tony Plate -- see reference in my post) is all that is needed: esub(mat[[2]], list(g1 = g1[[1]])) --- Yes, this is essentially what I did using lapply but I think the real problem could require multiple levels of substitution in which case repeated application of esub is needed as you walk the expression tree which is what proc() in my post does. -- Indeed. But my point was to handle the simple case simply. To answer your question, quote() produces a call object but expression produces a call wrapped in an expression which is why there is special handling of expression objects in the proc() function in my post. -- Aha! And of course I should have realized that I could have easily determined this myself with:
as.list(quote(a*b))
[[1]] `*` [[2]] a [[3]] b ## But ...
e <- as.list(expression(a*b)) e
[[1]] a * b
mode(e[[1]])
[1] "call"
as.list(e[[1]])
[[1]] `*` [[2]] a [[3]] b So now all is clear to me. Thanks to both Bill and Gabor for their informative replies. -- Bert Bert Gunter Genentech Nonclinical Statistics
On Fri, Jan 29, 2010 at 4:38 PM, Bert Gunter <gunter.berton at gene.com> wrote:
Folks: Stripped to its essentials, Jennifer's request seemed simple: substitute a subexpression as a named variable for a variable name in an expression,
also
expressed as a named variable. A simple example is:
e <- expression(0,a*b) z1 <- quote(1/t) ## explained below
The task is to "substitute" the expression in z1, "1/t", for "b" in e, yielding the substituted expression as the result. Gabor provided a solution, but it seemed to me like trying to swat a fly with a baseball bat -- a lot of machinery for what should be a more straightforward task. Of course, just because I think it **should be** straightforward does not mean it actually is. But I fooled around a bit (guided by Gabor's approach and an old Programmer's Niche column of Bill Venables) and came up with:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z1)))})
f
[[1]] [1] 0 [[2]] a * (1/t)
## f is a list. Turn it back into an expression f <- as.expression(f) ## check that this works as intended f
expression(0, a * (1/t))
a <- 2 t <- 3 eval(f)
[1] 0.6666667 Now you'll note that to do this I explicitly used quote() to produce the variable holding the subexpression to be substituted. You may ask, why not use expression() instead, as in
z2 <- expression(1/t)
This doesn't work:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z2)))})
f
[[1]] [1] 0 [[2]] a * expression(1/t)
f <- as.expression(f)
## Yielding ...
f
expression(0, a * expression(1/t)) #### Not what we want! ## And sure enough ...
eval(f)
Error in a * expression(1/t) : non-numeric argument to binary operator I think I understand why the z <- expression() approach does not work; but
I
do not understand why the z <- quote() approach does! The mode of the
return
from both of these is "call", but they are different (because identical() tells me so). Could someone perhaps elaborate on this a bit more? And is there a yet simpler and more straightforward way to do the above than what
I
proposed? Cheers, Bert Gunter Genentech Nonclinical Statistics -----Original Message----- From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org]
On
Behalf Of Gabor Grothendieck Sent: Friday, January 29, 2010 11:01 AM To: Jennifer Young Cc: r-help at r-project.org Subject: Re: [R] evaluating expressions with sub expressions The following recursively walks the expression tree. ?The esub function is from this page (you may wish to read that entire thread): http://tolstoy.newcastle.edu.au/R/help/04/03/1245.html esub <- function(expr, sublist) do.call("substitute", list(expr, sublist)) proc <- function(e, env = parent.frame()) { ? for(nm in all.vars(e)) { ? ? ?if (exists(nm, env) && is.language(g <- get(nm, env))) { ? ? ? ? if (is.expression(g)) g <- g[[1]] ? ? ? ? ? ?g <- Recall(g, env) ? ? ? ? ? ?L <- list(g) ? ? ? ? ? ?names(L) <- nm ? ? ? ? ? ? e <- esub(e, L) ? ? ? ? ?} ? ? ? ?} ? ? e } mat <- expression(0, f1*s1*g1) g1 <- expression(1/Tm) vals <- data.frame(f1=1, s1=.5, Tm=2) e <- sapply(mat, proc) sapply(e, eval, vals) The last line should give:
sapply(e, eval, vals)
[1] 0.00 0.25 On Fri, Jan 29, 2010 at 11:51 AM, Jennifer Young <Jennifer.Young at math.mcmaster.ca> wrote:
Hallo I'm having trouble figuring out how to evaluate an expression when one of the variables in the expression is defined separately as a sub
expression.
Here's a simplified example mat <- expression(0, f1*s1*g1) ?# vector of formulae g1 <- expression(1/Tm) ? ? ? ? ?# expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible values for variables before adding this sub expression I was using the following to evaluate
"mat"
sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is much longer, and the sub expression more complicated. Also, the subexpression is often adjusted for different scenarios. ?Is there a simple way of changing this or redefining "mat" so that I can define "g1" like a macro to be used in the expression vector. Thanks! Jennifer
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. ______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
Thanks so much everyone! Bert's shorted example does what I need, but I'm filing away Gabor's solution for when I inevitably need it some day. I've never found the handling of variables in R to be very straightforward; sometimes I pine for Maple to do my algebra for me...
If its good enough to have one level of substitution then esub in my post (originally due to Tony Plate -- see reference in my post) is all that is needed: esub(mat[[2]], list(g1 = g1[[1]])) but I think the real problem could require multiple levels of substitution in which case repeated application of esub is needed as you walk the expression tree which is what proc() in my post does. For example, suppose mat[[2]] is a function of g1 which is a function of Tm which is a function of z. Then continuing the example in the original post this does the repeated substitution needed (which would be followed by an eval, not shown here, as in my original post):
Tm <- expression(z^2) sapply(mat, proc)
[[1]] [1] 0 [[2]] f1 * s1 * (1/z^2) To answer your question, quote() produces a call object but expression produces a call wrapped in an expression which is why there is special handling of expression objects in the proc() function in my post. On Fri, Jan 29, 2010 at 4:38 PM, Bert Gunter <gunter.berton at gene.com> wrote:
Folks: Stripped to its essentials, Jennifer's request seemed simple: substitute a subexpression as a named variable for a variable name in an expression, also expressed as a named variable. A simple example is:
e <- expression(0,a*b) z1 <- quote(1/t) ## explained below
The task is to "substitute" the expression in z1, "1/t", for "b" in e, yielding the substituted expression as the result. Gabor provided a solution, but it seemed to me like trying to swat a fly with a baseball bat -- a lot of machinery for what should be a more straightforward task. Of course, just because I think it **should be** straightforward does not mean it actually is. But I fooled around a bit (guided by Gabor's approach and an old Programmer's Niche column of Bill Venables) and came up with:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z1)))})
f
[[1]] [1] 0 [[2]] a * (1/t)
## f is a list. Turn it back into an expression f <- as.expression(f) ## check that this works as intended f
expression(0, a * (1/t))
a <- 2 t <- 3 eval(f)
[1] 0.6666667 Now you'll note that to do this I explicitly used quote() to produce the variable holding the subexpression to be substituted. You may ask, why not use expression() instead, as in
z2 <- expression(1/t)
This doesn't work:
f <- lapply(e,function(x){do.call(substitute,list(x,list(b=z2)))})
f
[[1]] [1] 0 [[2]] a * expression(1/t)
f <- as.expression(f)
## Yielding ...
f
expression(0, a * expression(1/t)) #### Not what we want! ## And sure enough ...
eval(f)
Error in a * expression(1/t) : non-numeric argument to binary operator I think I understand why the z <- expression() approach does not work; but I do not understand why the z <- quote() approach does! The mode of the return from both of these is "call", but they are different (because identical() tells me so). Could someone perhaps elaborate on this a bit more? And is there a yet simpler and more straightforward way to do the above than what I proposed? Cheers, Bert Gunter Genentech Nonclinical Statistics -----Original Message----- From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On Behalf Of Gabor Grothendieck Sent: Friday, January 29, 2010 11:01 AM To: Jennifer Young Cc: r-help at r-project.org Subject: Re: [R] evaluating expressions with sub expressions The following recursively walks the expression tree. ?The esub function is from this page (you may wish to read that entire thread): http://tolstoy.newcastle.edu.au/R/help/04/03/1245.html esub <- function(expr, sublist) do.call("substitute", list(expr, sublist)) proc <- function(e, env = parent.frame()) { ? for(nm in all.vars(e)) { ? ? ?if (exists(nm, env) && is.language(g <- get(nm, env))) { ? ? ? ? if (is.expression(g)) g <- g[[1]] ? ? ? ? ? ?g <- Recall(g, env) ? ? ? ? ? ?L <- list(g) ? ? ? ? ? ?names(L) <- nm ? ? ? ? ? ? e <- esub(e, L) ? ? ? ? ?} ? ? ? ?} ? ? e } mat <- expression(0, f1*s1*g1) g1 <- expression(1/Tm) vals <- data.frame(f1=1, s1=.5, Tm=2) e <- sapply(mat, proc) sapply(e, eval, vals) The last line should give:
sapply(e, eval, vals)
[1] 0.00 0.25 On Fri, Jan 29, 2010 at 11:51 AM, Jennifer Young <Jennifer.Young at math.mcmaster.ca> wrote:
Hallo I'm having trouble figuring out how to evaluate an expression when one of the variables in the expression is defined separately as a sub expression. Here's a simplified example mat <- expression(0, f1*s1*g1) ?# vector of formulae g1 <- expression(1/Tm) ? ? ? ? ?# expansion of the definition of g1 vals <- data.frame(f1=1, s1=.5, Tm=2) # one set of possible values for variables before adding this sub expression I was using the following to evaluate
"mat"
sapply(mat, eval, vals) Obviously I could manually substitute in 1/Tm for each g1 in the definition of "mat", but the actual expression vector is much longer, and the sub expression more complicated. Also, the subexpression is often adjusted for different scenarios. ?Is there a simple way of changing this or redefining "mat" so that I can define "g1" like a macro to be used in the expression vector. Thanks! Jennifer
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. ______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
On Sat, Jan 30, 2010 at 10:39 AM, Jennifer Young
<Jennifer.Young at math.mcmaster.ca> wrote:
handling of variables in R to be very straightforward; sometimes I pine for Maple to do my algebra for me...
There are several interfaces to Computer Algebra Systems in R. Try this (but read instructions on home page http://ryacas.googlecode.com first particularly the part about ensuring you have the right version of XML installed). Below, Sym creates a symbolic variable:
library(Ryacas)
Loading required package: XML
f1 <- Sym("f1")
s1 <- Sym("s1")
Tm <- Sym("Tm")
g1 <- 1/Tm
mat <- f1 * s1 * g1
mat
[1] "Starting Yacas!" expression(f1 * s1/Tm)
1 day later
(For R language geeks only)
Folks:
I think the best solution for the issue in the Subject line(see 29 January
thread on this for details) was the one Jennifer and Gabor previously
arrived at: (essentially)don't use R; instead, use a computer algebra system
that you can access through an R interface (e.g. Ryacas).
HOWEVER, I still wondered whether one could come up with a "simple" pure R
solution for simple but more general cases. What I offered previously was
too simple for the general case, as Gabor pointed out. It could do:
substitute the expression, "1/t" for "b" in the expression a*b;
but it could not descend further to handle:
substitute the expression, "1/t" for "b" in the expression a*b, where the
expression "sin(z+3)" is in turn to be substituted for t.
So I fooled with this a bit further and **think** (with trepidation) I found
that my previous approach does seem to extend to the general case by just
repeatedly processing the expression until done. One can even do this
without recursion (as it's tail recursion only) as follows (but see the
caveat below):
esub <- function(expr,sublist)
{
nm <- names(sublist)
while(length(intersect(all.vars(expr),nm))){
sub<- lapply(sublist, function(x)if(is.expression(x))x[[1]] else x)
expr
<-as.expression(lapply(expr,function(x)do.call(substitute,list(x,sub))))
}
expr
}
It can be used as:
Example 1:
z <- expression(a+b)
a <- quote(1/t)
b <- expression(x^2)
esub(z,list(a=a,b=b))
expression(1/t + x^2) CAVEAT: Note that all the expressions to be substituted can be formed by either quote() or expression(), ** but they must be explicitly given in a list.** In particular, they will not automatically be looked up for in the frame of the call, as was the case with Gabor's/Tony Plate's version. Example 2:
esub(z,list(a=a,b=b, x = quote(t+3), t = quote(exp(y)) ))
expression(1/exp(y) + (exp(y) + 3)^2) ## So now the substitutions properly extend into subexpressions. Example 3: ## Of course, this also works:
d <- quote(exp(y))
esub(z,list(a=a,b=b, x = quote(t^2+3), t = d ))
expression(1/exp(y) + (exp(y)^2 + 3)^2) I would appreciate being told (on list) if/how this scheme can be broken or a reference to other approaches (besides that which Gabor provided, of course). Clever improvements are also always welcome. Cheers to all, Bert Gunter Genentech Nonclinical Statistics
On Sun, 31 Jan 2010, Bert Gunter wrote:
(For R language geeks only) Folks: I think the best solution for the issue in the Subject line(see 29 January thread on this for details) was the one Jennifer and Gabor previously arrived at: (essentially)don't use R; instead, use a computer algebra system that you can access through an R interface (e.g. Ryacas). HOWEVER, I still wondered whether one could come up with a "simple" pure R solution for simple but more general cases. What I offered previously was too simple for the general case, as Gabor pointed out. It could do: substitute the expression, "1/t" for "b" in the expression a*b; but it could not descend further to handle: substitute the expression, "1/t" for "b" in the expression a*b, where the expression "sin(z+3)" is in turn to be substituted for t. So I fooled with this a bit further and **think** (with trepidation) I found that my previous approach does seem to extend to the general case by just repeatedly processing the expression until done. One can even do this without recursion (as it's tail recursion only) as follows (but see the caveat below):
This is more or less what bquote() does, and it works, recursively, in a few lines of pure R (it just doesn't solve your particular problem because it substitutes for .() rather than for b).
-thomas
Thomas Lumley Assoc. Professor, Biostatistics
tlumley at u.washington.edu University of Washington, Seattle
Thankyou Thomas. Yes, I was motivated by bquote(). It is sooooo slick (to some extent, still too slick for me). I wanted to do it nonrecursively because it's both clearer (I think) and maybe even more efficient (though I doubt this is detectable in any case). Bert Gunter Genentech Nonclinical Statistics -----Original Message----- From: Thomas Lumley [mailto:tlumley at u.washington.edu] Sent: Sunday, January 31, 2010 2:57 PM To: Bert Gunter Cc: 'Gabor Grothendieck'; 'Jennifer Young'; r-help at r-project.org Subject: Re: [R] (With trepidation): Evaluating expressions with sub expressions again
On Sun, 31 Jan 2010, Bert Gunter wrote:
(For R language geeks only) Folks: I think the best solution for the issue in the Subject line(see 29 January thread on this for details) was the one Jennifer and Gabor previously arrived at: (essentially)don't use R; instead, use a computer algebra
system
that you can access through an R interface (e.g. Ryacas). HOWEVER, I still wondered whether one could come up with a "simple" pure R solution for simple but more general cases. What I offered previously was too simple for the general case, as Gabor pointed out. It could do: substitute the expression, "1/t" for "b" in the expression a*b; but it could not descend further to handle: substitute the expression, "1/t" for "b" in the expression a*b, where the expression "sin(z+3)" is in turn to be substituted for t. So I fooled with this a bit further and **think** (with trepidation) I
found
that my previous approach does seem to extend to the general case by just repeatedly processing the expression until done. One can even do this without recursion (as it's tail recursion only) as follows (but see the caveat below):
This is more or less what bquote() does, and it works, recursively, in a few
lines of pure R (it just doesn't solve your particular problem because it
substitutes for .() rather than for b).
-thomas
Thomas Lumley Assoc. Professor, Biostatistics
tlumley at u.washington.edu University of Washington, Seattle