我正在迭代地使用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个可用)但是我再也不知道如何委托每个核心。
感谢您的帮助。
答案 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)
作为参考,第一个代码似乎更快。