【问题标题】:How to copy a column from a dataframe into another by matching 3 columns in each如何通过匹配每个数据框中的 3 列将一列从数据框中复制到另一列
【发布时间】:2026-02-17 01:45:01
【问题描述】:

我有 2 个数据框,我试图通过将第一个数据框中的 3 列与第二个数据框中的 3 列相匹配,将一个数据框中的一列复制到另一个数据框中。我不想完全合并数据框,因为我的真实数据框每个都有太多列,我不希望它们都在一起。

以下是示例数据框:

df1

       ID_num  Terr_Bred  Dispersal_Dist  Year_Bred
  1         1        BAM             760       1987
  2         2        GRE            1006       1993
  3         3        MEW             999       2000

df2

        Mal_ID    Date_Rec   Year  Terr  Pair_ID  Fem_ID
  1          4   3/22/1987   1987   BAM       87       1
  2          7   2/22/1987   1987   YER       43       1
  3          5   1/17/1993   1993   GRE       22       2
  4          8   2/14/1991   1991   GRE       91       2
  5          6   10/1/2000   2000   MEW       65       3

我想要这个:

       ID_num  Year_Bred   Terr_Bred   Dispersal_Dist Mate_ID_num
  1         1       1987         BAM              760           4
  2         2       1993         GRE             1006           5
  3         3       2000         MEW              999           6

所以,我尝试将 df2 中的 Mal_ID 列添加到 df1 中,并将列重命名为 Mate_ID_num。为此,我想将 df1 中的 ID_num 列匹配到 df2 中的 Fem_ID 列,将 df1 中的 Year_Bred 列匹配到 df2 中的 Year 列,并将 df1 中的 Terr_Bred 列匹配到 df2 中的 Terr 列。如上面的示例所示,每个数据框中的列名称不同。

我无法找到执行此操作的方法,我只找到了完全合并数据框或基于匹配每个数据框中的单个列而不是多个列来添加列的示例。

【问题讨论】:

    标签: r


    【解决方案1】:

    1) 基数 这称为左连接:

    by.x <- c("ID_num", "Year_Bred", "Terr_Bred")
    by.y <- c("Fem_ID", "Year", "Terr")
    
    df <- merge(df1[by.x], df2[c(by.y, "Mal_ID")], 
             all.x = TRUE, all.y = FALSE, by.x = by.x, by.y = by.y)
    
    names(df["Mal_ID"]) <- "Mal_ID_num"
    

    给予:

    > df
      ID_num Year_Bred Terr_Bred Dispersal_Dist Mate_ID_num
    1      1      1987       BAM            760           4
    2      2      1993       GRE           1006           5
    3      3      2000       MEW            999           6
    

    我们使用名称而不是位置表示法,因为您指出列在实际问题中未对齐,但对于问题中显示的问题(在问题更改之前但反映在注释中的可重复输入中)合并使用这样的位置符号会稍微短一些:

    df <- merge(df1[1:3], df2[1:4], all.x = TRUE, all.y = FALSE, by = 1:3)
    

    然而,

    2) 也可以使用 SQL 来完成:

    library(sqldf)
    sqldf("select a.*, b.Mal_ID Ma1_ID_num
           from df1 a left join df2 b on a.ID_num = b.Fem_ID and 
                                         a.Year_Bred = b.Year and 
                                         a.Terr_Bred = b.Terr")
    

    给予:

      ID_num Year_Bred Terr_Bred Dispersal_Dist Ma1_ID_num
    1      1      1987       BAM            760          4
    2      2      1993       GRE           1006          5
    3      3      2000       MEW            999          6
    > 
    

    注意: df1df2 的可复制形式如下。问题最初有这些,但后来改变了它们;但是,上面的答案使用了原始的df1df2,如下所示。

    Lines1 <- "
           ID_num  Year_Bred  Terr_Bred  Dispersal_Dist  
      1         1       1987        BAM             760
      2         2       1993        GRE            1006
      3         3       2000        MEW             999"
    df1 <- read.table(text = Lines1, as.is = TRUE)
    
    Lines2 <- "
            Fem_ID   Year  Terr      Mal_ID  Pair_ID    Date_Rec
      1          1   1987   BAM           4       87   3/22/1987
      2          1   1987   YER           7       43   2/22/1987
      3          2   1993   GRE           5       22   1/17/1993
      4          2   1991   GRE           8       91   2/14/1991
      5          3   2000   MEW           6       65   10/1/2000"
    df2 <- read.table(text = Lines2, as.is = TRUE)
    

    【讨论】:

    • 我重新排列了 df2 以便我尝试匹配的列不对齐,因为在我的真实数据中,每个数据帧中的列不在同一个位置
    • 对不起,我也重新排列了 df1。我试图弄清楚如何按照你的方式去做,我这样做了: df
    • 已修改 (1) 显示如何使用名称而不是职位。 (2) 仅已使用的名称。这使用了您的原始数据框,但如果名称已更改,如何适应它应该很明显。
    • 谢谢!这也最终起作用了!唯一的事情是出于某种原因,我 df 没有 Dispersal_Dist 列,但我只是做了 merge(df, df1) 来取回该列。再次感谢!
    【解决方案2】:

    您也可以使用dplyr 来做同样的事情,它比基础 R 更具表现力:

    library(dplyr)
    
    df <- df1 %>%
      left_join(df2, c("ID_num" = "Fem_ID", "Year_Bred" = "Year", "Terr_Bred" = "Terr")) %>%
      rename(Mate_ID_num = Mal_ID) %>%
      select(1:5)
    

    【讨论】:

      最近更新 更多