Как удалить дублированные имена столбцов во вложенных тибблах перед отменой вложенности

#r #tidyr #unnest

Вопрос:

У меня есть тиббл со столбцом, содержащим (вложенные) тибблы. Вложенные фрагменты содержат дублированные данные (те же имена, те же значения).:

 df <- tibble(id = 1:2, data = list(tibble(id = 1, var1 = "a", var2 = "b"), tibble(id = 2, var1 = "c", var2 = "d")))

df

# # A tibble: 2 x 2
#      id data            
#   <int> <list>          
# 1     1 <tibble [1 x 3]>
# 2     2 <tibble [1 x 3]>  
 

Вызов df %>% unnest(data) приводит к

Error: Names must be unique. .

Я хотел бы написать функцию, которая заранее удаляет эти столбцы, но не знаю, как это сделать. Моя цель состоит в том, чтобы быть в состоянии использовать что-то вроде:

 df %>% 
  drop_duplicated_cols(data) %>% 
  unnest(data)
 

Что привело бы к:

 #> # A tibble: 2 x 4
#>      id var1  var2 
#>   <int> <chr> <chr>
#> 1     1 a     b    
#> 2     2 c     d    
 

Ответ №1:

Вы можете просто использовать unnest_longer

 library(tidyverse)
df %>%
  unnest_longer(data)
 

что дает:

 # A tibble: 2 x 2
     id data$id $var1 $var2
  <int>   <dbl> <chr> <chr>
1     1       1 a     b    
2     2       2 c     d 
 

Если вы хотите действительно преобразовать столбец tibble, вы также можете использовать:

 df %>%
  left_join(reduce(df$data, bind_rows), by = "id")
 

что дает:

 # A tibble: 2 x 4
     id data             var1  var2 
  <dbl> <list>           <chr> <chr>
1     1 <tibble [1 x 3]> a     b    
2     2 <tibble [1 x 3]> c     d   
 

И оттуда вы можете, например, отменить выбор столбца данных.

Ответ №2:

В этом есть names_repair аргумент unnest . По умолчанию это "check_unique" так, и это вызывает ошибку. Если мы изменим его на другой параметр, т. е. «уникальный», он сделает столбцы, которые дублируются, с .. последующими некоторыми цифрами, затем мы используем select , чтобы столбцы не дублировались

 library(dplyr)
library(tidyr)
library(stringr)
df %>%
    unnest(data, names_repair = "unique") %>%
    select(names(.)[!duplicated(str_remove(names(.), "\. .*"))]) %>%
    rename_with(~ str_remove(., "\. .*"), contains(".."))
 

-выход

 # A tibble: 2 x 3
     id var1  var2 
  <int> <chr> <chr>
1     1 a     b    
2     2 c     d   
 

Или другой вариант, чтобы избежать предупреждений, состоит в том, чтобы удалить повторяющиеся столбцы внутри list , выполнив цикл с map

 library(purrr)
out <- df %>% 
   mutate(data = map(data, ~ .x %>% 
            select(-any_of(names(df))))) %>%
   unnest(data)
out
# A tibble: 2 x 3
     id var1  var2 
  <int> <chr> <chr>
1     1 a     b    
2     2 c     d    
> str(out)
tibble [2 × 3] (S3: tbl_df/tbl/data.frame)
 $ id  : int [1:2] 1 2
 $ var1: chr [1:2] "a" "c"
 $ var2: chr [1:2] "b" "d"
 

ПРИМЕЧАНИЕ: Оба решения дают ожидаемый результат, как в посте ОП, вместе со структурой

Ответ №3:

Объедините df$data строки вместе и соедините их с исходным фреймом данных.

 library(dplyr)

left_join(df %>% select(-data), bind_rows(df$data), by = 'id')

#     id var1  var2 
#  <dbl> <chr> <chr>
#1     1 a     b    
#2     2 c     d