如何有效地将矩阵的每一行与R中列表的每个部分进行比较?

时间:2014-06-18 00:13:01

标签: r performance list matrix comparison

这是我的意思的一个例子,这段代码输出正确的东西:

list1 = list(c(1,2,3,4), c(5,6,7), c(8,9), c(10, 11))
matrix1 = rbind(c(1,2), c(1,5), c(8, 10))

compare <- function(list.t, matrix.t) {
    pairs <- 0
    for (i in 1:nrow(matrix.t)) {
         for (j in 1:length(list.t)) {
              if (length(intersect(matrix.t[i,], list.t[[j]])) == 2) {
                         pairs <- pairs + 1
              }
         }
    }
    return(pairs / nrow(matrix.t))
}

compare(list1, matrix1) 
# = 0.33333

我希望这是有道理的。我正在尝试使用nx2矩阵,并查看矩阵的每一行中的两个元素是否也在列表的每个部分中找到。因此,在上面的示例中,矩阵的第一行是(1,2),并且该对在列表的第一部分中找到。列表的任何部分均未找到(1,5)或(8,10)对。所以这就是我输出0.3333(1/3)的原因。

我想知道是否有人知道一种方法不使用两个for循环来比较每一行的每一行?我有更大的矩阵和列表,所以这太慢了。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

这项工作不一样吗?您可以在列表上调用sapply并同时与矩阵的所有行进行比较。

> list1 = list(c(1,2,3,4), c(5,6,7), c(8,9), c(10, 11))
> matrix1 = rbind(c(1,2), c(1,5), c(8, 10))

> s <- sapply(seq_along(list1), function(i){
      length(intersect(list1[[i]], matrix1)) == 2
  })
> sum(s)/nrow(matrix1)
# [1] 0.3333333

如果我们调用您的函数f1()以及相同函数sapply的此f2()版本,我们会在速度上获得以下差异。

> library(microbenchmark)
> microbenchmark(f1(), f2())
# Unit: microseconds
#  expr     min       lq  median       uq      max neval
#  f1() 245.017 261.2240 268.843 281.7350 1265.706   100
#  f2() 113.727 117.7045 125.478 135.6945  268.310   100

希望这是您正在寻找的效率提升。

答案 1 :(得分:0)

这是根据您的R高尔夫挑战的精神为您的问题提供的,一个紧凑的可能难以理解的解决方案:

mean( apply(matrix1, 1, 
          function(x) any( {lapply(list1, function(z) {all(x %in% z) } )}) )
     )

[1] 0.3333333

内部lapply测试list1的特定元素是否将两元素向量中的两个项都作为来自matrix1的行传递。然后any函数测试4个元素中的任何元素是否满足特定行的挑战。中间逻辑向量c(TRUE,FALSE,FALSE)mean转换为分数。 (它仍然是两个嵌套循环。)