rnso
rnso

Reputation: 24545

why this simple ave function is not working

I am using following code and data:

> d <- data.frame(year = rep(2000:2002, each = 3), count = round(runif(9, 0, 20)))
> d
  year count
1 2000     1
2 2000     4
3 2000     4
4 2001    14
5 2001     8
6 2001    15
7 2002    10
8 2002    14
9 2002    20
> 
> with(d, ave(count, year, sum))
Error in unique.default(x) : unique() applies only to vectors

I tried:

> with(d, ave(count, list(year), sum))
Error in unique.default(x) : unique() applies only to vectors
> with(d, ave(count, list('year'), sum))
Error in unique.default(x) : unique() applies only to vectors
> 
> with(d, ave(count, 'year', sum))
Error in unique.default(x) : unique() applies only to vectors

> with(d, ave('count', 'year', sum))
Error in unique.default(x) : unique() applies only to vectors
> ave(d$count, d$year, sum)
Error in unique.default(x) : unique() applies only to vectors

> ave(d$count, factor(d$year), sum)
Error in unique.default(x) : unique() applies only to vectors

> ave(d$count, unique(d$year), sum)
Error in unique.default(x) : unique() applies only to vectors

> ave(d$count, factor(unique(d$year)), sum)
Error in unique.default(x) : unique() applies only to vectors
> ave(d$count, as.factor(unique(d$year)), sum)
Error in unique.default(x) : unique() applies only to vectors

Following works:

> unique(d$count)
[1]  1  4 14  8 15 10 20
> unique(d$year)
[1] 2000 2001 2002

tapply, aggregate and by work:

> with(d, tapply(count, year, mean))
    2000     2001     2002 
 3.00000 12.33333 14.66667 

> with(d, aggregate(count, list(year), mean))
  Group.1        x
1    2000  3.00000
2    2001 12.33333
3    2002 14.66667

> with(d, by(count, year, mean))
year: 2000
[1] 3
------------------------------------------------------------------------------------------------- 
year: 2001
[1] 12.33333
------------------------------------------------------------------------------------------------- 
year: 2002
[1] 14.66667

Why there is error 'unique() applies only to vectors' and how can I use ave function here?

Upvotes: 4

Views: 1920

Answers (1)

joran
joran

Reputation: 173577

This is a little subtle and I think the best documentation of this is actually in the R language definition on argument matching:

The first thing that occurs in a function evaluation is the matching of formal to the actual or supplied arguments. This is done by a three-pass process:

  1. Exact matching on tags. For each named supplied argument the list of formal arguments is searched for an item whose name matches exactly. It is an error to have the same formal argument match several actuals or vice versa.

  2. Partial matching on tags. Each remaining named supplied argument is compared to the remaining formal arguments using partial matching. If the name of the supplied argument matches exactly with the first part of a formal argument then the two arguments are considered to be matched. It is an error to have multiple partial matches. Notice that if f <- function(fumble, fooey) fbody, then f(f = 1, fo = 2) is illegal, even though the 2nd actual argument only matches fooey. f(f = 1, fooey = 2) is legal though since the second argument matches exactly and is removed from consideration for partial matching. If the formal arguments contain ‘...’ then partial matching is only applied to arguments that precede it.

  3. Positional matching. Any unmatched formal arguments are bound to unnamed supplied arguments, in order. If there is a ‘...’ argument, it will take up the remaining arguments, tagged or not.

So this is a result of the special nature of the argument. It is, in a sense, "greedy", unless you are more explicit and used named arguments. The reason this doesn't pop up elsewhere is because is usually the last (or nearly last) argument, so you don't often end up with this sort of confusing behavior when using positional matching.

Upvotes: 6

Related Questions