[R] Trying to learn how to write an "advanced" function

Ivan Krylov kry|ov@r00t @end|ng |rom gm@||@com
Thu Mar 16 16:25:16 CET 2023


В Thu, 16 Mar 2023 14:53:33 +0000
"Sorkin, John" <jsorkin using som.umaryland.edu> пишет:

> I am trying to run the lm function on two different formulae:
> 1) y~x, 
> 2) y~x+z

A formula is already an unevaluated object that doesn't need further
quoting; thus it can be passed around like a normal variable. It
consists of a call to the `~` operator and an attached environment that
can be accessed using environment(the_formula_object). This makes it
reference your variables if they are accessible at the point where
you're creating the formula.

Wouldn't it be better to explicitly package your data in a data.frame
and pass that to lm together with the formula? Then no non-standard
evaluation is needed at all:

doit <- function(formula, data) lm(formula, data)
data <- data.frame(
 y = 1:10, x = 1:10 + rnorm(10), z = c(rep(1,5), rep(2,5))
)
doit(y~x, data)
doit(y~x+z, data)

> doit <- function(x){
>   ds <- deparse(substitute(x))
>   cat("1\n")
>   print(ds)
>   eval(lm(quote(ds)),parent.frame())
> }

If you do want to make a "macro" that would construct a call and
evaluate it as if you ran it yourself in the calling environment of the
"macro", the trick is to (1) construct an expression and (2) feed it to
eval().

One problem here is that you feed the substituted expression to
deparse(). deparse() returns a source code string (maybe a string
vector of length() > 1!), which is useful for plot labels, but is on a
level too low for computing on the language itself. Keep the expression
object returned by substitute():

ds <- substitute(x)

The other problem is that eval() doesn't quote its arguments itself, so
eval(lm(...)) will first evaluate lm() and then feed the result to
eval(). What you need to do instead is create a call to lm. There is
more than one way to do it:

expr <- quote(lm())
expr[[2]] <- ds

# or

expr <- call('lm', ds)

Once you have the call set up the way you want it, you can evaluate it:

eval(expr, parent.frame())

-- 
Best regards,
Ivan



More information about the R-help mailing list