Aggregate functions not working on S4 data.frames

Viewed 28

I have a S4 object which inherits from a data.frame, but when I try to use aggregate on it, it does not work unless I explicitly pass the data.frame part of the object. Let me ilustrate it with an example:

setOldClass("data.frame")

setClass("DataFrame",
         slots = c(
           data1 = "data.frame",
           data2 = "data.frame"
         ),
         contains = "data.frame")

df <- data.frame("a" = 1:6,
                 "b" = 2:7,
                 "c" = rep(c(1,2), each = 3))

df <- new("DataFrame", df)

Now if I execute aggregate(a ~ c, FUN = mean, data = df) it produces the following error:

Error in terms.formula(formula, data = data) : 'data' argument is of the wrong type

Why is that? df inherits from data.frame, so that should not be a problem. I know that executing aggregate(a ~ c, FUN = mean, data = S3Part(df)) works as I want, but I would like to know why calling the data directly from df don't.

1 Answers

S3 only chooses a method based on the first argument, which is x in the case of aggregate. So, the data argument is not used in choosing a method at all. Instead, because the first argument is a formula, aggregate.formula is called.

If you want to use the data.frame method, then you can use the aggregate.data.frame method directly, which has arguments (x,by,FUN,...) (see the help page on aggregate for more details).

It would be hard to write a S4 generic version of aggregate, because none of the arguments apart from x are shared between the different methods. Therefore the signature would have to be x only, which would basically replicate the S3 behaviour.

Another option is to write a method for as.data.frame for your new class (presumably returning the @.Data slot). This is called by terms.formula and so should solve your problem.

Related