【问题标题】:How to mutate() a list of columns using map2() in dplyr如何在 dplyr 中使用 map2() 改变() 列列表
【发布时间】:2018-05-22 00:25:39
【问题描述】:

我最近不得不编译一个学生分数的数据框(每个学生一行,id 列和几个整数值列,每个分数组件一个)。我必须将一个“主”数据帧和几个“校正”数据帧(主要包含 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

【问题讨论】:

  • 澄清一下,只有当值大于master中的值时才应该进行更正?
  • 问得好,但不,我们的目标是在mastercorrection1(以及correction2correction3 等)表中找到最大值。

标签: r dplyr purrr


【解决方案1】:

而不是做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可以拿一个列表

添加另一个表

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

【讨论】:

  • 简单啊!我什至不认为我可以按行而不是比较列。这是第一个答案,非常简单。
【解决方案2】:

抱歉,这不能回答您关于 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

【讨论】:

    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-21
      • 1970-01-01
      • 1970-01-01
      • 2021-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多