Привязать фреймы данных в списке два на два (или по имени) — R

#r #bind

#r #привязать

Вопрос:

Допустим, у меня есть этот список фреймов данных:

   DF1_A<- data.frame (first_column  = c("A", "B","C"),
                    second_column = c(5, 5, 5),
                    third_column = c(1, 1, 1)
)

DF1_B <- data.frame (first_column  = c("A", "B","E"),
                     second_column = c(1, 1, 5),
                     third_column = c(1, 1, 1)
)

DF2_A <- data.frame (first_column  = c("E", "F","G"),
                     second_column = c(1, 1, 5),
                     third_column = c(1, 1, 1)
)

DF2_B <- data.frame (first_column  = c("K", "L","B"),
                     second_column = c(1, 1, 5),
                     third_column = c(1, 1, 1)
)

mylist <- list(DF1_A, DF1_B, DF2_A, DF2_B)
names(mylist) = c("DF1_A", "DF1_B", "DF2_A", "DF2_B")


mylist =  lapply(mylist, function(x){
  x[, "first_column"] <- as.character(x[, "first_column"])
  x
})
 

Я хочу связать их по имени (все DF1, все DF2 и т.д.) Или, объективно, два на два в этом упорядоченном именованном списке. Сохранение «структуры именованного списка» списка важно для отслеживания (например, DF1_A и DF1_B = DF1 или что-то подобное в именах (mylist))

Есть несколько строк с дублированными значениями, и я хочу сохранить их (что приведет к появлению некоторых дублированных символов, таких как first_column, значение A).

Я пытался найти какие-либо подсказки здесь о переполнении стека, но большинство людей хотят привязывать фреймы данных независимо от их имен или порядков.

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

 mylist
DF1
DF2

DF1
first_column    second_column   third_column
A               1               1
A               5               1
B               1               1
B               5               1
C               5               1
E               5               1
 

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

1. В вашем вопросе вы говорите «объединить», «связать» и » » — все это звучит как разные операции. Не могли бы вы показать ожидаемый результат для DF1 ?

2. И когда вы говорите «Сохранить имя», вы имеете в виду, что вам нужно иметь возможность определить, из какого фрейма данных получено каждое наблюдение в результате? Или просто вам нужно знать, какие два фрейма данных являются частью данного результирующего фрейма данных?

3. Я отредактировал вопрос, чтобы придать ему больше смысла

4. Кроме того, может быть полезно знать вашу версию R или, по крайней мере, класс столбцов. В R версии 4.0 R переключился со старого значения по умолчанию, которое first_column будет factor class, на новое значение по умолчанию, которое будет character class .

5. У вас есть еще суффиксы или "A" и "B" являются единственными?

Ответ №1:

Вы имеете в виду что-то вроде этого?

 lapply(
  split(mylist, gsub("_.*", "", names(mylist))),
  function(v) `row.names<-`((out <- do.call(rbind, v))[do.call(order, out), ], NULL)
)
 

что дает

 $DF1
  first_column second_column third_column
1            A             1            1
2            A             5            1
3            B             1            1
4            B             5            1
5            C             5            1
6            E             5            1

$DF2
  first_column second_column third_column
1            B             5            1
2            E             1            1
3            F             1            1
4            G             5            1
5            K             1            1
6            L             1            1
 

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

1. Я думаю, что первый из них lapply (split (mylist, gsub(«_.*», «», имена(mylist))), функция(v) row.names<- ((out <- do.call(rbind, v))[do.call(order, out), ], NULL) ) лучше, просто потому, что он дает вам имена строк, указывающие, откуда взялась эта переменная!

2. @GabrielG. Спасибо. Я думаю, что заголовок вашего вопроса должен быть stack или row bind , а не merge . Лучше сделать более понятный заголовок для других читателей.

3. Могу ли я выбрать количество столбцов для rbind, если у df их разное количество? например, [,1:3]?

4. @GabrielG. Да, вы можете, но вы должны убедиться, что выбранные вами столбцы имеют одинаковые имена столбцов (поскольку rbind это требуется). Лучше выбирать столбцы по их именам, а не по индексам.

Ответ №2:

Вот решение с Map , но оно работает только для двух суффиксов. Если вы хотите merge , используйте первую Map инструкцию; если вы хотите сохранить дубликаты, используйте 2- rbind е решение.

 sp <- split(mylist, sub("^DF.*_", "", names(mylist)))
res1 <- Map(function(x, y)merge(x, y, all = TRUE), sp[["A"]], sp[["B"]])
res2 <- Map(function(x, y)rbind(x, y), sp[["A"]], sp[["B"]])

names(res1) <- sub("_.*$", "", names(res1))
names(res2) <- sub("_.*$", "", names(res2))
 

Ответ №3:

Одним из многих обязательных tidyverse решений может быть это.

 library(purrr)
library(stringr)

# find the unique DF names
unique_df <- set_names(unique(str_split_fixed(names(mylist), "_", 2)[,1]))

# loop over each unique name, extracting the elements and binding into columns
purrr::map(unique_df, ~ keep(mylist, str_starts(names(mylist), .x))) %>% 
  map(bind_rows)
 

Также для подобных вещей bind_rows() from dplyr имеет .id аргумент, который добавит столбец с именем элемента списка и сложит строки. Это также может быть полезным способом. Вы можете привязать, изменить имя, как хотите, а затем split() .