如何在 dplyr 中使用 map2() 改变 () 列列表

How to mutate() a list of columns using map2() in dplyr

我最近不得不编译一个学生分数的数据框(每个学生一行,id 列和几个整数值列,每个分数部分一个)。我不得不组合一个 "master" 数据框和几个 "correction" 数据框(主要包含 NA 和一些对主控的更新),以便结果包含主控的最大值,并且所有更正。

我成功地复制粘贴了一系列 mutate() 调用,这有效(见下面的示例),但在我看来并不优雅。我本来想做的不是复制和粘贴,而是使用 map2 和两个列列表来成对比较列。类似的东西(这显然不起作用):

list_of_cols1 <- list(col1.x, col2.x, col3.x)
list_of_cols2 <- list(col1.y, col2.y, col3.y
map2(list_of_cols1, list_of_cols2, ~ column = pmax(.x, .y, na.rm=T))

我似乎想不出办法去做。我的问题是:如何指定这样的列列表并在 dplyr 管道中的一个 map2() 调用中改变它们,或者甚至有可能——我都弄错了吗?

最小工作示例

library(tidyverse)

master <- tibble(
  id=c(1,2,3), 
  col1=c(1,1,1),
  col2=c(2,2,2),
  col3=c(3,3,3)
)
correction1 <- tibble(
  id=seq(1,3),
  col1=c(NA, NA, 2 ),
  col2=c( 1, NA, 3 ),
  col3=c(NA, NA, NA)
)

result <- reduce(
  # Ultimately there would several correction data frames
  list(master, correction1), 
  function(x,y) {
    x <- x %>% 
      left_join(
        y,
        by = c("id")
      ) %>%
      # Wish I knew how to do this mutate call with map2 
      mutate(
        col1 = pmax(col1.x, col1.y, na.rm=T), 
        col2 = pmax(col2.x, col2.y, na.rm=T), 
        col3 = pmax(col3.x, col3.y, na.rm=T)
      ) %>%
      select(id, col1:col3)
  }
)

结果是

> result
# A tibble: 3 x 4
     id  col1  col2  col3
  <int> <dbl> <dbl> <dbl>
1     1     1     2     3
2     2     1     2     3
3     3     2     3     3

而不是 left_join,只需绑定行然后汇总。例如

result <- reduce(
  list(master, master), 
  function(x,y) {
    bind_rows(x, y) %>%
      group_by(id) %>%
      summarize_all(max, na.rm=T)
  }
)
result
#     id  col1  col2  col3
#   <dbl> <dbl> <dbl> <dbl>
# 1     1     1     2     3
# 2     2     1     2     3
# 3     3     2     3     3

实际上,您甚至不需要 reduce,因为 bind_rows 可以使用列表

再添加一个table

correction2 <- tibble(id=2,col1=NA,col2=8,col3=NA)
bind_rows(master, correction1, correction2) %>% 
  group_by(id) %>%
  summarize_all(max, na.rm=T)

抱歉,这没有回答您关于 map2 的问题,我发现在 tidy R 中聚合行比聚合列更容易:

library(dplyr)

master <- tibble(
  id=c(1,2,3), 
  col1=c(1,1,1),
  col2=c(2,2,2),
  col3=c(3,3,3)
)
correction1 <- tibble(
  id=seq(1,3),
  col1=c(NA, NA, 2 ),
  col2=c( 1, NA, 3 ),
  col3=c(NA, NA, NA)
)

result <- list(master, correction1) %>% 
  bind_rows() %>% 
  group_by(id) %>% 
  summarise_all(max, na.rm = TRUE)

result
#> # A tibble: 3 x 4
#>      id  col1  col2  col3
#>   <dbl> <dbl> <dbl> <dbl>
#> 1     1     1     2     3
#> 2     2     1     2     3
#> 3     3     2     3     3

如果 correction 表将始终具有与 master 相同的结构,您可以执行如下操作:

library(dplyr)
library(purrr)

update_master = function(...){
  map(list(...), as.matrix) %>%
    reduce(pmax, na.rm = TRUE) %>%
    data.frame()
}

update_master(master, correction1)

要允许 id 取字符值,请进行以下修改:

update_master = function(x, ...){
  map(list(x, ...), function(x) as.matrix(x[-1])) %>%
    reduce(pmax, na.rm = TRUE) %>%
    data.frame(id = x[[1]], .)
}

update_master(master, correction1)

结果:

  id col1 col2 col3
1  1    1    2    3
2  2    1    2    3
3  3    2    3    3