【问题标题】:Parallel distance Matrix in RR中的平行距离矩阵
【发布时间】:2013-06-12 20:32:01
【问题描述】:

目前我正在使用内置函数 dist 来计算我在 R 中的距离矩阵。

dist(featureVector,method="manhattan")

这是当前应用程序的瓶颈,因此想法是并行化此任务(从概念上讲这应该是可能的)

搜索谷歌和这个论坛没有成功。

有人有想法吗?

【问题讨论】:

  • 你能提供一个例子featureVector吗?
  • 特征向量只是一个包含 100 列和大约 2000 行的 data.frame。列是单个维度的值
  • 在我的机器上大约需要 0.05 秒,你呢?我在想任何并行的东西都可能有更长的开销。为了确保您的预期输出是 100×100 矩阵,对吧?
  • 好的,我现在意识到您正在寻找一个 2000×2000 的矩阵。那个在我的机器上需要 0.6 秒,所以并行化可能是一种选择。
  • 我的预期输出是一个 2000x2000 矩阵。所以它需要做 2000*2000*100=400 000 000 次操作。正确的?。如果速度有这样的差异,我的代码可能有错误,尽管我现在看不到它

标签: r matrix parallel-processing distance spatial


【解决方案1】:

我发现 parallelDist 比 dist 快几个数量级,并且在我的 Mac 上使用 Microsoft R Open 3.4.0 时在此过程中消耗的虚拟内存要少得多。一个警告虽然 - 我没有运气在 R 3.3.3 上编译它。它没有将 R 的版本列为依赖项,但我怀疑它是。

