Как объединить список фреймов с одинаковыми именами столбцов?
У меня есть следующие датафреймы
df1 <- tibble::as.tibble(list(a = c(1,2,3), d = c(10,11,12) ,id = c("a","b","c")))
df2 <- tibble::as.tibble(list(a = c(4,5,6), e = c(13,14,15) ,id = c("a","b","c")))
df3 <- tibble::as.tibble(list(a = c(7,8,9), f = c(16,17,18) ,id = c("a","b","c")))
Я хочу объединить эти кадры данных. Поскольку имя столбца a
происходит во всех них, я буду использовать suffix
аргумент при слиянии.
Желаемый результат, который я ищу, это
| id | a.df1 | d | a.df2 | e | a.df3 | f |
|----|-------|----|-------|----|-------|----|
| a | 1 | 10 | 4 | 13 | 7 | 16 |
| b | 2 | 11 | 5 | 14 | 8 | 17 |
| c | 3 | 12 | 6 | 15 | 9 | 18 |
Ниже приведен код, который я пытался
test_list <- list(df1, df2, df3)
names(test_list) <- c("df1", "df2", "df3")
seq_along(temp) %>%
purrr::reduce(
~merge(
temp[[.x]],
temp[[.y]],
suffix = c(names(test_list[.x]), names(test_list[.y])))
Однако это приводит к ошибке, заявляющей Error in temp[[.x]] : invalid subscript type 'list
, Почему я не могу установить подмножество для фрейма данных в функции слияния
Также есть лучший способ объединить список из нескольких фреймов данных с одинаковыми именами столбцов.
2 ответа
library(tidyverse)
df1 <- tibble::as.tibble(list(a = c(1,2,3), d = c(10,11,12) ,id = c("a","b","c")))
df2 <- tibble::as.tibble(list(a = c(4,5,6), e = c(13,14,15) ,id = c("a","b","c")))
df3 <- tibble::as.tibble(list(a = c(7,8,9), f = c(16,17,18) ,id = c("a","b","c")))
# create your list and the names
test_list <- list(df1, df2, df3)
names(test_list) <- c("df1", "df2", "df3")
# spot overlapping columns
test_list %>%
map_df(names) %>%
gather() %>%
count(value) %>%
filter(n > 1 & value != "id") %>%
pull(value) -> overlaps
map2(test_list, names(test_list), ~{names(.x)[names(.x) %in% overlaps] = paste0(names(.x)[names(.x) %in% overlaps],".",.y); .x}) %>%
reduce(function(x,y) left_join(x,y, by="id")) %>%
select(id, everything())
# # A tibble: 3 x 7
# id a.df1 d a.df2 e a.df3 f
# <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 a 1 10 4 13 7 16
# 2 b 2 11 5 14 8 17
# 3 c 3 12 6 15 9 18
Учитывая список и его имена мы используем map2
обновить имя каждого элемента в позиции 1 (т.е. столбец a
).
Тогда мы используем reduce
чтобы присоединиться к кадрам данных последовательно, и мы используем select
расставить колонны.
Как это выглядит?
t <- merge(df1,df2, by = "id" )
df <- merge(t,df3, by = "id" )
names(df) <- c("id", "a.df1", "a.df2", "a.df3")
или я прав, предполагая, что у вас на самом деле гораздо больше столбцов, и вы не хотите проходить слияние всего этого?
Функция eat
моего пакета safejoin имеет такую особенность, если вы дадите ему список data.frames в качестве второго входа, он рекурсивно присоединит их к первому входу. Мы можем переименовать все столбцы "а" и использовать его.
# devtools::install_github("moodymudskipper/safejoin")
library(safejoin)
dfs <- imap(lst(df1,df2,df3), ~rename_at(.x, "a",paste, .y, sep="."), .y) %>%
unname()
eat(dfs[[1]], dfs[-1], .by = "id")
# # A tibble: 3 x 7
# id a.df1 d a.df2 e a.df3 f
# <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 a 1 10 4 13 7 16
# 2 b 2 11 5 14 8 17
# 3 c 3 12 6 15 9 18