【问题标题】:Replace value in data frame with value from other data frame based on set of conditions根据一组条件将数据框中的值替换为其他数据框中的值
【发布时间】:2017-04-22 00:07:05
【问题描述】:

在 df1 中,我需要将 msec 的值替换为 df2 中的相应值。

df1 <- data.frame(ID=c('rs', 'rs', 'rs', 'tr','tr','tr'), cond=c(1,1,2,1,1,2), 
block=c(2,2,4,2,2,4), correct=c(1,0,1,1,1,0), msec=c(456,678,756,654,625,645))

df2 <- data.frame(ID=c('rs', 'rs', 'tr','tr'), cond=c(1,2,1,2), 
block=c(2,4,2,4), mean=c(545,664,703,765))

在df1中,如果correct==0,则引用df2与ID、cond和block的匹配值。将df1 中msec 的值替换为df2 中mean 的对应值。

例如,df1 中的第二行有correct==0。因此,在df2 中找到ID=='rs'、cond==1、block==2 的对应行,并使用平均值 (mean=545) 的值替换毫秒 (msec=678) 的值。请注意,在 df1 中,ID、block 和 cond 的组合可以重复,但每个组合在 df2 中只出现一次。

【问题讨论】:

    标签: r


    【解决方案1】:

    使用data.table 包:

    # load the 'data.table' package
    library(data.table)
    
    # convert the data.frame's to data.table's
    setDT(df1)
    setDT(df2)
    
    # update df1 by reference with a join with df2
    df1[df2[, correct := 0], on = .(ID, cond, block, correct), msec := i.mean]
    

    给出:

    > df1
       ID cond block correct msec
    1: rs    1     2       1  456
    2: rs    1     2       0  545
    3: rs    2     4       1  756
    4: tr    1     2       1  654
    5: tr    1     2       1  625
    6: tr    2     4       0  765
    

    注意:上面的代码会更新df1而不是创建一个新的dataframe,这样更节省内存。

    【讨论】:

    • df1[c(list(correct = 0), df2), on=.(correct, ID, cond, block), msec := i.mean ] ?我想这几乎是一样的。另外值得一提的是,这会更新 df1 而不是创建新表(如 dplyr 变体)。
    • 这很棒。谢谢!
    【解决方案2】:

    一种选择是使用带有interaction() 和match() 的基本R。怎么样:

    df1[which(df1$correct==0),"msec"] <- df2[match(interaction(df1[which(df1$correct==0),c("ID","cond","block")]), 
                                                   interaction(df2[,c("ID","cond", "block")])),
                                             "mean"]
    
    df1
    #        ID cond block correct msec
    #1 rs    1     2       1  456
    #2 rs    1     2       0  545
    #3 rs    2     4       1  756
    #4 tr    1     2       1  654
    #5 tr    1     2       1  625
    #6 tr    2     4       0  765 
    

    我们用df2$mean 中的匹配行覆盖correct == 0 列

    编辑:另一个选项是 sql 合并,这可能看起来像:

    library(sqldf)
    merged <- sqldf('SELECT l.ID, l.cond, l.block, l.correct,
                            case when l.correct == 0 then r.mean else l.msec end as msec
                    FROM df1 as l
                    LEFT JOIN df2 as r
                    ON l.ID = r.ID AND l.cond = r.cond AND l.block = r.block')
    
    
    merged
      ID cond block correct msec
    1 rs    1     2       1  456
    2 rs    1     2       0  545
    3 rs    2     4       1  756
    4 tr    1     2       1  654
    5 tr    1     2       1  625
    6 tr    2     4       0  765
    

    【讨论】:

      【解决方案3】:

      dplyr。此解决方案 left_join 所有列和 mutate 正确时为 0。

      library(dplyr)
      left_join(df1,df2)%>%
      mutate(msec=ifelse(correct==0,mean,msec))%>%
      select(-mean)
      
        ID cond block correct msec
      1 rs    1     2       1  456
      2 rs    1     2       0  545
      3 rs    2     4       1  756
      4 tr    1     2       1  654
      5 tr    1     2       1  625
      6 tr    2     4       0  765
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-13
        • 1970-01-01
        • 1970-01-01
        • 2016-08-18
        相关资源
        最近更新 更多