2012-04-19 70 views
12

这最好用一个例子由两个或多个因子变量统计汇总?

str(mtcars) 
mtcars$gear <- factor(mtcars$gear, labels=c("three","four","five")) 
mtcars$cyl <- factor(mtcars$cyl, labels=c("four","six","eight")) 
mtcars$am <- factor(mtcars$am, labels=c("manual","auto") 
str(mtcars) 
tapply(mtcars$mpg, mtcars$gear, sum) 

这给了我每齿轮求和MPG示出。但是,我想要一张3x3的桌子,上面有齿轮,下面是圆柱形,9个单元格是二元的,我怎么能“聪明地”得到这个结果。

我可以去。

tapply(mtcars$mpg[mtcars$cyl=="four"], mtcars$gear[mtcars$cyl=="four"], sum) 
tapply(mtcars$mpg[mtcars$cyl=="six"], mtcars$gear[mtcars$cyl=="six"], sum) 
tapply(mtcars$mpg[mtcars$cyl=="eight"], mtcars$gear[mtcars$cyl=="eight"], sum) 

这看起来很麻烦。

那么我将如何在混合中引入第三个变量?

这是在我想的空间。 Summary statistics using ddply

更新这让我在那里,但它不是漂亮。

aggregate(mpg ~ am+cyl+gear, mtcars,sum) 

干杯

回答

32

这个怎么样,还在使用tapply()?它比你知道的更多才多艺!

with(mtcars, tapply(mpg, list(cyl, gear), sum)) 
#  three four five 
# four 21.5 215.4 56.4 
# six 39.5 79.0 19.7 
# eight 180.6 NA 30.8 

或者,如果你想打印输出更解释了一下:

with(mtcars, tapply(mpg, list("Cylinder#"=cyl, "Gear#"=gear), sum)) 

如果要使用两个以上的交叉分类变量,这个想法也正是一样。该结果将在3或更多的维数组返回:

A <- with(mtcars, tapply(mpg, list(cyl, gear, carb), sum)) 

dim(A) 
# [1] 3 3 6 
lapply(1:6, function(i) A[,,i]) # To convert results to a list of matrices 

# But eventually, the curse of dimensionality will begin to kick in... 
table(is.na(A)) 
# FALSE TRUE 
# 12 42 
+0

这似乎是一个明显的答案,考虑到一个因素的挑战是出发点。 'ftable'也可能是有趣的。 – 2012-04-19 02:15:25

3

我喜欢Josh的这个答案,但reshape2也可以提供这些类型的问题一个很好的框架:

library(reshape2) 

#use subset to only grab the variables of interest... 
mtcars.m <- melt(subset(mtcars, select = c("mpg", "gear", "cyl")), measure.vars="mpg") 
#cast into appropriate format 
dcast(mtcars.m, cyl ~ gear, fun.aggregate=sum, value.var="value") 

    cyl three four five 
1 four 21.5 215.4 56.4 
2 six 39.5 79.0 19.7 
3 eight 180.6 0.0 30.8 
+0

我编辑引用''mpg“'传递给'measure.vars',b/c代码不适合我。这对你看起来是否合适?另外,有没有简单的方法可以让它在底行中间返回“NA”而不是'0'? – 2012-04-19 02:15:17

+0

@ JoshO'Brien - 非常奇怪,我不知道为什么以前工作没有报价周围英寸...谢谢你。另外,'dcast'的'fill'参数应该允许NA,但是我收到了一个奇怪的错误...虽然设置了'fill = Inf'或任何其他数值。这不是我期望的功能......将进一步挖掘 – Chase 2012-04-19 03:05:08

5

我想这个问题上的答案是很棒的选择,但我想分享一个基于dplyr包的额外选项(这对我来说是因为我现在正在教授一门课,我们使用dplyr进行数据操作,所以我想避免介绍学生专门的基地R功能,如tapplyaggregate)。

您可以使用group_by函数对任意多个变量进行分组,然后使用summarize汇总这些组中的信息。我认为这种代码是更易读的R新人比aggregate式为基础的接口,得到相同的结果:

library(dplyr) 
mtcars %>% 
    group_by(am, cyl, gear) %>% 
    summarize(mpg=sum(mpg)) 
#  am cyl gear mpg 
# (dbl) (dbl) (dbl) (dbl) 
# 1  0  4  3 21.5 
# 2  0  4  4 47.2 
# 3  0  6  3 39.5 
# 4  0  6  4 37.0 
# 5  0  8  3 180.6 
# 6  1  4  4 168.2 
# 7  1  4  5 56.4 
# 8  1  6  4 42.0 
# 9  1  6  5 19.7 
# 10  1  8  5 30.8 

随着两个变量,可以用该行一个变量,而另一个上的列总结通过从tidyr包添加一个呼叫到spread功能:

library(dplyr) 
library(tidyr) 
mtcars %>% 
    group_by(cyl, gear) %>% 
    summarize(mpg=sum(mpg)) %>% 
    spread(gear, mpg) 
#  cyl  3  4  5 
# (dbl) (dbl) (dbl) (dbl) 
# 1  4 21.5 215.4 56.4 
# 2  6 39.5 79.0 19.7 
# 3  8 180.6 NA 30.8 
0

答案包含使用tapply和聚合函数相同的输出。

我想向Josh O'Brien的答案中添加一些信息。用户可以根据输出使用聚合函数或tapply。为了在tapply中使用多个因子变量,可以使用Josh所示的方法。

加载数据集

data("mtcars") 

使用tapply

with(mtcars, tapply(mpg, list("Cylinder#"=cyl, "Gear#"=gear), sum)) 

的上面的代码的输出是

 Gear# 
Cylinder#  3  4 5 
    4  21.5 215.4 56.4 
    6  39.5 79.0 19.7 
    8 180.6 NA 30.8 

使用聚集函数

with(mtcars, aggregate(mpg, list(Cylinder = cyl, Gear = gear), sum)) 
聚合函数

Cylinder Gear x 
1  4 3 21.5 
2  6 3 39.5 
3  8 3 180.6 
4  4 4 215.4 
5  6 4 79.0 
6  4 5 56.4 
7  6 5 19.7 
8  8 5 30.8 

输出现在,如果用户希望相同的输出聚合函数,但使用tapply。 tapply功能

as.data.frame(as.table(with(mtcars, tapply(mpg, list("Cylinder#"=cyl, "Gear#"=gear), 
sum)))) 

输出

Cylinder. Gear. Freq 
1   4  3 21.5 
2   6  3 39.5 
3   8  3 180.6 
4   4  4 215.4 
5   6  4 79.0 
6   8  4 NA 
7   4  5 56.4 
8   6  5 19.7 
9   8  5 30.8 

NA的可以保持或按业务要求删除。