我使用ddply但我不认为自己是专家。我有一个数据框(df),其分组变量“Group”具有值“A”,“B”和“C”以及要汇总的变量,“Var”具有数值。如果我使用
ddply(df, .(Group), summarize, mysum=sum(Var))
然后我得到每个A,B和C的总和,这是正确的。但我想要做的是将每个Group变量分组相加,因为它们在数据框中排列。例如,如果数据框具有
Group Var
A 1.3
A 1.2
A 0.4
B 0.3
B 1.3
C 1.5
C 1.7
C 1.9
A 2.1
A 2.4
B 6.7
期望的结果
A 2.9
B 1.6
C 5.1
A 4.5
B 6.7
因此,所需的输出对每个Group变量分组执行数学函数,而不是对各个Group变量的所有实例执行数学函数。这可以在ddply中完成吗?
数据
dat <- structure(list(Group = c("A", "A", "A", "B", "B", "C", "C", "C", "A", "A", "B"),
Var = c(1.3, 1.2, 0.4, 0.3, 1.3, 1.5, 1.7, 1.9, 2.1, 2.4, 6.7)),
.Names = c("Group", "Var"), class = "data.frame", row.names = c(NA, -11L))
答案 0 :(得分:12)
以下是使用rleid()
v1.9.6中最近实现的data.table
函数执行此操作的一种方法。见#686。
这会根据需要生成分组ID:
require(data.table) ## v1.9.6+
DT = as.data.table(dat)
rleid(DT$Group)
# [1] 1 1 1 2 2 3 3 3 4 4 5
我们可以直接使用它来汇总如下:
DT[, .(sum=sum(Var)), by=.(Group, rleid(Group))]
# Group rleid sum
# 1: A 1 2.9
# 2: B 2 1.6
# 3: C 3 5.1
# 4: A 4 4.5
# 5: B 5 6.7
HTH
答案 1 :(得分:3)
这是等效的基础
dat <- structure(list(Group = c("A", "A", "A", "B", "B", "C", "C", "C", "A", "A", "B"),
Var = c(1.3, 1.2, 0.4, 0.3, 1.3, 1.5, 1.7, 1.9, 2.1, 2.4, 6.7)),
.Names = c("Group", "Var"), class = "data.frame", row.names = c(NA, -11L))
with(dat, cumsum(c(1L, Group[-length(Group)] != Group[-1])))
# [1] 1 1 1 2 2 3 3 3 4 4 5
作为一项功能
rleid <- function(x) cumsum(c(1L, x[-length(x)] != x[-1]))
(dat <- within(dat, id <- rleid(Group)))
# Group Var id
# 1 A 1.3 1
# 2 A 1.2 1
# 3 A 0.4 1
# 4 B 0.3 2
# 5 B 1.3 2
# 6 C 1.5 3
# 7 C 1.7 3
# 8 C 1.9 3
# 9 A 2.1 4
# 10 A 2.4 4
# 11 B 6.7 5
aggregate
基于新变量
aggregate(Var ~ ., dat, sum)
# Group id Var
# 1 A 1 2.9
# 2 B 2 1.6
# 3 C 3 5.1
# 4 A 4 4.5
# 5 B 5 6.7
或者,你可以实际使用rle
,但它需要一个原子向量,所以如果你使用一个因子,那么你需要一个额外的步骤(即as.vector
)
rleid2 <- function(x) {
x <- as.vector(x)
rep(seq_along(rle(x)$values), rle(x)$lengths)
}
rleid2(dat$Group)
# [1] 1 1 1 2 2 3 3 3 4 4 5
一些基准:
set.seed(1)
dat2 <- dat[sample(1:nrow(dat), 1e6, TRUE), ]
identical(data.table::rleid(dat2$Group),
rleid(dat2$Group))
# [1] TRUE
library('microbenchmark')
microbenchmark(data.table::rleid(dat2$Group),
rleid(dat2$Group),
rleid2(dat2$Group), unit = 'relative')
# Unit: relative
# expr min lq mean median uq max neval cld
# data.table::rleid(dat2$Group) 1.032777 1.015395 1.005023 1.020923 1.000612 0.8935531 100 a
# rleid(dat2$Group) 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000 100 a
# rleid2(dat2$Group) 35.747987 35.351585 28.600030 34.058992 33.147546 9.8786083 100 b