我正在尝试根据顺序组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
: | : | :
然而,由于我的数据会被多次复制,这似乎很乏味且效率低下。
有没有人知道以更有效的方式处理累积组中的数据?
答案 0 :(得分:2)
以下是三个示例,一个包含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
答案 1 :(得分:1)
这里应该使用的一种方法是按组ID拆分data.frame,然后使用累积组运行for
循环(或lapply
)。下面是使用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,...在您的示例中。
答案 2 :(得分:1)
以下是几种方法:
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 (2)可以使用magrittr这样重写:
library(magrittr)
DF %>%
split(.$group) %>%
Reduce(f = rbind, acc = TRUE) %>%
lapply(transform, group = tail(group, 1)) %>%
do.call(what = "rbind")
给出与(2)中相同的结果。