在两个数据帧之间相交多列

时间:2014-05-23 05:28:39

标签: r dataframe

我有两个数据框,每个数据框有2列。例如:

df.1 = data.frame(col.1 = c("a","a","a","a","b","b","b","c","c","d"), col.2 = c("b","c","d","e","c","d","e","d","e","e"))
df.2 = data.frame(col.1 = c("b","b","b","a","a","e"), col.2 = c("a","c","e","c","e","c"))

我正在寻找一种有效的方法来查找df.1中每个col.1 col.2行对的df.2中的行索引。请注意,df.1中的行对可能以相反的顺序出现在df.2中(例如df.1 [1,],这是" a"," b"出现在df.2 [1,] as" b"," a")。这对我来说并不重要。换句话说,只要df.1中的行对以df.2中的任何顺序出现,我希望它的行索引在df.2中,否则它应该返回NA。还有一点需要注意,两个数据帧中的行对都是唯一的 - 这意味着每个行对只出现一次。

因此对于这两个数据帧,返回向量将是:

c(1,4,NA,5,2,NA,3,NA,6,NA)

4 个答案:

答案 0 :(得分:5)

也许使用dplyr包的内容:

首先制作参考框架

  • 使用row_number()有效地按行指数编号。
  • 使用select“翻转”列变量。

两半:

df_ref_top <- df.2 %>% mutate(n=row_number())
df_ref_btm <- df.2 %>% select(col.1=col.2, col.2=col.1) %>% mutate(n=row_number())

然后绑定在一起:

df_ref <- rbind(df_ref_top,df_ref_btm)

左连接并选择向量:

给出你的答案

left_join(df.1,df_ref)$n

答案 1 :(得分:3)

# Per @thelatemail's comment, here's a more elegant approach: 
match(apply(df.1,1,function(x) paste(sort(x),collapse="")),
      apply(df.2,1,function(x) paste(sort(x),collapse="")))

# My original answer, for reference:
# Check for matches with both orderings of df.2's columns
match.tmp = cbind(match(paste(df.1[,1],df.1[,2]), paste(df.2[,1],df.2[,2])),
                  match(paste(df.1[,1],df.1[,2]), paste(df.2[,2],df.2[,1])))

# Convert to single vector of match indices
match.index = apply(match.tmp, 1, 
                    function(x) ifelse(all(is.na(x)), NA, max(x, na.rm=TRUE)))

 [1]  1  4 NA  5  2 NA  3 NA  6 NA

答案 2 :(得分:2)

1)排序/合并首先排序df.2创建df.2.s并附加行号列。然后将此新数据框与df.1合并(已在问题中排序):

df.2.s <- replace(df.2, TRUE, t(apply(df.2, 1, sort)))
df.2.s$row <- 1:nrow(df.2.s)
merge(df.1, df.2.s, all.x = TRUE)$row

结果是:

[1]  1  4 NA  5  2 NA  3 NA  6 NA

2)sqldf 由于dot是SQL运算符,因此将数据框重命名为df1df2。请注意,出于同样的原因,当col_1col_2自动上传到后端数据库时,列名称将转换为df1df2。我们使用df2minmax进行排序,然后将其加入df1(已经排序):

df1 <- df.1
df2 <- df.2

library(sqldf)
sqldf("select b.rowid row
    from df1
    left join 
    (select min(col_1, col_2) col_1, max(col_1, col_2) col_2 from df2) b
    using (col_1, col_2)")$row

已修订一些代码改进。添加了第二个解决方案。

答案 3 :(得分:1)

这里有一个小函数来测试R中的一些循环选项(这不是故意的,但它确实发生了)。

check.rows <- function(data1, data2)
{
  df1 <- as.matrix(data1);df2 <- as.matrix(data2);ll <- vector('list', nrow(df1))
  for(i in seq(nrow(df1))){
    ll[[i]] <- sapply(seq(nrow(df2)), function(j) df2[j,] %in% df1[i,])
  }
  h <- sapply(ll, function(x) which(apply(x, 2, all)))
  sapply(h, function(x) ifelse(is.double(x), NA, x))
}

check.rows(df.1, df.2)
## [1]  1  4 NA  5  2 NA  3 NA  6 NA

df.1df.2的行维度增加时,这是一个基准。考虑到对40行中的每一行进行24次检查,我猜也不错。

> dim(df.11); dim(df.22)
[1] 40  2
[1] 24  2
> f <- function() check.rows(df.11, df.22)
> microbenchmark(f())
## Unit: milliseconds
##  expr      min       lq   median       uq      max neval
##   f() 75.52258 75.94061 76.96523 78.61594 81.00019   100