1

I'm looking to save an expression like this:

expression <- c(beta_a*a + beta_b*b + beta_d*d) 

And I want to return this expression:

expression
> beta_a*a + beta_b*b + beta_d*d

But when I try to run the first line, it just says the error "Object 'beta_a' not found".

Ultimately, I'm using this for Apollo for an ordered logit model, where I have to make 60 different utility specifications. I thought it would be easier bundle the specifications into a short expression, so I can rerun the same code only changing the specification. A specification both consists of defining the beta variables and the utility functions. I was able to use this method for the beta values that have a structure like this:

betas = c(beta_a = 0, beta_b = 0, beta_d = 0)

To turn it into this:

b_specification1 <- c(beta_a = 0, beta_b = 0, beta_d = 0)
betas = b_specification1

But doing the utility function:

u_specification1 <- c(beta_a*a + beta_b*b + beta_d*d) 
utility = u_specification1

Gives the error "object 'beta_a' not found". Both b_specification1 and u_specification1 are run before betas and utility.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Victor Nielsen
  • 443
  • 2
  • 14
  • 2
    `c(…)` evaluates its arguments as usual. That is why you are getting an error about undefined objects. In fact, the `c` function call is entirely redundant here. If you want to store an unevaluated expression in R, use `quote` or `expression`. However, I don’t know ‘apollo’ so I have no idea what input it expects. — Another comment: don’t mix different assignment operators. Decide on either `=` or `<-` (it doesn’t matter which, they are effectively identical; just be consistent). – Konrad Rudolph Jan 03 '23 at 16:11
  • @KonradRudolph thank you for your solution. The use of = is entirely because that's how it is used in Apollo. Everything I do before starting the Apollo process, I do with <- . I'll try both quote and expression and see what works. – Victor Nielsen Jan 03 '23 at 16:44

1 Answers1

3

Define the expression using quote and then use eval to evaluate it.

e <- quote(a + b)
a <- 1
b <- 2
eval(e)
## [1] 3

It is also possible to define it as a character string in which case parse it and then evaluate it.

ch <- "a + b"
a <- 1
b <- 2
eval(parse(text = ch))
## [1] 3

Note that eval has an envir argument in case you need to evaluate it looking up variable names in a different environment than the current one. For example,

f <- function(s, envir = parent.frame()) {
  eval(parse(text = s), envir)
}

a <- 1
b <- 2
g <- function() {
  a <- 3
  b <- 4
  c(f("a+b"), f("a+b", .GlobalEnv))
}
g()
# [1] 7 3

To combine multiple expressions use substitute but be careful because it acts differently when run at top level at the console vs within a function. The second argument in the first example is not needed if run within a funciton.

spec1 <- quote(beta_a * a + beta_b * b)
spec2 <- quote(beta_d * d + beta_e * e)

# run at top level
substitute(spec1 + spec2, as.list(environment()))
## beta_a * a + beta_b * b + (beta_d * d + beta_e * e)

# same
substitute(spec1 + spec2, list(spec1 = spec1, spec2 = spec2))
## beta_a * a + beta_b * b + (beta_d * d + beta_e * e)


# run within a function
f <- function() {
  spec1 <- quote(beta_a * a + beta_b * b)
  spec2 <- quote(beta_d * d + beta_e * e)
  substitute(spec1 + spec2)
}

if (exists("spec1")) rm(spec1)
if (exists("spec2")) rm(spec2)

f()
## beta_a * a + beta_b * b + (beta_d * d + beta_e * e)

If using character string use paste or sprintf.

G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
  • Thank you, that works. Is there a way for me to save two different specifications after eachother? Like if I have spec1 <- quote(beta_a * a + beta_b * b) and spec2 <- quote(beta_d * d + beta_e * e) How do I then make spec3 <- quote(spec1 + spec2) return beta_a * a + beta_b * b + beta_d * d + beta_e * e? – Victor Nielsen Jan 04 '23 at 13:38
  • See added discussion at end. – G. Grothendieck Jan 04 '23 at 14:12
  • Thank you! Is it "cleaner" if I use expression instead? – Victor Nielsen Jan 04 '23 at 14:24