【问题标题】:double loop matrix instead use of loop R双循环矩阵,而不是使用循环 R
【发布时间】:2019-05-10 14:37:09
【问题描述】:

我是使用 apply/purrr 函数的新手。我不知道何时以及如何使用此功能。我有矩阵的双循环,我想避免它们。有没有办法做到这一点?我必须做这个操作(见下面的代码)

NCols=4
NRows=4

set.seed(1234)
myMat<-matrix(runif(NCols*NRows), ncol=NCols)
myMat

norm=matrix(0,NRows,NCols)

 for (i in 1:nrow(myMat)){
    for (j in 1:nrow(myMat)){
      norm[i,j] <- sum((myMat[i,]-myMat[j,])^2)
    }
  }

谢谢

对@markus 使用 dist 函数是更快的方法。

【问题讨论】:

  • @www 抱歉,我忘记了。它是空矩阵。我更新了代码。谢谢。

标签: r loops for-loop matrix apply


【解决方案1】:

尝试dist,因为您似乎在寻求计算欧几里得距离的平方。

dist(myMat, diag = TRUE, upper = TRUE) ^ 2
#          1         2         3         4
#1 0.0000000 0.7408859 0.9713548 0.9768185
#2 0.7408859 0.0000000 0.8285694 0.1746331
#3 0.9713548 0.8285694 0.0000000 0.3690422
#4 0.9768185 0.1746331 0.3690422 0.0000000

【讨论】:

  • 这令人印象深刻。请在我的回答中查看我的microbenchmarkdist 函数比其他方法快得多。
  • @www 感谢您的基准测试 (+1)。是的,比 OP 的循环有了很大的改进。
【解决方案2】:

我们可以使用expand.grid创建所有索引组合,然后使用map2_dbl循环遍历所有组合,最后创建一个矩阵。

library(purrr)

ind <- expand.grid(1:NRows, 1:NRows)

norm <- matrix(map2_dbl(ind$Var1, ind$Var2, ~sum((myMat[.x,] - myMat[.y,])^2)),
               NRows, NCols)
norm
#           [,1]      [,2]      [,3]      [,4]
# [1,] 0.0000000 0.7408859 0.9713548 0.9768185
# [2,] 0.7408859 0.0000000 0.8285694 0.1746331
# [3,] 0.9713548 0.8285694 0.0000000 0.3690422
# [4,] 0.9768185 0.1746331 0.3690422 0.0000000

类似的想法,但我们也可以使用Vectorize

myfun <- function(x, y) sum((myMat[x,] - myMat[y,])^2)
myfun_v <- Vectorize(myfun)

norm <- matrix(myfun_v(ind$Var1, ind$Var2), NRows, NCols)
norm
#           [,1]      [,2]      [,3]      [,4]
# [1,] 0.0000000 0.7408859 0.9713548 0.9768185
# [2,] 0.7408859 0.0000000 0.8285694 0.1746331
# [3,] 0.9713548 0.8285694 0.0000000 0.3690422
# [4,] 0.9768185 0.1746331 0.3690422 0.0000000

这是当前方法的速度比较,包括另一个答案中的 dist 函数。

library(microbenchmark)

microbenchmark(m1 = {ind <- expand.grid(1:NRows, 1:NRows);
                     matrix(map2_dbl(ind$Var1, ind$Var2, ~sum((myMat[.x,] - myMat[.y,])^2)),
                            NRows,NCols)},
               m2 = {ind <- expand.grid(1:NRows, 1:NRows);
                     myfun <- function(x, y) sum((myMat[x,] - myMat[y,])^2);
                     myfun_v <- Vectorize(myfun);
                     matrix(myfun_v(ind$Var1, ind$Var2), NRows, NCols)},
               m3 = {for (i in 1:nrow(myMat)){
                 for (j in 1:nrow(myMat)){
                   norm <- matrix(0, NRows, NCols);
                   norm[i,j] <- sum((myMat[i,]-myMat[j,])^2)
                 }}},
               m4 = {dist(myMat, diag = TRUE, upper = TRUE)^2}
               )

Unit: microseconds
 expr      min        lq      mean    median        uq       max neval cld
   m1  261.142  278.3625  310.1212  302.5230  323.8570   434.894   100  b 
   m2  200.997  238.7805  287.5953  259.5995  286.3305  2417.610   100  b 
   m3 4902.562 5369.8390 5725.5358 5578.2895 5717.8560 10317.123   100   c
   m4   16.451   22.6200   34.1653   32.9010   42.4110    81.222   100 a

【讨论】:

  • @liguang 它可能比for loop 慢,因为map_dbl 需要额外的时间来检查输出是否为数字。
  • 还有比循环更快的方法吗?
  • @liguang 请看我的更新。我不认为我的方法比for循环慢,但是其他人提出的dist函数比我的方法快得多。请考虑使用dist函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-21
  • 1970-01-01
  • 2021-12-31
  • 2012-02-21
  • 2014-10-02
  • 2018-01-30
相关资源
最近更新 更多