ROLO
ROLO

Reputation: 4223

How to make lm display in its output a formula passed to it as a variable

Please consider the following example code (from the lm doc):

ctl <- c(4.17,5.58,5.18,6.11,4.50,4.61,5.17,4.53,5.33,5.14)
trt <- c(4.81,4.17,4.41,3.59,5.87,3.83,6.03,4.89,4.32,4.69)
group <- gl(2,10,20, labels=c("Ctl","Trt"))
weight <- c(ctl, trt)
lm(weight ~ group)
form1 <- weight ~ group
lm(form1)
do.call("lm",list(formula=form1))

With the following (abbreviated) output:

> lm(weight ~ group)

Call:
lm(formula = weight ~ group)

> lm(form1)

Call:
lm(formula = form1)

> do.call("lm",list(formula=form1))

Call:
lm(formula = weight ~ group)

As you can see, the second call to lm does not display the formula, but the variable containing the formula. With some experimenting, I came up with the third solution, but I find that one a bit tedious.

The question hence is: is there another way to make lm display the formula instead of the variable (i.e. without using the do.call method I used above).

(The reason I want this is that I am working on a Sweave document, so I cannot see the calls, only the outputs, and then is having lm tell you what formula it used very handy.)


EVEN BETTER SOLUTION - Thanks to @Aaron

lm <- function(...) {
  mf <- match.call()
  mf[[1]] <- quote(stats::lm)
  env <- parent.frame()
  mf$formula <- eval(mf$formula, env)
  eval(mf, env)
}

SOLUTION: Based on G. Grothendieck's answer, I came up with the following function:

lm <- function(...) {
    mf <- match.call()
    mf[[1]] <- quote(stats::lm)
    env <- parent.frame()
    fm <- eval(mf, env)
    fm$call$formula <- formula(fm)
    fm
}

Upvotes: 4

Views: 1809

Answers (4)

Aaron - mostly inactive
Aaron - mostly inactive

Reputation: 37734

A variant based on the OP's final solution (as of Mar 30).

lm <- function(formula, ...) {
  mf <- match.call()
  mf[[1]] <- quote("stats::lm")
  env <- parent.frame()
  mf$formula <- eval(mf$formula, env)
  eval(mf, env)
}

Upvotes: 2

G. Grothendieck
G. Grothendieck

Reputation: 269381

Put this near the top of your Sweave file:

<<preliminaries,echo=FALSE,results=hide>>=
lm <- function(fo, ...) { fm <- stats::lm(fo, ...); fm$call <- fo; fm }
@

and then call lm normally in the rest of the file.

Using the example in the question and assuming we have defined lm as above:

> lm(form1)

Call:
weight ~ group

Coefficients:
(Intercept)     groupTrt  
      5.032       -0.371  

Upvotes: 5

kohske
kohske

Reputation: 66842

You can modify the print.lm:

body(print.lm)[[2]] <- 
  as.call(expression({
    ca<-x$call
    ca$formula <- formula(x)
    cat("\nCall:\n", paste(deparse(ca), sep = "\n", collapse = "\n"), "\n\n", sep = "")
  })[[1]])

then,

> lm(form1)

Call:
lm(formula = weight ~ group)

Coefficients:
(Intercept)     groupTrt  
      5.032       -0.371  

Upvotes: 2

BenBarnes
BenBarnes

Reputation: 19454

This might be just as tedious, but at least it contains fewer characters ;)

R> eval(call("lm",form1))

Call:
lm(formula = weight ~ group)

Coefficients:
(Intercept)     groupTrt  
      5.032       -0.371 

Upvotes: 3

Related Questions