15

最好用一个例子来说明这一点

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)

这似乎很麻烦。

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

这有点在我正在考虑的空间中。 使用 ddply 汇总统计信息

更新这让我到了那里,但它并不漂亮。

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

干杯

4

4 回答 4

38

这个怎么样,还在用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 
于 2012-04-19T01:48:07.463 回答
9

我认为这个问题的答案已经是很棒的选择,但我想分享一个基于dplyr包的附加选项(这对我来说是因为我现在正在教一门我们dplyr用于数据操作的课程,所以我想避免向学生介绍专门的基本 R 函数,如tapplyor aggregate)。

您可以使用该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

spread使用两个变量,您可以通过从包中添加对函数的调用,在行上使用一个变量,在列上使用另一个变量进行汇总tidyr

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
于 2016-02-04T23:10:56.273 回答
4

我喜欢 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
于 2012-04-19T01:53:31.983 回答
3

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

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

加载数据集

data("mtcars")

使用轻拍

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。

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

tapply 函数的输出

   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。

于 2018-02-18T05:29:36.020 回答