Композитные функции в mutate_at - PullRequest
5 голосов
/ 22 июня 2019

У меня есть тибль:

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 устарела, но я не уверен, что использовать вместо него. Мне было интересно, может ли кто-то пролить свет на то, почему вышеперечисленное не работает, так как я совсем не знаком с внутренней работой глаголов с ограниченным кругом.

Ответы [ 2 ]

3 голосов
/ 22 июня 2019

Мы можем использовать 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"

В вышеприведенном примере мы используем лямбда-выражение стиля, используя ~, чтобы использовать его как функцию иэто правда, funs устарела и была заменена на list().Ответ и комментарии в на этот вопрос дают более полное представление об этом.

1 голос
/ 22 июня 2019

С 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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...