#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