【问题标题】:Optimize for loops searching for closest points优化循环搜索最近点
【发布时间】:2021-10-21 19:42:24
【问题描述】:

我正在尝试优化一个耗时太长的 for 循环。我确信它可以优化,但由于我对 R 还很陌生,我不知道该怎么做。

我有两个矩阵,tarU_xsrc_x。对于tarU_x 中的每一行,我想在src_x 中找到最接近的行并分配相同的标签(我在src_y 中有src_x 的标签,tarU_x 的估计标签将在@ 987654329@)。

我使用的是经典的嵌套 for 循环,效率不高,所以我想利用 R 提供的可能性。代码如下:

# Estimate tarU_y
tarU_y <- vector()
for (i in 1:nrow(tarU_x)) {
  tarU_vector <- tarU_x[i,]
  lowest_dist <- Inf
  lowest_dist_class <- -1
  for (j in 1:nrow(src_x)) {
    distance <- dist(rbind(tarU_vector, src_x[j,]))
    if (distance < lowest_dist) {
      lowest_dist <- distance
      lowest_dist_class <- src_y[j]
    }
  }
  tarU_y[i] <- lowest_dist_class
}

编辑

按照 s__ 的建议,我尝试使用 apply,并让它工作,最终得到以下代码:

distances <- apply(src_x, 1, function (y) apply(tarU_x, 1, function(x) dist(rbind(x,y))))
tarU_y <- apply(distances, 1, function(x) src_y[which.min(x)])

但它似乎有点慢,我猜底层代码非常相似。例如,使用 for 循环的测试需要 14 秒,而使用 apply 需要 16 秒。

有关更多信息,我使用的数据是此处提供的数据:https://archive.ics.uci.edu/ml/datasets/Gas+Sensor+Array+Drift+Dataset+at+Different+Concentrations,它分为 10 个不同批次,每个样本有 128 个特征。

【问题讨论】:

  • 请提供一个可重复的小输入数据示例。
  • 试试nabor::knn()

标签: r performance for-loop vectorization


【解决方案1】:

试试library(pracma)中的distmat函数:

library(pracma)
tarU_y <- src_y[max.col(-distmat(tarU_x, src_x))]

编辑:添加基准

使用随机法线矩阵说明:

library(pracma)
library(microbenchmark)

set.seed(123)
tarU_x <- matrix(rnorm(1e4, mean = rep(1:100, 10)), nrow = 100L)
src_x <- matrix(rnorm(2e4, mean = rep(200:1, 10)/2), nrow = 200L)
src_y <- rep(200:1, 10)/2

using.forloop <- function(x1, x2, y1) {
  y2 <- rep(y1[1], nrow(x2))
  for (i in 1:nrow(x2)) {
    lowest_dist <- dist(rbind(x1[1,], x2[i,]))
    for (j in 2:nrow(x1)) {
      distance <- dist(rbind(x1[j,], x2[i,]))
      if (distance < lowest_dist) {
        lowest_dist <- distance
        y2[i] <- y1[j]
      }
    }
  }
  return(y2)
}

using.distmat <- function(x1, x2, y1) {
  return(y1[max.col(-distmat(x2, x1))])
}

all.equal(using.forloop(src_x, tarU_x, src_y), using.distmat(src_x, tarU_x, src_y))
[1] TRUE

microbenchmark(using.forloop(src_x, tarU_x, src_y), using.distmat(src_x, tarU_x, src_y))

Unit: milliseconds
                                expr      min        lq       mean   median        uq      max neval
 using.forloop(src_x, tarU_x, src_y) 415.8176 447.95200 473.345159 462.0715 495.33775 609.8592   100
 using.distmat(src_x, tarU_x, src_y)   2.4413   2.59575   2.779786   2.7072   2.91965   3.8540   100

【讨论】:

    猜你喜欢
    • 2018-01-06
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 2012-12-28
    • 1970-01-01
    • 2011-02-22
    相关资源
    最近更新 更多