我有个小标题:
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]>
我想使用two
将three
和one
列中的缺失值替换为coalesce()
列中的值,然后将每个字符向量(行)折叠到使用two
将three
和toString()
合并为一个字符串。我的预期输出如下所示:
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
,但是我不确定该用什么。我想知道是否有人可以阐明上述原因为何不起作用,因为我对范围动词的内在工作方式完全不熟悉。
答案 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"