【问题标题】:dplyr collapse 'tail' rows into larger groupsdplyr 将“尾”行折叠成更大的组
【发布时间】:2018-11-10 15:16:45
【问题描述】:
library(tidyverse)
df <- tibble(a = as.factor(1:20), b = c(50, 20, 13, rep(2, 10), rep(1, 7)))

如何让 dplyr 查看此数据框 df 并将所有这些出现的 2 折叠到一个求和组中,并将所有出现的 1 折叠到一个求和组中?并且还保留数据框的其余部分。

转动这个:

# A tibble: 20 x 2
   a         b
   <fct> <dbl>
 1 1        50
 2 2        20
 3 3        13
 4 4         2
 5 5         2
 6 6         2
 7 7         2
 8 8         2
 9 9         2
10 10        2
11 11        2
12 12        2
13 13        2
14 14        1
15 15        1
16 16        1
17 17        1
18 18        1
19 19        1
20 20        1

进入这个:

# A tibble: 5 x 2
   a         b
   <fct> <dbl>
 1 1        50
 2 2        20
 3 3        13
 4 grp2     20
 5 grp1      7

[编辑] - 我修复了示例数据。对此感到抱歉。

【问题讨论】:

  • 澄清一下,grp2grp1 只是字符还是它们包含对应于 21a 元素?
  • 感谢您更正我的示例数据。我最初忘记这样做了。感谢您的回复,尽管我并不需要 grp 元素来包含 a 的元素。但反应是有启发性和优秀的。
  • @Julius Vainora 你的答案好像消失了?你介意张贴吗?这很好,我没有机会将它复制粘贴到我的参考文件中。而且我确信 StackOverflow 的其余部分会发现它很有用。不管怎样,谢谢。
  • 当然,但是因为它回答了一个不同的问题,所以我就把它留在这里:df %&gt;% group_by(b) %&gt;% summarise(a = list(a)) %&gt;% mutate(b = b * lengths(a))

标签: r dplyr


【解决方案1】:

我们按制造的sortkey 分组以保持排序顺序。我们使用了 b 在输入中按降序排列的事实,但如果您的实际数据不是这种情况,则将 sortkey = -b 替换为更通用的 sortkey = data.table::rleid(b) 或更长的 sortkey = cumsum(coalesce(b != lag(b), FALSE))

我们还将b 转换为组名,从而提供新的a。目前尚不清楚哪些组将转换为 grp... 形式。硬编码 1 和 2?有超过一排的任何组吗?最后的组有多行?无论如何,一旦澄清,更改if_else 中的条件就很容易了。

最后进行求和,然后去掉sortkey

df %>% 
  group_by(sortkey = -b, a = paste0(if_else(b %in% 1:2, "grp", ""), b)) %>%
  summarize(b = sum(b)) %>%
  ungroup %>%
  select(-sortkey)

给予:

# A tibble: 5 x 2
  a         b
  <chr> <int>
1 50       50
2 20       20
3 13       13
4 grp2     20
5 grp1      7

【讨论】:

    【解决方案2】:

    这是一种方法。我已将 a 从因子转换为字符,以使事情变得更容易。如果需要,您可以将其转换回因子。你的测试数据也有点错误。

    df <- tibble(a = as.character(1:20), b = c(50, 20, 13, rep(2, 10), rep(1, 7)))
    
    df %>% 
      mutate(
        a = case_when(
          b == 1 ~ "grp1",
          b == 2 ~ "grp2",
          TRUE ~ a
        )
      ) %>% 
      group_by(a) %>% 
      summarise(b = sum(b))
    
    # A tibble: 5 x 2
      a         b
      <chr> <dbl>
    1 1        50
    2 2        20
    3 3        13
    4 grp1      7
    5 grp2     20
    

    【讨论】:

      【解决方案3】:

      这种方法可以为您提供所需的组名称,并且您无需事先考虑需要多少这样的案例(例如,它将创建 grp3grp4、...取决于b 中的数字)。

      library(dplyr)
      
      df %>%
        mutate(
          grp = as.numeric(lag(df$b) != df$b),
          grp = cumsum(ifelse(is.na(grp), 0, grp))
        ) %>% group_by(grp) %>%
        mutate(
          a = ifelse(n() > 1, paste0("grp", b), a),
          b = sum(b)
        ) %>% ungroup() %>% distinct(a, b)
      

      输出:

        a         b
        <chr> <dbl>
      1 1        50
      2 2        20
      3 3        13
      4 grp2     20
      5 grp1      7
      

      请注意,代码也可以压缩,但在我看来这会导致缺乏可读性:

      df %>%
        group_by(grp = cumsum(ifelse(is.na(as.numeric(lag(df$b) != df$b)), 0, as.numeric(lag(df$b) != df$b)))) %>%
        mutate(
          a = ifelse(n() > 1, paste0("grp", b), a),
          b = sum(b)
        ) %>% ungroup() %>% distinct(a, b)
      

      【讨论】:

        猜你喜欢
        • 2018-04-10
        • 1970-01-01
        • 2013-12-07
        • 1970-01-01
        • 2021-11-25
        • 2016-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多