首页 文章

提取其条目对应于另一个数据帧的行的数据帧的行索引

提问于
浏览
4

我已经挣扎了一段时间,我找不到出路 . 这是我的问题 .

我有2个数据帧:

df1 <- data.frame(replicate(3,sample(1:10,20,rep=TRUE)))
    df1
      X1 X2 X3
   1  10  1  9
   2   3  4  2
   3   7  6  8
   4   8 10  7
   5   5  7  5
   6   8  5  9
   7   9  8  4
   8   6  2  7
   9   2  9  6
   10  5  2  9

  df2 <- data.frame(df1[sample(nrow(df1),4), ])
  df2
     X1 X2 X3
  8   6  2  7
  3   7  6  8
  10  5  2  9
  7   9  8  4

我想创建一个长度为(x)=长度(df1)的向量x,每df1行包含df2中相应行的行索引(即df1和df2之间每列的相同精确值) .

考虑一下:

dim(df1)
    [1] 1096188  3 

    dim(df2)
    [1] 256  3

并且df1有几行具有相同的值(即相应的行索引将是相同的),并且原则上df1中的所有行应该找到与df2中的行匹配 .

预期的产出是:

x
   [1] 0 0 2 0 0 0 4 1 0 3

希望这很清楚......

你能帮我吗?

谢谢,

PIERA

4 回答

  • 3

    我试试:

    x <- rownames(df2)[match(do.call(paste, df1), do.call(paste, df2))]
     x[is.na(x)] <- 0
    

    关于它的期望输出有很多讨论;在@CathG解释中,这一行产生它:

    match(do.call(paste, df1), do.call(paste, df2),nomatch=0)
    
  • 6

    这是 data.table 的一个选项:

    require(data.table)
    
    # first set the original orders (data.frame will be sorted when doing setkey)
    setDT(df1)[, ori := .I]
    setDT(df2)[, ind_df2 := .I]
    
    # define keys
    setkey(df1, X1, X2, X3)
    setkey(df2, X1, X2, X3)
    
    # compute the indices of the df1 line in df2
    x <- df2[df1, ind_df2]
    # put the nomatch to 0
    x[is.na(x)] <- 0
    
    # Finally, put the original orders back and delete the variable ori
    x <- x[order(df1$ori)]
    df2 <- df2[order(df2$ind_df2)]
    df1[, ori:=NULL]
    df2[, ind_df2:=NULL]
    

    结果x(包含您的数据):

    x
    #[1] 0 0 2 0 0 0 4 1 0 3
    

    Another, more simple and efficient option, suggested by @Frank:

    setkeyv(setDT(df2)[,ii:=.I],setdiff(names(df2),"ii"))
    x <- df2[df1]$ii
    x[is.na(x)] <- 0
    

    Some benchmark between @nicola answer, @Frank suggestion and my answer, on a 100000 rows df1 and 200 rows df2 ,略微修改了nicola获得所需输出的答案(两个函数都给出了相同的结果,除了需要 as.numeric 为nicola的):

    所以:

    set.seed(17)
    df1 <- data.frame(replicate(3,sample(1:100,100000,rep=TRUE)))
    df2 <- data.frame(df1[sample(nrow(df1),200), ])
    
    nicola <- function(){x<-match(do.call(paste,df1),do.call(paste,df2), nomatch=0)}
    
    cath <- function(){
              dt1 <-data.table(df1); dt1[, ori:=.I]
              dt2 <- data.table(df2); dt2[, ind_df2:=.I]
              setkey(dt1, X1, X2, X3)
              setkey(dt2, X1, X2, X3)
              x <- dt2[dt1, ind_df2]
              x[is.na(x)] <- 0
              x <- x[order(dt1$ori)]
              x
            }
    
    Frank <- function(){dt1 <-data.table(df1);dt2 <- data.table(df2); setkey(setDT(dt2)[,ii:=.I],X1,X2,X3); x <- dt2[dt1]$ii;x[is.na(x)] <- 0}
    
    require(microbenchmark)
    microbenchmark(cath(), Frank(), nicola(), unit="relative", times=100)
        #Unit: relative
        # expr       min        lq     mean    median       uq      max neval cld
      #Frank()  1.000000  1.000000 1.000000  1.000000 1.000000 1.000000   100 a  
      # cath()  3.238195  3.099896 2.438342  2.767165 2.177365 1.447397   100  b 
     #nicola() 13.127820 12.476996 8.761549 10.899191 7.292086 2.783436   100   c
    
  • 0

    我意识到这是一个非常古老的问题的新答案,但是有什么问题

    match(data.frame(t(df1)), data.frame(t(df2)))
    

    ??

    输出是

    [1] NA NA  2 NA NA NA  4  1 NA  3
    

    所以有 NA 而不是 0 s,但我认为这是一个单行,也不需要 do.call() 或其他任何东西 .

  • 0

    在您的示例中,df1中的行在df2中都不匹配(例如,第1行) . 但是,假设他们这样做(也许df1中有多次出现多次行),你可以:

    x <- rep(0, length(df1[, 1]) #initialise
    for(r1 in 1:length(df1[, 1])){
      for(r2 in 1:length(df2[, 1])){
        if(identical(df1[r1,], df2[r2,])){
          x[r1] <- r2
          break
        }
      }
    }
    

    df1中实际上不在df2中的任何行都将保留为值0.也许不是最快的解决方案 - 您需要多少次重复该过程?

相关问题