объединить несколько столбцов в R в новый векторный столбец (предпочтительно решение tidyr)

#r #dplyr #tidyr

#r #dplyr #tidyr

Вопрос:

Я пытаюсь объединить несколько столбцов в вектор (в идеале я хотел бы указать, какие столбцы используют какое-либо регулярное выражение или dplyr::contains() . В любом случае, я НЕ собираюсь объединять столбцы или использовать решение paste (я хочу иметь возможность использовать %in% оператор для результирующего вектора. Я хочу, чтобы новый столбец был вектором значений, который можно было бы отменить с помощью unnest_wider или какой-либо подобной функции. Я уверен, что это возможно, просто пока не могу придумать правильные условия поиска. Это кажется близким, но не работает:

 df <- tribble(~A, ~B,
               1, 2, 
               3, 4, 
               5, 6)

df %>%
    mutate(C = I(list(A, B)))
 

Результат будет выглядеть примерно так

       A     B    C
1     1     2   c(1,2)
2     3     4   c(3,4)
3     5     6   c(5,6)
 

Ответ №1:

Здесь мы можем либо использовать rowwise

 library(dplyr)
df %>%
   rowwise %>%
   mutate(C = list(c(A, B))) %>%
   ungroup
# A tibble: 3 x 3
#      A     B C        
#  <dbl> <dbl> <list>   
#1     1     2 <dbl [2]>
#2     3     4 <dbl [2]>
#3     5     6 <dbl [2]>
 

Или с map2 помощью которого по умолчанию возвращается a list . Здесь мы перебираем соответствующие элементы ‘A’, ‘B’ и объединяем ( c )

 library(dplyr)
library(purrr)
df %>%
   mutate(C = map2(A, B, c))
# A tibble: 3 x 3
#      A     B C        
#   <dbl> <dbl> <list>   
#1     1     2 <dbl [2]>
#2     3     4 <dbl [2]>
#3     5     6 <dbl [2]>
 

Обновить

Основываясь на комментариях OP, если мы хотим создать list столбец только со столбцами, имеющими суффикс _id

 names(df) <- paste0(names(df), "_id")
df %>%
    rowwise %>%
    mutate(C = list(c_across(ends_with("_id")))) %>%
    ungroup
 

-вывод

 # A tibble: 3 x 3
#   A_id  B_id C        
#  <dbl> <dbl> <list>   
#1     1     2 <dbl [2]>
#2     3     4 <dbl [2]>
#3     5     6 <dbl [2]>
 

Если подстрока "_id" находится в начале, измените значение ends_with на starts_with или используйте matches("^_id")

Или с pmap

 df %>%
     mutate(C = pmap(select(., ends_with("_id")), ~ c(...)))
 

-вывод

 # A tibble: 3 x 3
#   A_id  B_id C        
#  <dbl> <dbl> <list>   
#1     1     2 <dbl [2]>
#2     3     4 <dbl [2]>
#3     5     6 <dbl [2]>
 

Или с помощью Map из base R

 df$C <-  do.call(Map, c(f = c, df[grep("_id", names(df))]))
 

Комментарии:

1. Спасибо, этот первый вариант работает, есть идеи о том, как добавить команду grepl для выбора переменных, которые необходимо включить (скажем, только столбцы с префиксом «_id»)? второй вариант работает только для меня, если есть максимум две строки, но может обратиться к другим функциям purr.s

2. @LSmeets Если у вас более одной переменной, вы можете использовать pmap вместо map2

3. @LSmeets вы можете проверить обновленное решение

4. Да, это работает! Спасибо. чтобы добавить функцию фильтра, просто добавьте %>% rowwise %>% filter(3 %in% C) к любому из двух вариантов.

5. Это очень классные решения! В моем случае мне больше всего понравился этот c_across метод, но он медленный с таким гигантским набором данных, как у меня (почти 4 миллиона строк). Для тех, кто читает это, у кого большой набор данных, purrr::pmap используйте вместо этого решение; это намного быстрее, потому что позволяет избежать необходимости использования rowwise .