如何在 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
我最近不得不编译一个学生分数的数据框(每个学生一行,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