Reputation: 24545
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
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:
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.
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.
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