如何在列表中使用相同的列名 rbind 数据帧

how to rbind dataframes with identical column names in a list

我有一个这样的列表:

list=list(
  df1=read.table(text = "a  b   c
11  14  20
                 17 15  12
                 6  19  17
                 ",header=T),

  df2=read.table(text = "a  b   c
6   19  12
                 9  7   19

                 ",header=T),
  df3=read.table(text = "a  d   f
12  20  15
                 12 10  8
                 7  8   7

                 ",header=T),
  df4=read.table(text = "g  f   e   z
5   12  11  5
16  17  20  16
19  9   11  20

                 ",header=T),
  df5=read.table(text = "g  f   e   z
15  13  9   18
                 12 12  17  16
                 15 9   12  11
                 15 20  19  15

                 ",header=T),
  df6=read.table(text = "a  d   f
11  7   16
                 11 12  11

                 ",header=T)
)

我的列表包含不同的数据框。根据列名,列表中有 3 种类型的数据框。

type1:df1 and df2
type2:df3 and df6
type3:f4 and df5

我将 rbind 具有相同列名的数据帧并将结果保存在新列表中。例如,df1 和 df2、df3 和 df6 以及 df4 和 df5 具有相同的列 names.I 需要一个代码来自动识别和 rbind 具有相同列名的数据帧。

预期结果如下:

> new list
$df1.df2
  a  b  c
1 11 14 20
2 17 15 12
3  6 19 17
4  6 19 12
5  9  7 19

$df3.df6
   a  d  f
1 12 20 15
2 12 10  8
3  7  8  7
4 11  7 16
5 11 12 11

$df4.df5
   g  f  e  z
1  5 12 11  5
2 16 17 20 16
3 19  9 11 20
4 15 13  9 18
5 12 12 17 16
6 15  9 12 11
7 15 20 19 15

新列表中数据框的名称可以是任何名称。

因为我不喜欢命名变量 list,所以我将您的数据命名为 l

lapply(
  split(l, sapply(l, function(a) paste(colnames(a), collapse = "_"))),
  dplyr::bind_rows)
# $a_b_c
#    a  b  c
# 1 11 14 20
# 2 17 15 12
# 3  6 19 17
# 4  6 19 12
# 5  9  7 19
# $a_d_f
#    a  d  f
# 1 12 20 15
# 2 12 10  8
# 3  7  8  7
# 4 11  7 16
# 5 11 12 11
# $g_f_e_z
#    g  f  e  z
# 1  5 12 11  5
# 2 16 17 20 16
# 3 19  9 11 20
# 4 15 13  9 18
# 5 12 12 17 16
# 6 15  9 12 11
# 7 15 20 19 15

我通常更喜欢使用 by(data, INDICES, FUN) 而不是 lapply(split(data, INDICES), FUN),但由于某种原因它一直在抱怨......所以上面。

选择将与 _ 折叠的列名称连接在一起是任意的,目的是找到一个简单的 "hashing";不难设计出一种情况,即此方法发现两个相似的帧,而实际上它们不相似......也许不太可能引起关注。

我还应该注意,我使用的是 dplyr::bind_rows,但没有使用 dplyr。这可以很容易地转换成使用 purrr:: 或其他整洁包分组的东西。

我们可以

library(tidyverse)
library(janitor)

bind_rows(dfls) %>% 
  mutate(code= apply(apply(., 2, function(x){
               ifelse(is.na(x), 1, 2)}), 1, paste, collapse="")) %>% 
  nest(.,-code, .key="code") %>% 
  mutate(filtered = map(code, janitor::remove_empty_cols)) %>% 
  pull(filtered) -> out

glimpse(out)

# List of 3
#  $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 5 obs. of  3 variables:
#   ..$ a: int [1:5] 11 17 6 6 9
#   ..$ b: int [1:5] 14 15 19 19 7
#   ..$ c: int [1:5] 20 12 17 12 19
#  $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 5 obs. of  3 variables:
#   ..$ a: int [1:5] 12 12 7 11 11
#   ..$ d: int [1:5] 20 10 8 7 12
#   ..$ f: int [1:5] 15 8 7 16 11
#  $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 7 obs. of  4 variables:
#   ..$ f: int [1:7] 12 17 9 13 12 9 20
#   ..$ g: int [1:7] 5 16 19 15 12 15 15
#   ..$ e: int [1:7] 11 20 11 9 17 12 19
#   ..$ z: int [1:7] 5 16 20 18 16 11 15