【问题标题】:How to keep index when merging two dataframes in r在r中合并两个数据帧时如何保持索引
【发布时间】:2015-06-03 01:22:07
【问题描述】:

我有两个数据框:

> df1:
  a b
1 1 2
2 2 3
3 2 4
4 3 4
5 4 4
> df2:
  a b
1 1 1
2 1 2
3 2 3
4 3 4
5 5 5

然后合并df1和df2得到df3,请注意合并by=c("a","b")

df3<-merge(df1,df2)
> df3
  a b
1 1 2
2 2 3
3 3 4

我想获取 df1 中被选中的行的索引,并在 df1 中添加一个名为“label”的列。

   > df1:
      a b label    
    1 1 2  TRUE
    2 2 3  TRUE
    3 2 4 FALSE
    4 3 4  TRUE
    5 4 4 FALSE

我试过这个:

df1$label<-apply(df1,1,function (x) ifelse(nrow(merge(x,df3))>0,TRUE,FALSE))

得到了错误的结果,而且速度很慢,因为我的 df1 非常大。 有什么简单的方法吗?像向量中的 is.element 吗?谢谢。

【问题讨论】:

    标签: r merge


    【解决方案1】:

    通过在 SQL 中执行与 LEFT OUTER JOIN 等效的操作来合并 ab,然后将值 FALSE 分配给不匹配的行:

    df1 <- data.frame(a=c(1,2,2,3,4), b=c(2,3,4,4,4))
    df2 <- data.frame(a=c(1,1,3,5), b=c(1,2,4,5))
    df2$label <- TRUE                                  # df1 matches to df2 is TRUE
    df3 <- merge(df1, df2, by=c("a", "b"), all.x=TRUE) # merge on a AND b 
    df3$label[is.na(df3$label)] <- FALSE               # non-match is FALSE
    

    输出:

    > df3
      a b label
    1 1 2  TRUE
    2 2 3  TRUE
    3 2 4 FALSE
    4 3 4  TRUE
    5 4 4 FALSE
    

    【讨论】:

    • 谢谢,但问题是我需要“a”和“b”合并,而不仅仅是“a”。如果在 df2 中添加另一行,例如 '1 1',则将其标记为 TRUE,应为 FALSE。
    • 谢谢,但我不确定 'df3$a' 是否给出匹配行的索引。我刚刚编辑了我的问题,你能检查一下吗?
    • 嗨@xinyiFu 我已经根据你的要求再次更新了。
    【解决方案2】:

    这是使用data.table的另一种方式:

    require(data.table)
    setkey(setDT(df1), a)                     ## (1)
    idx = df1[df2, which=TRUE, nomatch=0L]    ## (2)
    df1[, label := FALSE][idx, label := TRUE] ## (3)
    df1
    #    a b label
    # 1: 1 2  TRUE
    # 2: 2 3 FALSE
    # 3: 3 4  TRUE
    # 4: 4 5 FALSE
    
    1. setDT 通过引用将 data.frame 转换为 data.table。在 data.table 上,我们在 a 列上 setkey - 它基本上按列 a 重新排序 data.table df1标记 该列已排序.这是在第 2 步中完成加入的先决条件。

    2. 我们执行x[i] 形式的连接,其中x=df1i=df2x 必须是 keyed data.table,i 可以是列表、data.frame 或 data.table。连接在键列a 上执行。对于df2a列的每一行,我们找到匹配的行,并使用参数which=TRUE返回它们,如果没有匹配,我们返回一个“0”该行使用nomatch=0L

      在这一步,我们得到idx = 1, 3, 0。因为,“1”和“3”匹配第一行和第三行,“5”没有匹配。

    3. 我们将整个label 列设置为FALSE,并且仅将idx 的那些行更新为TRUE(这些是匹配的行)。这是使用:= 运算符再次通过引用完成的(为了速度和内存效率)。

    查看HTML vignettes 了解更多信息。

    【讨论】:

      【解决方案3】:

      如果数据集比较大,也可以试试data.table

       library(data.table)
       setkey(setDT(df2),a)[df1][,c('label','b') := 
                             list(!is.na(b), i.b)][,i.b:= NULL][]
       #    a b label
       #1: 1 2  TRUE
       #2: 2 3 FALSE
       #3: 3 4  TRUE
       #4: 4 5 FALSE
      

      【讨论】:

        猜你喜欢
        • 2019-08-11
        • 2014-04-14
        • 2015-08-12
        • 2021-06-02
        • 1970-01-01
        • 1970-01-01
        • 2017-08-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多