2012-04-19 82 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的可以保持或按業務要求刪除。