【问题标题】:Vectorization in R with double forR中的向量化与double for
【发布时间】:2017-09-21 15:33:50
【问题描述】:

我已经使用 R 练习了 1 年,现在我面临一个新问题,称为:矢量化。基本上我希望我的代码更快。 这是我的问题: 我有一个 0 和 1 的矩阵,我想将每一行与其他行进行比较,以在同一位置找到匹配项。 例如,我的矩阵是:a<-matrix(c(1,1,1,0,1,1,0,1,0,1,0,1,0,0,0),5,3)。在这种情况下,第一行和第二行有一个匹配,第一行和第三行有三个匹配。我想建立一个对称矩阵行维,并在每个地方写匹配的总和,对角线上为 0。

我写的代码是:

a<-matrix(sample(c(0,1), size=18, replace=T), ncol=3) # a random matrix 6x3

mat<-diag(0,nrow=dim(a)[1])

n<-dim(a)[1]

for( i in 1:(n-1)){
   for (j in (i+1):n){
       mat[i,j]<-sum(ifelse(a[i,]==a[j,],1,0))
    }}

我正在寻找一些东西来改进此代码并删除 for 循环。 我正在申请,但它适用于除倒数第二行和最后一行之外的所有内容:

for( i in 1:(n-2)){
   vv<-a[(i+1):n,]
   mat3[i,(i+1):n]<-apply(vv,1,function(x) sum(ifelse(x==a[i,],1,0)))
}

我必须在 for 循环中放入 2 而不是 1,因为 apply 仅适用于矩阵而不适用于数组(实际上最终 vv 将是一个数组)。 提前谢谢你。

【问题讨论】:

    标签: r for-loop vectorization apply


    【解决方案1】:

    不确定这是否比您的方法更快,但这是我的方法。首先,列出您想要的所有组合。

    coms <- combn(1:nrow(a), 2) # combn from utils package
    coms
    #     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
    #[1,]    1    1    1    1    2    2    2    3    3     4
    #[2,]    2    3    4    5    3    4    5    4    5     5
    

    因此,第一列将比较 1 到 2,第二列将比较 1 到 3,依此类推。

    现在,编写一个函数来计算公共给定向量长度 2 中的元素数,该向量表示行索引。

    funky <- function(com){
      sum(a[com[1], ] == a[com[2], ])
    }
    funky(c(1, 2))
    # [1] 1
    funky(c(1, 3))
    # [1] 3
    

    现在将此函数应用于组合矩阵。

    apply(coms, 2, funky)
    # [1] 1 3 1 3 1 1 1 1 3 1
    

    如果你喜欢在你的矩阵输出中使用这个

    mat <- diag(0, nrow = nrow(a))
    mat[lower.tri(mat, diag = FALSE)] <- apply(coms, 2, funky)
    t(mat)
    #      [,1] [,2] [,3] [,4] [,5]
    # [1,]    0    1    3    1    3
    # [2,]    0    0    1    1    1
    # [3,]    0    0    0    1    3
    # [4,]    0    0    0    0    1
    # [5,]    0    0    0    0    0
    

    【讨论】:

    • 这绝对比for 循环快。在 100x100 矩阵上,它大约快 4 倍。使用sum(a[com[1], ] == a[com[2], ]) 似乎性能更好,但只有几毫秒。
    • 谢谢@Benjamin。你是对的,这不仅应该稍微快一点,而且更容易阅读和理解。我已根据您的建议更新了我的答案。
    【解决方案2】:

    你可以简单地做tcrossprod(a) + tcrossprod(1 - a)

    【讨论】:

      【解决方案3】:

      这个怎么样...

      a <- matrix(c(1,1,1,0,1,1,0,1,0,1,0,1,0,0,0), 5, 3)
      
      b <- apply(a, 1, function(r) apply(a, 1, function(s) sum(r==s)))
      diag(b) <- 0
      
      b
           [,1] [,2] [,3] [,4] [,5]
      [1,]    0    1    3    1    3
      [2,]    1    0    1    1    1
      [3,]    3    1    0    1    3
      [4,]    1    1    1    0    1
      [5,]    3    1    3    1    0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-22
        • 1970-01-01
        • 2020-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多