【问题标题】:Speed of Daisy Function菊花函数的速度
【发布时间】:2021-07-01 23:31:52
【问题描述】:

我正在努力提高我正在编写的函数的速度(用于差异度量),它在数学上与欧几里得距离函数非常相似。但是,当我将我的函数与 cluster 包中的 daisy 函数中实现的函数进行比较时,我发现速度上有很大差异,daisy 的性能要好得多。鉴于(我假设)由于需要在所有变量上将每个对象与其自身进行比较(其中n 是对象数量,p 是变量数量),因此差异测量需要 O(n x p) 时间,我相对于我简单直接的实现,很难理解 daisy 函数如何表现得如此出色(从我所做的几个实验来看,接近恒定时间)。我在下面展示了我用来实现和测试的代码。我曾尝试查看r 源代码以实现daisy 函数,但我发现它很难理解。我发现没有嵌套的for 循环。非常感谢任何有助于理解为什么这个函数执行得如此之快以及我如何修改我的代码以具有相似速度的帮助。

euclidean <- function (df){
  
  no_obj <- nrow(df)
  
  dist <- array(0, dim = c(no_obj, no_obj))
  
  for (i in 1:no_obj){
    for (j in 1:no_obj){
      dist_v <- 0
      if(i != j){
        for (v in 1:ncol(df)){
          dist_v <- dist_v + sqrt((df[i,v] - df[j,v])^2)
        }
      }
      dist[i,j] <- dist_v
    }
  }
  return(dist)
}

data("iris")

tic <- Sys.time()
dst <- euclidean(iris[,1:4])
time <- difftime(Sys.time(), tic, units = "secs")[[1]]
print(paste("Time taken [Euclidean]: ", time))

tic <- Sys.time()
dst <- daisy(iris[,1:4])
time <- difftime(Sys.time(), tic, units = "secs")[[1]]
print(paste("Time taken [Daisy]: ", time))

【问题讨论】:

  • 不是专家,但基于source code,“数字运算”是使用 fortran 子例程完成的。我不知道该方法是否使用嵌套的 for 循环(我还没有学过 fortran),但是使用较低级别的语言可以显着加快运行时间。如果您想提高代码的速度,有两个可能的选择:对其进行矢量化(例如stackoverflow.com/questions/10728137/…),或使用较低级别的语言(C/C++/fortran)来完成“繁重的工作”。
  • 我的函数也返回“NULL” - 是不是有错字?
  • @jared_mamrot 哦,非常感谢。我看到了 fortran-y 的东西,但无法真正理解它。我现在正在检查矢量化选项。感谢您指出我忘记返回dist,哈哈。

标签: r performance similarity r-daisy


【解决方案1】:

一个选项:

 euclidean3 <- function(df) {
  require(data.table)
  n <- nrow(df)
  i <- CJ(1:n, 1:n) # generate all row combinations
  dl <- sapply(df, function(x) sqrt((x[i[[1]]] - x[i[[2]]])^2)) # loop over columns
  dv <- rowSums(dl) # sum values of columns
  d <- matrix(dv, n, n) # fill in matrix
  d
}
dst3 <- euclidean3(iris[,1:4])
all.equal(euclidean(iris[,1:4]), dst3) # TRUE

[1] "Time taken [Euclidean3]:  0.008"
[1] "Time taken [Daisy]:  0.002"

代码中最大的瓶颈是在循环中选择 data.frame 元素 (df[j,v]))。也许将其更改为matrix 也可以提高速度。我相信在 stackoverflow 上可能会有更高效的方法,您只需要通过正确的关键字进行搜索...

【讨论】:

  • 非常感谢@minem!这就是我一直在寻找的东西,尽管在我看来,如果我能够使用 FORTRAN 或 C/C++,甚至可以提高速度。我尝试转换为矩阵,但大大增加了运行时间。我认为转换为矩阵的过程(使用as.matrix)并不是那么简单。
猜你喜欢
  • 1970-01-01
  • 2016-03-28
  • 1970-01-01
  • 1970-01-01
  • 2020-06-06
  • 1970-01-01
  • 1970-01-01
  • 2022-10-02
  • 1970-01-01
相关资源
最近更新 更多