mutate_at中的复合函数

时间:2019-06-22 05:02:16

标签: r dplyr data-manipulation purrr mutate

我有个小标题:

df = tibble(one = list('a', 'b'), two = list(c('p1', 'p2', 'p3'), NA_character_), three = list(NA_character_, c('z1', 'z2', 'z3')))

df
# A tibble: 2 x 3
  one   two       three    
  <chr> <list>    <list>   
1 a     <chr [3]> <chr [1]>
2 b     <chr [1]> <chr [3]>

我想使用twothreeone列中的缺失值替换为coalesce()列中的值,然后将每个字符向量(行)折叠到使用twothreetoString()合并为一个字符串。我的预期输出如下所示:

df = tibble(one = c('a', 'b'), two = list('p1, p2, p3', 'b'), three = list('a', 'z1, z2, z3'))
df
# A tibble: 2 x 3
  one   two       three    
  <chr> <list>    <list>   
1 a     <chr [1]> <chr [1]>
2 b     <chr [1]> <chr [1]>

这是我最初尝试的内容:

df %>% mutate_at(vars(two, three), funs(coalesce(., one) %>% map(., toString)))

我知道funs()引用了它的参数,但是我不明白为什么它不适用于管道。该文档还建议不建议使用funs,但是我不确定该用什么。我想知道是否有人可以阐明上述原因为何不起作用,因为我对范围动词的内在工作方式完全不熟悉。

2 个答案:

答案 0 :(得分:3)

我们可以先使用map2,再使用coalesce,然后再使用toString

library(dplyr)
library(purrr)

df1 <- df %>% 
        mutate_at(vars(two, three), ~map2(., one, ~toString(coalesce(.x, .y))))

df1

#  one   two       three    
#  <chr> <list>    <list>   
#1 a     <chr [1]> <chr [1]>
#2 b     <chr [1]> <chr [1]>

df1$two
#[[1]]
#[1] "p1, p2, p3"

#[[2]]
#[1] "b"

df1$three
#[[1]]
#[1] "a"

#[[2]]
#[1] "z1, z2, z3"

在上面的示例中,我们使用~的lambda样式表达式将其用作函数,确实是funs已被弃用,并已由list()代替。 this question中的答案和评论提供了对此的更多见解。

答案 1 :(得分:1)

有了tidyverse,我们就可以利用pmap

library(tidyverse)
out <- df %>% 
          mutate_at(vars(two, three),
               list(~ pmap(list(., one), ~ list(...) %>% 
                        reduce(coalesce) %>%
                        toString)))

out
# A tibble: 2 x 3
#  one   two       three    
#  <chr> <list>    <list>   
#1 a     <chr [1]> <chr [1]>
#2 b     <chr [1]> <chr [1]>
out$two
#[[1]]
#[1] "p1, p2, p3"

#[[2]]
#[1] "b"

out$three
#[[1]]
#[1] "a"

#[[2]]
#[1] "z1, z2, z3"

或使用Map中的base R

df[-1] <- lapply(df[-1], function(x) do.call(Map, 
     c(f = function(x, y) toString(coalesce(x, y)), list(x, df$one))))
df
# A tibble: 2 x 3
#  one   two       three    
#  <chr> <list>    <list>   
#1 a     <chr [1]> <chr [1]>
#2 b     <chr [1]> <chr [1]>
df$two
#[[1]]
#[1] "p1, p2, p3"

#[[2]]
#[1] "b"

df$three
#[[1]]
#[1] "a"

#[[2]]
#[1] "z1, z2, z3"