使用apply 和duplicated 的解决方案。这个想法是使用apply 循环遍历A1 中的每一行,并使用函数rbind 每行到a1,并使用duplicated 和any 检查是否有任何重复项。
which(apply(A1, 1, function(x) any(duplicated(rbind(x, a1)))))
# [1] 1 3
或者我们可以将所有数字组合成字符串并匹配来自A1 和a1 的字符串。该解决方案的灵感来自 Pkumar 的解决方案。
which(apply(A1, 1, toString) %in% apply(a1, 1, toString))
# [1] 1 3
测试方法
在 Dror Bogin 的答案的评论部分,OP 提出了一个解决方案,即which(duplicated(rbind(a1 ,A1))) - nrow(a1)。此解决方案仅在大矩阵中没有重复项时才有效,例如A1。
例如,考虑以下矩阵,A2,它与 A1 相同,除了三个额外的行,其中两个是重复的。
A2 <- rbind(c(1, 2), c(1, 4), c(1, 3), c(2, 4), c(5, 8), c(4, 3), c(5, 8))
A2 的预期输出也应该是c(1, 3)。但是,当我们使用 OP 的解决方案时,我们会在 7 处获得一个额外的索引。
which(duplicated(rbind(a1 ,A2)))-nrow(a1)
# [1] 1 3 7
但我的解决方案仍会返回 c(1, 3)。
which(apply(A2, 1, function(x) any(duplicated(rbind(x, a1)))))
# [1] 1 3
最后,如果 OP 确定没有任何重复项。我们可以使用下面的代码来进一步简化代码。
which(duplicated(rbind(A1, a1), fromLast = TRUE))
# [1] 1 3
绩效评估
由于 OP 提到现实世界的矩阵是巨大的,因此值得在这里对所有提出的方法进行性能评估。
到目前为止,我们一共有五种方法。
方法一:我提出的“apply-duplicate”方法。
方法2:受PKumar启发的“apply-toString-match”方法
方法 3:PKumar 提出的“do.call-dataframe-match”方法
方法四:Dror Bogin 提出的“for-loop”方法
方法5:tophcito提出的“data.table”方法
下面我使用microbenchmark包进行性能评估。
library(microbenchmark)
library(data.table)
microbenchmark(m1 = {which(apply(A1, 1, function(x) any(duplicated(rbind(x, a1)))))},
m2 = {which(apply(A1, 1, toString) %in% apply(a1, 1, toString))},
m3 = {which(do.call("paste0",data.frame(A1)) %in% do.call("paste0",data.frame(a1)))},
m4 = {v1 = vector()
for(i in 1:nrow(A1)){
b = ifelse(all(a1[1,] == A1[i,]),i,NA)
d = ifelse(all(a1[2,] == A1[i,]),i,NA)
v1 = c(v1,b,d)
}
v1[!is.na(v1)]},
m5 = {a1_dt <- as.data.table(as.data.frame(a1))
A1_dt <- as.data.table(as.data.frame(A1))
setnames(a1_dt, c("x", "y"))
setnames(A1_dt, c("x", "y"))
A1_dt[, id := 1:nrow(A1_dt)]
result <- merge(A1_dt, a1_dt, by = c("x", "y"))
result[, id]})
# Unit: microseconds
# expr min lq mean median uq max neval
# m1 164.498 191.7435 235.6025 215.1320 237.751 1777.094 100
# m2 71.968 82.2490 101.0790 99.2130 112.064 202.024 100
# m3 140.851 165.5265 197.3618 185.3175 206.908 395.824 100
# m4 4734.462 5107.4095 5450.1260 5348.2450 5535.876 8807.847 100
# m5 1286.684 1394.6360 1591.3651 1508.7560 1674.283 4361.256 100
结果显示方法 2 最快,方法 3 次之。方法 2 应该比方法 3 更快是有道理的,因为将对象从矩阵转换为数据框需要一些时间。方法1排在第三位,在我看来仍然是一种性能不错的方法。方法5比上述三种方法要慢,说明虽然data.table是为处理大数据帧而设计的,但是这种情况下不需要使用data.table进行操作。最后,方法 4 是最慢的,表明这种情况下 for 循环是低效的。