【讨论】:

    【解决方案2】:

    您还可以使用 parallelDist 包的parDist 函数,该函数专为并行距离矩阵计算而构建。优点是该软件包可在 Mac OS、Windows 和 Linux 上使用,并且已经支持 39 种不同的距离测量(参见parDist)。

    manhattan 距离的性能比较(系统规格:Mac OS;Intel Core i7,4 核 @ 2.5 GHz 并启用超线程):

    library(parallelDist)
    library(amap)
    library(wordspace)
    library(microbenchmark)
    
    set.seed(123)
    x <- matrix(rnorm(2000 * 100), nrow = 2000, ncol = 100)
    
    microbenchmark(parDist(x, method = "manhattan"),
                   Dist(x, method = "manhattan", nbproc = 8),
                   dist.matrix(x, method = "manhattan"),
                   times = 10)
    
    Unit: milliseconds
                                          expr      min       lq     mean   median       uq      max neval
              parDist(x, method = "manhattan") 210.9478 214.3557 225.5894 221.3705 237.9829 247.0844    10
     Dist(x, method = "manhattan", nbproc = 8) 749.9397 755.7351 797.6349 812.6109 824.4075 844.1090    10
          dist.matrix(x, method = "manhattan") 256.0831 263.3273 279.0864 275.1882 296.3256 311.3821    10
    

    使用更大的矩阵:

    x <- matrix(rnorm(10000 * 100), nrow = 10000, ncol = 100)
    microbenchmark(parDist(x, method = "manhattan"),
    +                Dist(x, method = "manhattan", nbproc = 8),
    +                dist.matrix(x, method = "manhattan"),
    +                times = 10)
    Unit: seconds
                                          expr       min        lq      mean    median        uq       max neval
              parDist(x, method = "manhattan")  6.298234  6.388501  6.737168  6.894203  6.947981  7.221661    10
     Dist(x, method = "manhattan", nbproc = 8) 22.722947 24.113681 24.326157 24.477034 24.658145 25.301353    10
          dist.matrix(x, method = "manhattan")  7.156861  7.505229  7.544352  7.567980  7.655624  7.800530    10
    

    进一步的性能比较可以在parallelDistvignette中找到。

    【讨论】:

      【解决方案3】:

      我是一名 Windows 用户,正在寻找一种有效的方法来计算距离矩阵以在层次聚类中使用它(例如,使用“stats”包中的函数 hclust)。 Dist 函数在 Windows 中不能并行工作,所以我不得不寻找不同的东西,我找到了 Stefan Evert 的 "wordspace" 包,其中包含 @987654322 @ 功能。 你可以试试这段代码:

      X <- data.frame(replicate(1000,sample(0:1,5000,rep=TRUE)))
      system.time(d <- dist(X, method = "manhattan"))
      system.time(d2 <- as.dist( dist.matrix(as.matrix(X), method="manhattan") ))
      

      如您所见,使用 dist.matrix 计算具有 1000 个二进制特征和 5000 个实例的数据帧的距离矩阵要快得多

      这些是我的笔记本电脑 (i7-6500U) 中的结果:

      > system.time(d <- dist(X, method = "manhattan"))
         user  system elapsed 
       151.79    0.04  152.59 
      > system.time(d2 <- as.dist( dist.matrix(as.matrix(X), method="manhattan") ))
         user  system elapsed 
        19.19    0.22   19.56 
      

      这解决了我的问题。在这里您可以查看我找到它的原始线程: http://r.789695.n4.nabble.com/Efficient-distance-calculation-on-big-matrix-td4633598.html

      它不能并行解决,但在很多情况下就足够了。

      【讨论】:

      • dist.matrix 确实非常快,但不适用于 NA。有没有也可以处理 NA 的解决方案?
      【解决方案4】:

      这是您可以走的一条路线的结构。它并不比仅仅使用dist() 函数快,而是花费了很多倍的时间。它确实是并行处理的,但即使计算时间减少到零,启动函数并将变量导出到集群的时间也可能比仅使用dist()

      library(parallel)
      
      vec.array <- matrix(rnorm(2000 * 100), nrow = 2000, ncol = 100)
      
      TaxiDistFun <- function(one.vec, whole.matrix) {
          diff.matrix <- t(t(whole.matrix) - one.vec)
          this.row <- apply(diff.matrix, 1, function(x) sum(abs(x)))
          return(this.row)
      }
      
      cl <- makeCluster(detectCores())
      clusterExport(cl, list("vec.array", "TaxiDistFun"))
      
      system.time(dist.array <- parRapply(cl, vec.array,
                              function(x) TaxiDistFun(x, vec.array)))
      
      stopCluster(cl)
      
      dim(dist.array) <- c(2000, 2000)
      

      【讨论】:

        【解决方案5】:

        R 包amap 为聚类和主成分分析提供了强大的并行化功能。在这些函数中,Dist 方法提供了您正在寻找的功能:以并行方式计算并返回距离矩阵。

        Dist(x, method = "euclidean", nbproc = 8)
        

        上面的代码用 8 个线程计算欧几里得距离。

        【讨论】:

        • R函数,amap::Dist函数是dist的多线程版本(并行化)。我相信这是最好的答案!参考:inside-r.org/packages/cran/amap/docs/Dist
        • 我完全同意,这是最好的答案!
        • 感谢您的回答。但是,我无法确定 amap 的 hcluster() 是否适用于距离矩阵,还是绝对需要原始数据?
        • 手册中的@Maxim.K,它只接受原始数据而不接受dist数据,并且在设置nbproc和method参数后,距离矩阵应该在内部并行计算。参考inside-r.org/packages/cran/amap/docs/hcluster
        • 请注意,根据文档,此包不会在 Windows 上并行化
        【解决方案6】:

        我也在使用较大的距离矩阵并尝试加快计算速度。上面的 Will Benson 说“启动函数并将变量导出到集群的时间可能比仅仅使用更长”时,他可能是正确的。

        但是,我认为这适用于小到中等大小的距离矩阵。请参阅下面的示例,其中使用来自包 amap 的函数 Dist(具有 10 个处理器)、来自包 statsdist 和来自包 fields 的 rdist ,它调用一个 Fortran 函数。第一个示例创建一个 400 x 400 距离矩阵。第二个创建一个 3103 x 3103 距离矩阵。

        require(sp)
        require(fields)
        require(amap)
        data(meuse.grid)
        meuse.gridA <- meuse.grid[1:400, 1:2]
        meuse.gridB <- meuse.grid[, 1:2]
        
        # small distance matrix
        a <- Sys.time()
        invisible(dist(meuse.gridA, diag = TRUE, upper = TRUE))
        Sys.time() - a
        Time difference of 0.002138376 secs
        a <- Sys.time()
        invisible(Dist(meuse.gridA, nbproc = 10, diag = TRUE, upper = TRUE))
        Sys.time() - a
        Time difference of 0.005409241 secs
        a <- Sys.time()
        invisible(rdist(meuse.gridA))
        Sys.time() - a
        Time difference of 0.02312016 secs
        
        # large distance matrix
        a <- Sys.time()
        invisible(dist(meuse.gridB, diag = TRUE, upper = TRUE))
        Sys.time() - a
        Time difference of 0.09845328 secs
        a <- Sys.time()
        invisible(Dist(meuse.gridB, nbproc = 10, diag = TRUE, upper = TRUE))
        Sys.time() - a
        Time difference of 0.05900002 secs
        a <- Sys.time()
        invisible(rdist(meuse.gridB))
        Sys.time() - a
        Time difference of 0.8928168 secs
        

        请注意,当距离矩阵很大 (3103 x 3103) 时,与 dist 相比,使用 Dist 的计算时间如何从 0.09845328 秒减少到 0.05900002 秒。因此,如果您有多个可用处理器,我建议您使用 amap 包中的函数 Dist

        【讨论】:

          猜你喜欢
          • 2022-01-12
          • 2016-12-29
          • 1970-01-01
          • 2013-06-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多