Manuel Ramón
Manuel Ramón

Reputation: 2498

How to use a character as attribute of a function

I want to run a multiple comparisons analysis for the different variables of a model. My idea is as follows:

library(multcomp)
set.seed(123)
x1 <- gl(4,10)
x2 <- gl(5,2,40)
y <- rnorm(40)

fm1 <- lm(y ~ x1 + x2)

for(var in c('x1', 'x2'))
{
mc1 <- glht(fm1, linfct=mcp(var='Tukey'))
print(summary(mc1))
}

When I run, I get the following error:

Error en mcp2matrix(model, linfct = linfct) : 
    Variable(s) ‘var’ have been specified in ‘linfct’ but cannot be found in ‘model’! 

That is, it is not possible to use a character to specify an attribute of the mcp function. Anyone knows a solution?

Upvotes: 4

Views: 2221

Answers (3)

Josh O&#39;Brien
Josh O&#39;Brien

Reputation: 162321

(Update: Make sure to see Hadley's answer for the better way of doing this, without resorting to string-pasting. My answer will still be useful for explaining why that is harder-than-usual in this case.)

The peculiarities of mcp() require you to use the relatively brute force approach of pasting together the expression you'd like to evaluate and then passing it through eval(parse()).

The tricky bit is that mcp() interprets its first argument in a nonstandard way. Within mcp(), x1 = 'Tukey' does not (as it normally would) mean "assign a value of 'Tukey' to the argument x1". Instead, the whole thing is interpreted as a symbolic description of the intended contrasts. (In this, it is much like more familiar formula objects such as the y ~ x1 + x2 in your lm() call).

for(var in c('x1', 'x2')) {
    # Construct a character string with the expression you'd type at the command 
    # line. For example : "mcp(x1 = 'Tukey')"
    exprString <- paste("mcp(", var, "='Tukey')")
    # eval(parse()) it to get an 'mcp' object.
    LINFCT <- eval(parse(text = exprString))
    mc1 <- glht(fm1, linfct = LINFCT)
    print(summary(mc1))
}

Upvotes: 3

hadley
hadley

Reputation: 103898

It's generally better to avoid working with strings representing code wherever possible - it prevents errors that are hard to debug, and aesthetically is much more elegant. This problem turns out to be fairly easy to solve if you use do.call and the setNames function:

var <- "x1"
cmp <- do.call(mcp, setNames(list("Tukey"), var))
glht(fm1, linfct = cmp)

You can't use substitute here because it does not allow you modify the names of function parameters. I have some intuition for why this is reasonable, but not enough to explain it :/

If you're a package author, it's a good idea to provide an alternative version of functions that use unusual syntax so they can be accessed programmatically without jumping through hoops.

Upvotes: 14

aatrujillob
aatrujillob

Reputation: 4816

Have you tried: eval(parse(text='variable')) or assign ?

Upvotes: 2

Related Questions