【问题标题】:Split grouped data set into packages that should not exceed a maximum size将分组数据集拆分为不应超过最大大小的包
【发布时间】:2022-07-22 18:01:41
【问题描述】:

为了进一步处理,我需要将我的数据分成不应超过特定行大小的块,条件是属于同一组的案例不应分成不同的块,并且组大小是不同的。

假设我有这样的表:

df <- tibble(id = c("id1", "id1", "id2", "id2", "id2", "id3", "id4", "id5", "id5", "id6"),
             group_size = c(2, 2, 3, 3, 3, 1, 1, 2, 2, 1))

   id    group_size
   <chr>      <dbl>
 1 id1            2
 2 id1            2
 3 id2            3
 4 id2            3
 5 id2            3
 6 id3            1
 7 id4            1
 8 id5            2
 9 id5            2
10 id6            1

如果块大小不应该大于3。那么表示哪个case属于哪个分割部分的变量应该是这样的:

   id    group_size  part
   <chr>      <dbl> <dbl>
 1 id1            2     1
 2 id1            2     1
 3 id2            3     2
 4 id2            3     2
 5 id2            3     2
 6 id3            1     3
 7 id4            1     3
 8 id5            2     4
 9 id5            2     4
10 id6            1     4

是否已经有可以完成这项工作的函数或包,如果没有,如何编程?

【问题讨论】:

    标签: r


    【解决方案1】:

    到目前为止,我找不到执行此任务的函数,因此我通过以下步骤解决了它:

    1. 累计计算组大小。
    2. 如果新组的累积计数超过给定的块大小,则开始一个新的块并开始新的计数。
           id    group_size cum_size  part
           <chr>      <dbl>    <dbl> <dbl>
         1 id1            2        2     1
         2 id1            2        2     1
         3 id2            3        3     2
         4 id2            3        3     2
         5 id2            3        3     2
         6 id3            1        1     3
         7 id4            1        2     3
         8 id5            2        2     4
         9 id5            2        2     4
        10 id6            1        3     4
    

    像往常一样,在 R 中有很多方法可以做到这一点。一种方法可能只是对案例进行 for 循环。

    df$part <- 1 # start with part 1
    cum_size <- df$group_size[1] # init with size of first group
    max_chunk_size <- 3
    
    for (i in 2:nrow(df)) {
      if (df$id[i] == df$id[i-1]) { # if id is the same as previus row, copy part value 
        df$part[i] <- df$part[i-1]
        print(cum_size)
      }
      else if (cum_size + df$group_size[i] <= max_chunk_size) { # else if the next group fits in the chunk, copy part value
        cum_size <- cum_size + df$group_size[i]
        df$part[i] <- df$part[i-1]
      }
      else { # start a new part, and begin group size counting a new.
        cum_size <- df$group_size[i]
        df$part[i] <- df$part[i-1] + 1
        print(cum_size)
      }
    }
    

    另一种方法遵循相同的方法,但这次我使用 purrr 包中的累积函数而不是 for 循环。在这种方法中,我还迭代了行号。但是,此解决方案非常适合 tidyverse %&gt;% 命令链。

    max_chunk_size <- 3
    
    df %>%
      mutate(
        cum_size = accumulate(
          .x = row_number(),
          .f = ~ {
            if (..2 == 1) group_size[1] # init with first value of group_size
            else if (id[..2] == id[..2-1]) ..1 # if id is same as previous id copy cum_size value
            else if (..1 + group_size[..2] <= max_chunk_size) ..1 + group_size[..2] # else if new group fits into chunk, add its group size to cum size. 
            else (group_size[..2]) # else start new cum_size counting with current group size. 
          },
          .init = 0)[-1],
        part = accumulate(
          .x = row_number(),
          .f = ~ {
            if (..2 == 1) 1 # init with part = 1
            else if (id[..2] == id[..2-1]) ..1 # if id is same as previous id, copy id.
            else if (cum_size[..2-1] + group_size[..2] <= max_chunk_size) ..1 # else if new group fits into chunk, copy group id.
            else ..1 + 1 # else begin a new group.
          },
          .init = 0
        )[-1])
    

    【讨论】:

      猜你喜欢
      • 2021-03-28
      • 1970-01-01
      • 2018-10-22
      • 1970-01-01
      • 2014-02-21
      • 2017-04-28
      • 1970-01-01
      • 2020-01-14
      • 2019-03-26
      相关资源
      最近更新 更多