如何使用 purrr 将函数应用于成对的列?
How to apply function to pairs of columns with purrr?
我有以下由 dplyr 连接产生的数据框:
data_frame(id=1:4, a.x = c(1, NA, 3, 4), a.y = c(1, 2, 3, 4), b.x = c(NA, NA, 3, NA), b.y = c(2, 2, NA, 4))
# A tibble: 4 x 5
id a.x a.y b.x b.y
<int> <dbl> <dbl> <dbl> <dbl>
1 1 1 1 NA 2
2 2 NA 2 NA 2
3 3 3 3 3 NA
4 4 4 4 NA 4
我想用 .y
结尾的列中的值替换以 .x
结尾的列中的所有 NA。最终,我想实现这个:
# A tibble: 4 x 5
id a.x a.y b.x b.y
<int> <dbl> <dbl> <dbl> <dbl>
1 1 1 1 2 2
2 2 2 2 2 2
3 3 3 3 3 NA
4 4 4 4 4 4
我用 purrr 试过这样的东西:
data_frame(id=1:4, a.x = c(1, NA, 3, 4), a.y = c(1, 2, 3, 4), b.x = c(NA, NA, 3, NA), b.y = c(2, 2, NA, 4)) %>%
map2_dfr(.x = ends_with('.y'), .y = ends_with('.x'), ~ case_when(is.na(.x) ~ .y,
TRUE ~ .x))
这是错误的。文档让我有点困惑,我认为这里的问题是 .x 需要一个向量,但是我怎样才能传递列列表?
一个tidyr解决方案。我们可以 gather
列,separate
.
,arrange
列,fill
向上的值,unite
列,最后 spread
将数据框改成原来的结构。
library(tidyverse)
dat2 <- dat %>%
gather(Column, Value, -id) %>%
separate(Column, into = c("Col1", "Col2")) %>%
arrange(id, Col1, Col2) %>%
group_by(id, Col1) %>%
fill(Value, .direction = "up") %>%
unite(Column, Col1, Col2, sep = ".") %>%
spread(Column, Value) %>%
ungroup()
dat2
## A tibble: 4 x 5
# id a.x a.y b.x b.y
# * <int> <dbl> <dbl> <dbl> <dbl>
# 1 1 1.00 1.00 2.00 2.00
# 2 2 2.00 2.00 2.00 2.00
# 3 3 3.00 3.00 3.00 NA
# 4 4 4.00 4.00 4.00 4.00
或者如果数据框中列的顺序很好,我们可以使用 data.table 包中的 transpose
函数,但要注意列类型可能会在处理后发生变化.
dat2 <- dat %>%
data.table::transpose() %>%
fill(everything(), .direction = 'up') %>%
data.table::transpose() %>%
setNames(names(dat))
dat2
# id a.x a.y b.x b.y
# 1 1 1 1 2 2
# 2 2 2 2 2 2
# 3 3 3 3 3 NA
# 4 4 4 4 4 4
或者使用purrr的解决方案先创建列名为ends_with
"x"和"y"的子集,然后替换以[=36结尾的原始列=].
dat_x <- dat %>% select(ends_with("x"))
dat_y <- dat %>% select(ends_with("y"))
dat[, grepl("x$", names(dat))] <- map2(dat_x, dat_y, ~ifelse(is.na(.x), .y, .x))
dat
# # A tibble: 4 x 5
# id a.x a.y b.x b.y
# <int> <dbl> <dbl> <dbl> <dbl>
# 1 1 1.00 1.00 2.00 2.00
# 2 2 2.00 2.00 2.00 2.00
# 3 3 3.00 3.00 3.00 NA
# 4 4 4.00 4.00 4.00 4.00
数据
dat <- data_frame(id=1:4, a.x = c(1, NA, 3, 4), a.y = c(1, 2, 3, 4), b.x = c(NA, NA, 3, NA), b.y = c(2, 2, NA, 4))
我有以下由 dplyr 连接产生的数据框:
data_frame(id=1:4, a.x = c(1, NA, 3, 4), a.y = c(1, 2, 3, 4), b.x = c(NA, NA, 3, NA), b.y = c(2, 2, NA, 4))
# A tibble: 4 x 5
id a.x a.y b.x b.y
<int> <dbl> <dbl> <dbl> <dbl>
1 1 1 1 NA 2
2 2 NA 2 NA 2
3 3 3 3 3 NA
4 4 4 4 NA 4
我想用 .y
结尾的列中的值替换以 .x
结尾的列中的所有 NA。最终,我想实现这个:
# A tibble: 4 x 5
id a.x a.y b.x b.y
<int> <dbl> <dbl> <dbl> <dbl>
1 1 1 1 2 2
2 2 2 2 2 2
3 3 3 3 3 NA
4 4 4 4 4 4
我用 purrr 试过这样的东西:
data_frame(id=1:4, a.x = c(1, NA, 3, 4), a.y = c(1, 2, 3, 4), b.x = c(NA, NA, 3, NA), b.y = c(2, 2, NA, 4)) %>%
map2_dfr(.x = ends_with('.y'), .y = ends_with('.x'), ~ case_when(is.na(.x) ~ .y,
TRUE ~ .x))
这是错误的。文档让我有点困惑,我认为这里的问题是 .x 需要一个向量,但是我怎样才能传递列列表?
一个tidyr解决方案。我们可以 gather
列,separate
.
,arrange
列,fill
向上的值,unite
列,最后 spread
将数据框改成原来的结构。
library(tidyverse)
dat2 <- dat %>%
gather(Column, Value, -id) %>%
separate(Column, into = c("Col1", "Col2")) %>%
arrange(id, Col1, Col2) %>%
group_by(id, Col1) %>%
fill(Value, .direction = "up") %>%
unite(Column, Col1, Col2, sep = ".") %>%
spread(Column, Value) %>%
ungroup()
dat2
## A tibble: 4 x 5
# id a.x a.y b.x b.y
# * <int> <dbl> <dbl> <dbl> <dbl>
# 1 1 1.00 1.00 2.00 2.00
# 2 2 2.00 2.00 2.00 2.00
# 3 3 3.00 3.00 3.00 NA
# 4 4 4.00 4.00 4.00 4.00
或者如果数据框中列的顺序很好,我们可以使用 data.table 包中的 transpose
函数,但要注意列类型可能会在处理后发生变化.
dat2 <- dat %>%
data.table::transpose() %>%
fill(everything(), .direction = 'up') %>%
data.table::transpose() %>%
setNames(names(dat))
dat2
# id a.x a.y b.x b.y
# 1 1 1 1 2 2
# 2 2 2 2 2 2
# 3 3 3 3 3 NA
# 4 4 4 4 4 4
或者使用purrr的解决方案先创建列名为ends_with
"x"和"y"的子集,然后替换以[=36结尾的原始列=].
dat_x <- dat %>% select(ends_with("x"))
dat_y <- dat %>% select(ends_with("y"))
dat[, grepl("x$", names(dat))] <- map2(dat_x, dat_y, ~ifelse(is.na(.x), .y, .x))
dat
# # A tibble: 4 x 5
# id a.x a.y b.x b.y
# <int> <dbl> <dbl> <dbl> <dbl>
# 1 1 1.00 1.00 2.00 2.00
# 2 2 2.00 2.00 2.00 2.00
# 3 3 3.00 3.00 3.00 NA
# 4 4 4.00 4.00 4.00 4.00
数据
dat <- data_frame(id=1:4, a.x = c(1, NA, 3, 4), a.y = c(1, 2, 3, 4), b.x = c(NA, NA, 3, NA), b.y = c(2, 2, NA, 4))