两个两个(或按名称)绑定列表中的数据帧 - R

Bind dataframes in a list two by two (or by name) - 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

这里有一个 Map 的解决方案,但它只适用于两个后缀。如果要merge,使用第一个Map指令;如果您想保留重复项,请使用第二个 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))

你的意思是这样的吗?

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

许多强制性 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)

同样对于这样的事情,dplyr 中的 bind_rows() 有一个 .id 参数,它将添加一个带有列表元素名称的列,并堆叠行。这也是一种有用的方法。您可以绑定,随意操作名称,然后 split().