【问题标题】:Binding dataframes of different length (no cbind, no merge)绑定不同长度的数据帧(无 cbind,无合并)
【发布时间】:2021-07-16 08:25:58
【问题描述】:

我正在尝试将多个数据框并排显示以比较某些条目。但是,它们的行数不同,我希望每个数据框的顺序完全相同。 我尝试使用cbind,由于行数不同,它不起作用。我使用merge 将两个 dfs 绑定在一起,然后再次合并它们,但是当我这样做时它们会改变顺序,当我总共有超过 5 个时合并两个 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 的顺序。任何帮助将不胜感激!

【问题讨论】:

    标签: r merge cbind


    【解决方案1】:
    library(plyr)
    combined <- rbind.fill(df[c("v", "x")], df2[c("m", "n")])
    

    这是你想要的吗?

    【讨论】:

      【解决方案2】:

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

      • 创建所有 dfs 的列表,除了一个说第一个之外
      • 使用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
      

      早期答案:在 dfs 中创建一个虚拟列 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>
      

      【讨论】:

      • 我已经试过了,但是我仍然有一个问题,我想把多个数据框放在一起。一旦我在命令中放入两个以上的数据框,合并就不起作用。一次合并两个似乎非常低效。我只是想知道是否有更快的方法来做到这一点
      • 查看编辑后的答案。如果在要连接的任何数据框中有一个名为 id 的列,请使用其他名称,例如 dummy,该名称在任何数据框中都不存在。
      【解决方案3】:

      基础 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>
      

      【讨论】:

        【解决方案4】:

        另一种基本 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)
        

        【讨论】:

          猜你喜欢
          • 2012-12-15
          • 2020-04-10
          • 2019-02-27
          • 2016-10-09
          • 2019-05-22
          • 2023-03-16
          • 2011-08-23
          • 2016-11-03
          相关资源
          最近更新 更多