2

巨大なデータセットの最近傍を計算するために、rdist を繰り返し使用しています。現在、6 列の 634,000 ベクトルのかなり小さな行列があります。

前述のように、rdist を使用して、各ベクトルから他のすべてのベクトルまでの距離を計算しています。各距離の計算は 1 ステップです。さらに、すべてのステップで、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はそれをメモリに保存しようとしますが、それを行うことを検討するには大きすぎます。

上記の機能を改善するにはどうすればよいですか?適用関数をいじってみましたが、何も役に立ちません。すべてを明確に説明できたことを願っています。私の計算が正しければ、最悪の場合、そのコードを実行するのに 1 週​​間以上かかると推測されます。これを処理するための非常に強力なサーバーがあります。ただし、GPU はありません。マルチコアを試したことはありません (12 が利用可能である必要があります) が、コアごとに委任する方法がわかりません。

ご協力ありがとうございました。

4

2 に答える 2

1

いくつかのヒント:

0) line.profiling オプションを指定して Rprof を使用してコードをプロファイリングします。

1) R の行列は列単位です。それらの間でベクトルを比較するため、それらを行列の列として保存すると、はるかに高速になります

2) rdist 関数がどこから来たのかわかりませんが、新しい行列をコピーして作成する as.matrix(rdist(tab[i,],tab)) を避ける必要があります

3) 同じベクトルを 4 回ソートする knn() 関数を最適化できます

4) rdist(tab) だけではないのはなぜですか?

于 2014-03-12T10:06:51.227 に答える
0

だから私はしばらくの間これに取り組んでテストしてきました。同様の問題で立ち往生している他の人のために、コードのさらに最適化された 2 つのバージョンを次に示します。計算時間は大幅に短縮されましたが、データ エントリが多すぎるとまだ爆発します。私の次のステップは、これを Rcpp で実装し、可能であれば利用可能な 12 個のコアを利用することです (最終目標は、妥当な時間枠で 100 万から 200 万のエントリを計算することです)。どちらの点でも最善の方法はわかりませんが、これが私のコードです。お手伝いありがとう!

##################################
##############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)

参考までに、最初のコードの方が速いようです。

于 2014-04-04T08:29:20.297 に答える