0

I need to apply a series of operations to different variables in a data.frame. To make my code shorter and easier to read, I am trying to functionalize these operations. However, I am having trouble using a variable (in the function) to refer to a variable in the data.frame. Here is a toy example:

set.seed(1)
dframe <- data.frame(ID=rep(1:4, each=3),
                     cond=rep(c("a", "b"), each=6), 
                     x=rnorm(12))
dframe
   ID cond          x
1   1    a -0.6264538
2   1    a  0.1836433
3   1    a -0.8356286
4   2    a  1.5952808
5   2    a  0.3295078
6   2    a -0.8204684
7   3    b  0.4874291
8   3    b  0.7383247
9   3    b  0.5757814
10  4    b -0.3053884
11  4    b  1.5117812
12  4    b  0.3898432

get.means <- function(var, dframe){
  dframe <- dframe[order(dframe$ID),]
  mat    <- aggregate(var~ID, data=dframe, FUN=mean)
  mat 
}
get.means(var=x, dframe=dframe)
Error in eval(expr, envir, enclos) : object 'x' not found

I can get it to work by using get.means(var=dframe$x, dframe=dframe), but this causes other problems down the road. Here are some other things I've tried that haven't worked:

get.means2 <- function(var, dframe){
  dframe <- dframe[order(dframe$ID),]
  mat    <- aggregate(get(var)~ID, data=dframe, FUN=mean)
  mat 
}
get.means2(var=x, dframe=dframe)
Error in get(var) : object 'x' not found

get.means3 <- function(var, dframe){
  dframe <- dframe[order(dframe$ID),]
  mat    <- aggregate(eval(var)~ID, data=dframe, FUN=mean)
  mat 
}
get.means3(var=x, dframe=dframe)
Error in eval(var) : object 'x' not found

get.means4 <- function(var, dframe){
  dframe <- dframe[order(dframe$ID),]
  mat    <- aggregate(dframe[,var]~ID, data=dframe, FUN=mean)
  mat 
}
get.means4(var=x, dframe=dframe)
Error in `[.data.frame`(dframe, , var) : object 'x' not found

2 Answers 2

2

x is defined only in the scope of dframe. You can try this:

get.means <- function(var, dframe){
    aggregate(as.formula(paste(var, '~ ID')), data=dframe, FUN=mean)
}

get.means(var='x', dframe=dframe)

You can also call get.means4 using column name:

get.means4(var='x', dframe=dframe)

or even get.means3 in this way (although I wouldn't recommend that):

get.means3(var=dframe$x, dframe=dframe)

In the last case you safely remove eval and leave:

aggregate(var~ID, data=dframe, FUN=mean)
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your help. Scope is killing me. I just went through the manual again, & I must have missed something. #3 works w/ my toy example, but breaks down further on w/ the real (ie more complicated) code. The workaround (1) version seems best, but is that how the developers think people should be doing this? It seems awkward.
Generally speaking if you use $ syntax it is better to avoid data argument. Although some functions will work correctly with call like this: foobar(df$foo ~ bar, data=df) it can give you unexpected results. In this case use foobar(df$foo ~ df$bar) otherwise df$bar can be interpreted as df$df$bar. Personally I think that using string names is the best solution and should work fine both with dataframes and matrices.
1

You can consider using data.table instead of data.frame. It allows for smaller and perhaps more manageable code.

require(data.table)
DT <- data.table(ID = rep(1:4, each = 3), cond = rep(c("a", "b"), each = 6), x = rnorm(12))
DT
##     ID cond           x
##  1:  1    a -0.97191681
##  2:  1    a  1.28097125
##  3:  1    a -0.47717701
##  4:  2    a -0.29965951
##  5:  2    a  1.06189839
##  6:  2    a  1.09880286
##  7:  3    b -1.46961507
##  8:  3    b  1.12854103
##  9:  3    b -0.09556682
## 10:  4    b  0.45225307
## 11:  4    b -0.64993127
## 12:  4    b -0.59079915

DT[, mean(x), by = ID]
##    ID          V1
## 1:  1 -0.28531921
## 2:  2  0.01713826
## 3:  3  0.23810745
## 4:  4 -0.16118247

1 Comment

Thanks. I don't really know data.table & given that this is just a toy example of one small part of more complicated code that I need to fit the solution into, I should really stay with w/ base R. I do intend to try to learn it, though--the vignettes look helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.