操作超过两个因素的水平

时间:2013-03-02 19:07:12

标签: r vectorization

我有一个看起来像这样的数据集,有很多类,每个类都有很多(5-10)个子类,每个类都有一个与之关联的值:

> data.frame(class=rep(letters[1:4], each=4), subclass=c(1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8), value=1:16)
   class subclass value
1      a        1     1
2      a        1     2
3      a        2     3
4      a        2     4
5      b        3     5
6      b        3     6
7      b        4     7
8      b        4     8
9      c        5     9
10     c        5    10
11     c        6    11
12     c        6    12
13     d        7    13
14     d        7    14
15     d        8    15
16     d        8    16

我想首先对每个类/子类的值求和,然后在所有子类中取每个类的中值。

即,中间步骤将对每个类的每个子类的值求和,并且看起来像这样(请注意,我不需要保留此中间步骤中的数据):

> data.frame(class=rep(letters[1:4], each=2), subclass=1:8, sum=c(3,7,11,15,19,23,27,31))
  class subclass   sum
1     a        1     3
2     a        2     7
3     b        3    11
4     b        4    15
5     c        5    19
6     c        6    23
7     d        7    27
8     d        8    31

第二步将采用所有子类中每个类的中位数,如下所示:

> data.frame(class=letters[1:4], median=c(median(c(3,7)), median(c(11,15)), median(c(19,23)), median(c(27,31))))
  class median
1     a      5
2     b     13
3     c     21
4     d     29

这是我需要保留的唯一数据。请注意,$ class和$ subclass都是因子变量,value始终是一个不缺少的正整数。每个类都有不同数量的子类。

我确信我可以通过一些讨厌的for循环来做到这一点,但我希望有一种更好的方法,它可以被矢量化并且更容易维护。

3 个答案:

答案 0 :(得分:3)

以下是使用aggregate

的另一个示例
temp <- aggregate(df$value,list(class=df$class,subclass=df$subclass),sum)

aggregate(temp$x,list(class=temp$class),median)

输出:

      class  x
  1     a    5
  2     b   13
  3     c   21
  4     d   29

或者如果你喜欢单线解决方案,你可以这样做:

aggregate(value ~ class, median, data=aggregate(value ~ ., sum, data=df))

答案 1 :(得分:2)

您可以尝试第一步:

df_sums <- aggregate(value ~ class + subclass, sum, data=df)

然后:

aggregate(value ~ class, median, data=df_sums)

答案 2 :(得分:2)

以下是另外两种选择。

第一个在ave语句中使用within,我们会在添加汇总数据后逐步减少源data.frame。由于这将导致许多重复行,我们可以安全地使用unique作为获得所需输出的最后一步。

unique(within(mydf, {
  Sum <- ave(value, class, subclass, FUN = sum)
  rm(subclass, value)
  Median <- ave(Sum, class, FUN = median)
  rm(Sum)
}))
#    class Median
# 1      a      5
# 5      b     13
# 9      c     21
# 13     d     29

第二个选项是使用“data.table”包并“复合”您的语句,如下所示。 V1data.table如果用户未指定名称将自动创建的名称。

library(data.table)
DT <- data.table(mydf)
DT[, sum(value), by = c("class", "subclass")][, median(V1), by = "class"]
#    class V1
# 1:     a  5
# 2:     b 13
# 3:     c 21
# 4:     d 29