簡體   English   中英

使用R和dplyr執行累積組操作

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM