我有两个数据框,每个数据框有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)
答案 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运算符,因此将数据框重命名为df1
和df2
。请注意,出于同样的原因,当col_1
和col_2
自动上传到后端数据库时,列名称将转换为df1
和df2
。我们使用df2
和min
对max
进行排序,然后将其加入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.1
和df.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