R - 比较两个数据集时如何避免循环?

sda*_*ata 5 loops r vectorization

版本以简化问题

我有两个矩阵:

  • mat1:nrow = 100 000; NcoI位= 5
  • mat2:nrow = 500 000; NcoI位= 5

预期成绩

计算每行mat1与每行之间相似数字的数量mat2:

提案

   Intersection <- function(matrix1, matrix2){
        Intersection = matrix(nrow=nrow(matrix1), ncol=ncol(matrix2)) 
          for(i in 1:nrow(matrix3)) {
            for(j in 1:ncol(matrix3)) {
            Intersection[i,j] = length(intersect(matrix1[i,], matrix2[j,])
           } 
         }   
    return(Intersection) }
Run Code Online (Sandbox Code Playgroud)

题:

如何向量化这个函数以避免循环

数据样本

以下是为了试验解决方案而提供的数据示例:

dput(matrix1)结构(c(1L,20L,2L,1L,7L,2L,22L,12L,2L,27L,3L,35L,16L,3L,32L,4L,37L,35L,17L,33L,5L, 38L,46L,27L,49L),. Dim = c(5L,5L))

dput(matrix2)结构(c(1,14,7,1,7,2,22,12,2,27,7,35,16,3,32,14,39,35,17,32,17, 38,46,20,49),. Dim = c(5L,5L))

42-*_*42- 2

提高处理效率的方法不是丢弃循环,而是检查循环的内部逻辑。在这种情况下,您似乎想要使用 的TARGET第 i 列和mat第 j 列中的相交元素的数量作为偏移量来选取“IF_n”列中的元素并将该项目放置在 (5+i)- 中第 j 行和第 j 列。ifelse当以这种方式描述问题时,我们应该能够摆脱所有这些陈述。(我经常发现,花时间用尽可能清晰的自然语言重述问题是提高效率的关键。)在获取 0 结果来索引第五列时,会涉及到一些模算术运算。

我在询问 df$TARGET[i] 与 mat-column 的交集长度时也存在逻辑问题。df$TARGET[i] 只能是单个数字,因为您使用的是向量索引而不是矩阵索引。(df$TARGET是一个矩阵,所以应该是df$TARGET[,i])

这是我的反建议。我认为它既更符合预期的结果,也可能至少快 5 倍,因为你可以完全消除所有这些ifelse文件夹。)

BDfunc <- function(df, mat){
  for  (i in 1:nrow(df)) {   # print(i)  (use for debugging)
    for (j in 1:ncol(mat)){  # print(j)
     mat[5+i, j]<- df[i , 2 + (
      (length(intersect(df$TARGET[,i], mat[,j])) ) %% 5 )]   }
  }
  return(mat)
}   
 mat <- BDfunc(df, mat)

> mat
          [,1]      [,2]      [,3]      [,4]      [,5]
 [1,] 1.000000 20.000000  2.000000  1.000000  7.000000
 [2,] 2.000000 22.000000 12.000000  2.000000 27.000000
 [3,] 3.000000 35.000000 16.000000  3.000000 32.000000
 [4,] 4.000000 37.000000 35.000000 17.000000 33.000000
 [5,] 5.000000 38.000000 46.000000 27.000000 49.000000
 [6,] 5.855105  2.216690  7.458434  3.120932  2.216690
 [7,] 6.381849  6.381849  6.630405  6.381849  6.630405
 [8,] 2.464372  2.464372  2.464372  5.993037  5.993037
 [9,] 1.614552  1.614552  1.614552  5.507400  1.614552
[10,] 2.088811  2.088811  2.088811  2.088811  5.974585
Run Code Online (Sandbox Code Playgroud)