我有一个看起来像这样的数据集,有很多类,每个类都有很多(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循环来做到这一点,但我希望有一种更好的方法,它可以被矢量化并且更容易维护。
答案 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”包并“复合”您的语句,如下所示。 V1
是data.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