【问题标题】:Sum all columns, by same ID按相同 ID 对所有列求和
【发布时间】:2020-10-07 15:47:36
【问题描述】:

我有 12 个具有相同变量但行号不同的数据帧。这些 data.frames 有一个列 ID,并且这些 IDs 中的 90% 在所有 data.frames 中都是相同的。

ID <- c(1:10)
wage <- c(1500:1509)
bonus <- c(1000:1009)

df1 <- data.frame(ID,wage,bonus)
ID <- c(1:11)
wage <- c(1800:1810)
bonus <- c(1200:1210)

df2 <- data.frame(ID,wage,bonus)

为了简化这个过程,data.frames 存储在一个列表中,所以你可以像这样访问:df[[1]]、df[[2]]。

我想创建一个新的数据框,我们称之为 new_df,它具有相同的变量,但按 ID 对所有列值求和(并且只有所有 data.frames 中存在的 ID)。由于每个df都有每个月的工资和奖金,我的目标是获得年薪。 如果有人可以提供帮助,我将不胜感激。

【问题讨论】:

    标签: r dplyr plyr


    【解决方案1】:

    这行得通吗:

    > ID <- c(1:10)
    > wage <- c(1500:1509)
    > bonus <- c(1000:1009)
    > 
    > df1 <- data.frame(ID,wage,bonus)
    > 
    > ID <- c(1:11)
    > wage <- c(1800:1810)
    > bonus <- c(1200:1210)
    > 
    > df2 <- data.frame(ID,wage,bonus)
    > 
    > ID <- c(1:20)
    > wage <- c(2001:2020)
    > bonus <- c(1301:1320)
    > 
    > df3 <- data.frame(ID,wage,bonus)
    > 
    > mylist <- list(df1, df2, df3)
    > 
    > my_df <- do.call(rbind, mylist)
    > 
    > my_df %>% group_by(ID) %>% filter(n() == length(mylist)) %>% summarise(tot_wage = sum(wage), tot_bonus = sum(bonus))
    `summarise()` ungrouping output (override with `.groups` argument)
    # A tibble: 10 x 3
          ID tot_wage tot_bonus
       <int>    <int>     <int>
     1     1     5301      3501
     2     2     5304      3504
     3     3     5307      3507
     4     4     5310      3510
     5     5     5313      3513
     6     6     5316      3516
     7     7     5319      3519
     8     8     5322      3522
     9     9     5325      3525
    10    10     5328      3528
    > 
    

    如果您想选择任意数量的列:

    > my_func <- function(df, summary_vars){
    +   df %>% 
    +         summarise(across({{summary_vars}}, sum))
    + }
    > my_df %>% group_by(ID) %>% filter(n() == length(mylist)) %>% my_func(wage)
    `summarise()` ungrouping output (override with `.groups` argument)
    # A tibble: 10 x 2
          ID  wage
       <int> <int>
     1     1  5301
     2     2  5304
     3     3  5307
     4     4  5310
     5     5  5313
     6     6  5316
     7     7  5319
     8     8  5322
     9     9  5325
    10    10  5328
    > my_df %>% group_by(ID) %>% filter(n() == length(mylist)) %>% my_func(bonus)
    `summarise()` ungrouping output (override with `.groups` argument)
    # A tibble: 10 x 2
          ID bonus
       <int> <int>
     1     1  3501
     2     2  3504
     3     3  3507
     4     4  3510
     5     5  3513
     6     6  3516
     7     7  3519
     8     8  3522
     9     9  3525
    10    10  3528
    > my_df %>% group_by(ID) %>% filter(n() == length(mylist)) %>% my_func(c(wage,bonus))
    `summarise()` ungrouping output (override with `.groups` argument)
    # A tibble: 10 x 3
          ID  wage bonus
       <int> <int> <int>
     1     1  5301  3501
     2     2  5304  3504
     3     3  5307  3507
     4     4  5310  3510
     5     5  5313  3513
     6     6  5316  3516
     7     7  5319  3519
     8     8  5322  3522
     9     9  5325  3525
    10    10  5328  3528
    > 
    

    【讨论】:

    • 谢谢伙计,它适用于这些变量。但我想的是更通用的东西,因为我有 30 个变量,尽管这 2 个(工资和奖金)是最重要的
    • 已编辑我的答案以添加将提供选择变量选项的代码。请检查是否有效。
    【解决方案2】:

    要放弃另一个选项,如果您有一个包含所有数据框的列表,您可以使用purrr::map_dfr 将它们全部绑定在一起。在这种情况下,被映射的函数只是返回数据帧,所以它与bind_rows 没有什么不同。但是如果你想在绑定它们之前对每个数据帧做一些事情(例如过滤器),map_dfr 是一个不错的选择。

    此外,如果您想按 ID 对 所有 列值求和,您可以使用 summarize_all

    library(tidyverse)
    
    list(df1, df2) %>%
      map_dfr(.f = ~.) %>%
      group_by(ID) %>%
      summarize_all(sum)
    

    编辑:我错过了@Karthik S 得到的过滤步骤。 filter(n() == length(df_lst)) 是一个不错的解决方案。

    df_lst <- list(df1, df2) 
    
    df_lst %>%
      map_dfr(.f = ~.) %>%
      group_by(ID) %>%
      filter(n() == length(df_lst)) %>%
      summarize_all(sum)
    

    【讨论】:

      【解决方案3】:

      如果您有dfs 列表,您可以使用此dplyr 解决方案

      library(dplyr)
      
      dfs <- list(df1, df2)
      
      bind_rows(dfs) %>% 
        group_by(ID) %>%
        summarise(wage = sum(wage), bonus = sum(bonus))
      

      【讨论】:

      • 来自dplyr 本身的bind_rows() 怎么样?
      【解决方案4】:

      另一种选择是组合 base R 函数以附加两个数据帧,然后简单地聚合结果。

      library(dplyr)
      do.call('rbind', list(df1, df2)) %>%
        group_by(ID) %>%
        filter(n() == length(list(df1, df2))) %>%  #as per Karthik S
        summarise_all(., sum)
      
      #       ID  wage bonus
      #     <int> <int> <int>
      # 1     1  3300  2200
      # 2     2  3302  2202
      # 3     3  3304  2204
      # 4     4  3306  2206
      # 5     5  3308  2208
      # 6     6  3310  2210
      # 7     7  3312  2212
      # 8     8  3314  2214
      # 9     9  3316  2216
      # 10    10  3318  2218
      

      【讨论】:

        猜你喜欢
        • 2018-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-18
        • 1970-01-01
        • 2020-06-17
        相关资源
        最近更新 更多