优化(向量化?)对于R中具有嵌套循环的循环

时间:2014-03-11 16:15:24

标签: r optimization for-loop distance neighbours

我正在迭代地使用rdist来计算大数据集的最近邻居。目前我有一个相当小的634,000个向量的矩阵,有6列。

如上所述,我使用rdist计算每个向量与每个其他向量的距离,每个距离计算都是一个步骤。此外,在每个步骤中,我运行一个函数来计算k = 1,2,3,4最近邻居并得到总和(实际上k =所有邻居)。

###My function to compute k nearest neighbours from distance vector

    knn <- function (vec,k) {
      sum((sort(vec)[1:k+1]))
    }

###My function to compute nearest neighbours iteratively for every vector
myfunc <- function (tab) {

  rowsums <- numeric(nrow(tab)) ###Here I will save total sums
  knnsums_log <- matrix(nrow=nrow(tab),ncol=4) ###Matrix for storing each of my kNN sums

  for(i in 1:nrow(tab)) { ###For loop to compute distance and total sums
    q<-as.matrix(rdist(tab[i,],tab))
    rowsums[i] <- rowSums(q)

     for (k in c(1:4)) { ###Nested loop to run my knn function
     knnsums[i,k] <- knn(q,k) 
    }

  }

  return(cbind(rowsums,knnsums_log))
}

数据的样本(这是634k行)

    X1  X2  X3  X4  X5  X6
1   0.00    0.02    0   0   0.02    -0.263309267
2   0.00    0.02    0   0   0.02    -0.171764667
3   0.00    0.02    0   0   0.02    -0.128784869
4   0.00    0.02    0   0   0.02    -0.905651733

对于那些不熟悉函数的人来说rdist在争论之间得到了欧几里德距离。它的工作速度远远快于自定义编写函数。它比dist更适用,因为dist仅在矩阵距离内计算。我在技术上知道这就是我正在做的事情,但是dist尝试将其存储在内存中,甚至考虑这样做也远远不够。

如何让上述工作更好?我尝试过使用应用函数,但没有任何用处。我希望我已经清楚地解释了一切。如果我的数学是正确的,最糟糕的情况是猜测我需要一个多星期来运行该代码。我有非常强大的服务器来处理这个问题。但是没有GPU。我没有尝试过多核(应该有12个可用)但是我再也不知道如何委托每个核心。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

一些提示:

0)使用Rprof和line.profiling选项

分析您的代码

1)R中的矩阵是逐列的。因为你比较它们之间的向量,如果将它们存储为矩阵的列

,它会快得多

2)我不知道rdist函数的来源,但你应该避免复制和创建新矩阵的as.matrix(rdist(tab [i,],tab))

3)你可以优化你的knn()函数,对相同的向量进行4次排序

4)为什么不只是rdist(tab)?

答案 1 :(得分:0)

所以我已经研究了一段时间并进行测试。对于其他遇到类似问题的人来说,这里有两个更优化的代码版本。我已经大大减少了计算时间,但是它仍然因为数据条目太多而爆炸。我的下一步是尝试使用Rcpp实现这一点,并且如果可能的话,使用我可用的12个核心(最终目标是在合理的时间范围内计算1-2百万个条目)。不知道在任何一点上进行的最佳方式,但这是我的代码。谢谢你的帮助!

##################################
##############Optimized code
t.m<-t(test_euclid_log)

knn_log <- function (vec,k) {
  sum(vec[1:k+1])
}
knn_log <- cmpfun(knn_log)

distf <- function(x,t.m) sqrt(colSums((x - t.m)^2))
distf <- cmpfun(distf)

myfunc <- function (tab) {
  rowsums<-numeric(nrow(tab))
  knnsums_log <- matrix(nrow=nrow(tab),ncol=4)
  for(i in 1:nrow(tab)) {
    q<-apply(tab[i,],1,distf,t.m=t.m)
    rowsums[i] <- colSums(q)
    q<-sort(q)
    for (kn in 1:4) {
      knnsums_log[i,kn] <- knn_log(q,kn)             
    }
  }
  return(cbind(rowsums,knnsums_log))
}
myfunc <- cmpfun(myfunc)
system.time(output <- myfunc(t))

我尝试使用申请:

###############Vectorized
myfuncvec <- function (tab) {
  kn<-c(1:4)
  q<-apply(tab,1,distf,t.m=t.m)
  rowsums <- colSums(q)
  q<-sort(q)
  knnsums_log <- vapply(kn,knn_log,vec=q,FUN.VALUE=c(0))        
  return(c(rowsums,knnsums_log))
}
myfuncvec <- cmpfun(myfuncvec)

t1<-split(t,row(t))
system.time(out <- vapply(t1,myfuncvec,FUN.VALUE=c(0,0,0,0,0)))
out <- t(out)

作为参考,第一个代码似乎更快。