[英]Perform a cumulative group operations with R and dplyr
我正在尝试根据顺序的组ID处理数据。 有J组,我想为组i < j=1..J
运行数据处理功能
最琐碎的情况是每一行都是它自己的组,然后您计算累积总和。 但是,我在每个组中都有多行,并且处理比求和更为复杂。
这是我的数据格式的最小示例:
row | group | value
----|-------|------
1 | 1 | 2065
2 | 1 | 2075
3 | 2 | 18008
4 | 2 | 17655
: | : | :
N-1 | J-1 | 2345
N | J | 5432
我想到的一种解决方案是复制数据,将其堆叠并在每个数据中重新分配组,以使组i<j
到j。 这将导致非常长的数据帧,例如:
row | group | value
----|-------|------
1 | 1 | 2065
2 | 1 | 2075
3 | 2 | 2065
4 | 2 | 2075
5 | 2 | 18008
6 | 2 | 17655
: | : | :
但是,这似乎乏味且效率低下,因为我的数据将被多次复制。
有谁知道一种更有效的方式来处理累积组中的数据?
这是三个示例,其中一个具有aggregate
,一个具有data.table
,最后一个具有dplyr
。
首先创建数据框
library(data.table)
library(dplyr)
group <- c(1,1,2,2,3)
value <- c(2065, 2075, 18008, 17655, 561)
使用data.table可以使用此功能
dat <- data.table(group, value)
recap <- dat[, list(somma = sum(value)), by = group]
包含包装统计信息中的汇总
dat <- data.frame(group, value)
aggregate(dat$value, by=list(Group=dat$group), FUN=sum)
然后与dplyr
dat %>%
group_by(group) %>%
summarise(result = sum(value))
这些会给你
group | result
---------------
1 | 4140
2 | 35663
3 | 561
这里应采用的一种方法是按组ID拆分data.frame,然后使用累积组运行for
循环(或lapply
)。 下面是使用for
循环的示例for
因为我认为它的实现会更加简单。
# split data.frame by group ID
myList <- split(df, df$group)
# initialize empty output list
myOutputList <- list()
# loop through group IDs, including the next one
for(i in seq_along(unique(df$group))) {
# create temporary df for analysis
myTempDf <- do.call(rbind, myList[seq_len(i)])
## perform analysis on myTempDf here ##
# save results
myOutputList[[i]] <- list(<list of analysis ouput>)
}
输出将是一个嵌套列表。 我建议命名嵌套列表中的每个项目,以使其易于访问,例如myOutputList[[i]][["regression.1"]]
。
请注意,这是假设在原始data.frame中正确地对组进行了正确排序,并且组id是计数数字1,2,3,4,...,在您的示例中。
以下是几种方法:
1)sqldf这是从注释转移过来的。 我最初将其放在此处是因为它不是dplyr解决方案,但似乎您正在考虑其他解决方案。 在指定的条件下,我们将唯一组值与数据框结合在一起。 只需一条SQL语句即可:
DF <- data.frame(group = c(1, 1, 2, 2), value = 1:4) # test data
library(sqldf)
outDF <- sqldf("select a.[group], b.value
from
(select distinct [group] from DF) a
join DF b on a.[group] >= b.[group]")
赠送:
> outDF
group value
1 1 1
2 1 2
3 2 1
4 2 2
5 2 3
6 2 4
现在我们可以处理组了。 根据看似fun
事情,可以选择其中之一:
aggregate(value ~ group, outDF, fun)
tapply(outDF$value, outDF$group, fun)
by(outDF, outDF$group, fun)
ave(outDF$value, outDF$group, FUN = fun)
例如,如果运算是求和运算,而不是单独的聚合,则可以将其与上述运算结合起来。
sqldf("select a.[group], sum(b.value) cumsum
from (select distinct [group] from DF) a join DF b on a.[group] >= b.[group]
group by a.[group]")
赠送:
group cumsum
1 1 3
2 2 10
注意
group
是一个SQL关键字,这就是我们使用[group]
对其进行转义的原因
我们假设需要累积在数值上等于或小于当前组的组,这在问题示例中就是这种情况。 如果需要不同的顺序,我们可以创建另一个分组变量,其顺序反映出所需的顺序。
2)base这不使用任何包。 我们假设希望对当前组和在拆分中出现在其之前的组进行累加,以便按数字顺序累加组。 但是,如果我们希望使用不同的顺序,则可以将group
划分为一个因子,然后根据需要对级别进行排序,因为split
输出将按照分组因子的级别进行排序。
L <- Reduce(rbind, split(DF, DF$group), acc = TRUE)
do.call("rbind", lapply(L, transform, group = tail(group, 1)))
赠送:
group value
1 1 1
2 1 2
3 2 1
4 2 2
5 2 3
6 2 4
3)可以使用magrittr重写magrittr (2),如下所示:
library(magrittr)
DF %>%
split(.$group) %>%
Reduce(f = rbind, acc = TRUE) %>%
lapply(transform, group = tail(group, 1)) %>%
do.call(what = "rbind")
得到与(2)中相同的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.