[英]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.