绑定不同长度的数据帧(无 cbind,无合并)

Binding dataframes of different length (no cbind, no merge)

我正在尝试并排显示多个数据框以比较某些条目。但是,它们的行数不同,我希望每个数据框的顺序完全相同。 我尝试使用 cbind 由于行数不同而无法使用。我使用 merge 将两个 dfs 绑定在一起,然后再次合并它们,但是当我这样做时它们改变了顺序,当我总共有 5 个以上的 dfs 时合并两个 dfs 似乎效率低下。

示例:

df <-  data.frame(v=1:5, x=sample(LETTERS[1:5],5))
df 
  v x
1 1 E
2 2 B
3 3 D
4 4 C
5 5 A

df2 <- data.frame(m=7:10, n=sample(LETTERS[6:9],4))
df2
   m n
1  7 G
2  8 I
3  9 F
4 10 H

然后我点了df2

df2 <- df2[order(df2$m, decreasing = TRUE),]
df2
   m n
4 10 F
3  9 I
2  8 H
1  7 G

预期输出:

  v x m n
1 1 E 10 F
2 2 B 9 I
3 3 D 8 H
4 4 C 7 G
5 5 A NA NA

正如我所说,我有两个以上的dfs,dfs的顺序应该保持不变。任何帮助将不胜感激!

library(plyr)
combined <- rbind.fill(df[c("v", "x")], df2[c("m", "n")])

这是你想要的吗?

编辑:如果有多个 df。这样做

  • 创建除第一个以外的所有 df 的列表
  • 使用purrr::reduce将所有这些连接在一起
  • .init 参数中首先传递 df
df2 <- data.frame(m=7:10, n=sample(LETTERS[6:9],4))
df <-  data.frame(v=1:5, x=sample(LETTERS[1:5],5))
df3 <- data.frame(bb = 101:110, cc = sample(letters, 10))


reduce(list(df2, df3), .init = df %>% mutate(id = row_number()) , ~full_join(.x, .y %>% mutate(id = row_number()), by = "id" )) %>%
  select(-id)

    v    x  m    n  bb cc
1   1    A 10    I 101  u
2   2    C  9    H 102  v
3   3    D  8    G 103  n
4   4    E  7    F 104  w
5   5    B NA <NA> 105  s
6  NA <NA> NA <NA> 106  y
7  NA <NA> NA <NA> 107  g
8  NA <NA> NA <NA> 108  i
9  NA <NA> NA <NA> 109  p
10 NA <NA> NA <NA> 110  h

较早的答案:在两个 df 中创建一个虚拟列 id 并使用 full_join

full_join(df %>% mutate(id = row_number()), df2 %>% mutate(id = row_number()), by = "id") %>%
  select(-id)

  v x  m    n
1 1 A 10    I
2 2 C  9    H
3 3 D  8    G
4 4 E  7    F
5 5 B NA <NA>

随机数种子不同导致结果与预期不同


或在 BaseR 中

merge(transform(df, id = seq_len(nrow(df))), transform(df2, id = seq_len(nrow(df2))), all = T)

  id v x  m    n
1  1 1 A 10    I
2  2 2 C  9    H
3  3 3 D  8    G
4  4 4 E  7    F
5  5 5 B NA <NA>

通过子集 []

简单地删除多余的列
merge(transform(df, id = seq_len(nrow(df))), transform(df2, id = seq_len(nrow(df2))), all = T)[-1]

  v x  m    n
1 1 A 10    I
2 2 C  9    H
3 3 D  8    G
4 4 E  7    F
5 5 B NA <NA>

基础 R 方法:

将数据帧放入列表中,获取行数最大的数据帧,将 NA 附加到行数较少的数据和 cbind.

list_df <- list(df, df2)
n_r <- seq_len(max(sapply(list_df, nrow)))
result <- do.call(cbind, lapply(list_df, `[`, n_r, ))
result

#  v x  m    n
#1 1 C 10    F
#2 2 B  9    H
#3 3 E  8    G
#4 4 D  7    I
#5 5 A NA <NA>

另一种基础 R 方法,但对于合并,您需要:

  • 添加 sort 参数以确保结果不会被排序
  • 从数据框中删除行名称
  • 添加 all 参数以确保使用所有行,
  • [-1]是去掉merge
  • 添加的行名列

示例:

set.seed(123)
df1 <-  data.frame(v = 1:5, 
                   x = sample(LETTERS[1:5], 5))
df1 
#>   v x
#> 1 1 A
#> 2 2 B
#> 3 3 D
#> 4 4 C
#> 5 5 E

df2 <- data.frame(m = 7:10, 
                  n = sample(LETTERS[6:9], 4))
df2
#>    m n
#> 1  7 G
#> 2  8 H
#> 3  9 I
#> 4 10 F

df2 <- df2[order(df2$m, decreasing = TRUE),]
df2
#>    m n
#> 4 10 F
#> 3  9 I
#> 2  8 H
#> 1  7 G

merge(data.frame(df1, row.names = NULL),
      data.frame(df2, row.names = NULL),
      by = 0,
      all = TRUE,
      sort = FALSE)[-1]
#>   v x  m    n
#> 1 1 A 10    F
#> 2 2 B  9    I
#> 3 3 D  8    H
#> 4 4 C  7    G
#> 5 5 E NA <NA>

如果您需要超过 2 个数据帧,您可以使用 Reduce

df3 <-  data.frame(a = 1:7, 
                   z = sample(LETTERS[1:7], 7))

Reduce(function(x,y) merge(x = x, y = y, by = 0, all = TRUE, sort = FALSE)[-1], 
       list(data.frame(df1, row.names = NULL), 
            data.frame(df2, row.names = NULL),
            data.frame(df3, row.names = NULL)))
#>    v    x  m    n a z
#> 1  1    C 10    I 1 F
#> 2  2    B  9    F 2 G
#> 3  3    E  8    H 3 A
#> 4  4    D  7    G 4 B
#> 5  5    A NA <NA> 5 C
#> 6 NA <NA> NA <NA> 6 D
#> 7 NA <NA> NA <NA> 7 E


Created on 2021-04-22 by the reprex package (v2.0.0)