Отменить ввод нескольких столбцов

#r #tidyr

#r #tidyr

Вопрос:

У меня есть этот тип данных с несколькими столбцами списка:

 df <- structure(list(go = c("go after it", "here we go", "he went bust", 
                            "go get it go", "i 'm gonna go", "she 's going berserk"), left = list(
                              "", "we", "he", c("", "it"), c("'m", "gonna"), "'s"), node = list(
                                "go", "go", "went", c("go", "go"), c("gonna", "go"), "going"), 
                     right = list("after", "", "bust", c("get", ""), c("go", ""
                     ), "berserk")), class = "data.frame", row.names = c(NA, -6L
                     ))
 

Моя цель — отменить перечисление трех столбцов left , node , и right . Оба unnest_longer и unnest_auto , похоже, являются шагом в правильном направлении, но я не уверен, как действовать дальше:

 library(tidyr)
df %>%
  unnest_longer(node) # or:   unnest_auto(node)
# A tibble: 8 × 4
  go                   left      node   right    
  <chr>                <list>    <chr>  <list>   
1 go after it          <chr [0]> go     <chr [1]>
2 here we go           <chr [1]> go     <chr [0]>
3 he went bust         <chr [1]> went   <chr [1]>
4 go get it go         <chr [1]> go     <chr [1]>
5 go get it go         <chr [1]> go     <chr [1]>
6 i 'm gon na go       <chr [2]> gon na <chr [1]>
7 i 'm gon na go       <chr [2]> go     <chr [1]>
8 she 's going berserk <chr [1]> going  <chr [1]>
 

Ожидаемый результат таков:

 # go                         left      node     right  
# <chr>                      <chr>    <chr>     <chr>  
# 1 go after it                         go       after  
# 2 here we go                 we       go       
# 3 he went bust               he       went     bust   
# 4 go get it go                        go       get    
# 5 go get it go               it       go           
# 6 i 'm gon na go             'm       gon na   go     
# 7 i 'm gon na go         gon na       go            
# 8 she 's going berserk       's       going    berserk 
 

Ответ №1:

Мы можем использовать where

 library(dplyr)
library(tidyr)
library(purrr)
df %>% 
   mutate(mx = invoke(pmax, across(where(is.list), lengths))) %>% 
   mutate(across(where(is.list), ~ map2(.x, mx, ~ {
        length(.x) <- .y
        if(cur_column() == "left") .x <- .x[order(!is.na(.x))]
        .x})), mx = NULL) %>%
   unnest(where(is.list))
# A tibble: 8 × 4
  go                   left  node   right  
  <chr>                <chr> <chr>  <chr>  
1 go after it          <NA>  go     after  
2 here we go           we    go     <NA>   
3 he went bust         he    went   bust   
4 go get it go         <NA>  go     get    
5 go get it go         it    go     <NA>   
6 i 'm gon na go       'm    gon na go     
7 i 'm gon na go       na    go     <NA>   
8 she 's going berserk 's    going  berserk
 

Обновить

Основываясь на комментариях из OP, предыдущее решение работает

 df %>%
    unnest(where(is.list))
 

Если есть NULL элементы, укажите keep_empty = TRUE (в данных OP некоторые элементы были пустыми ( "" ) вместо NULL , поэтому предыдущий тоже должен работать

 df %>%
     unnest(where(is.list), keep_empty = TRUE)
# A tibble: 8 × 4
  go                   left    node  right    
  <chr>                <chr>   <chr> <chr>    
1 go after it          ""      go    "after"  
2 here we go           "we"    go    ""       
3 he went bust         "he"    went  "bust"   
4 go get it go         ""      go    "get"    
5 go get it go         "it"    go    ""       
6 i 'm gonna go        "'m"    gonna "go"     
7 i 'm gonna go        "gonna" go    "" 
 

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

1. Уважаемый @akrun, пожалуйста, примите мои искренние извинения: как вы и подозревали, я опубликовал неверно df . Я обновил его сейчас. С обновленным фреймом данных ваше оригинальное решение df %>% unnest(where(is.list)) работает отлично. Большое спасибо. Пожалуйста, обновите, чтобы я мог принять ваш ответ!

2. Еще раз извините за ошибочный dput. Теперь это должны быть правильные данные. И еще раз спасибо!

3. Оба решения, опубликованные @akrun, работают отлично!

Ответ №2:

 library(tidyverse)

df %>% unnest(c(left, node, right), keep_empty = TRUE)
#> # A tibble: 8 × 4
#>   go                   left    node  right    
#>   <chr>                <chr>   <chr> <chr>    
#> 1 go after it          ""      go    "after"  
#> 2 here we go           "we"    go    ""       
#> 3 he went bust         "he"    went  "bust"   
#> 4 go get it go         ""      go    "get"    
#> 5 go get it go         "it"    go    ""       
#> 6 i 'm gonna go        "'m"    gonna "go"     
#> 7 i 'm gonna go        "gonna" go    ""       
#> 8 she 's going berserk "'s"    going "berserk"
 

Создано 2021-12-04 пакетом reprex (v2.0.1)