按相同 ID 对所有列求和

Sum all columns, by same ID

我有 12 个 data.frames 具有相同的变量,但行号不同。这些 data.frames 有一个列 ID,并且这些 ID 的 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都有每个月的工资和奖金,所以我这里的目标是拿到年薪。 如果有人能提供帮助,我将不胜感激。

如果你有一个列表 dfs 你可以使用这个 dplyr 解决方案

library(dplyr)

dfs <- list(df1, df2)

bind_rows(dfs) %>% 
  group_by(ID) %>%
  summarise(wage = sum(wage), bonus = sum(bonus))

这个有用吗:

> 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
> 

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

> 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
> 

抛出另一个选项,如果你有一个包含所有数据框的列表,你可以使用 purrr::map_dfr 将它们绑定在一起。在这种情况下,被映射的函数只是 return 数据帧,因此它与 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)

另一种选择是组合 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