0

私はスーパーバイザー向けに単純な初期ゲノム スケール統計を行う関数の単純なコレクションに取り組んできました。これは、より多くの時間を費やす可能性のある将来の分析についてチームに迅速な指示を与えるために簡単に実行できます。たとえば、RDP4 またはBioC (BioConductor に直行しなかった理由を説明するため)。コンティグのサイズを大きくできるようにいくつかの処理を高速化したいので、doParallel と foreach を使用して一部の for ループを編集し、これを可能にすることにしました。以下は、いくつかのシーケンス (行列として格納されている) 内の同一の塩基を識別し、それらを削除する単純な関数の 1 つです。

strip.invar <- function(x) {
  cat("
          Now removing invariant sites from DNA data matrix, this may take some time...
      ")
  prog <- txtProgressBar(min=0, max=ncol(x), style=3)
  removals<-c()
  for(i in 1:ncol(x)){
    setTxtProgressBar(prog, i)
    if(length(unique(x[,i])) == 1) { 
      removals <- append(removals, i)
    }
  }
  newDnaMatrix <- x[,-removals]
  return(newDnaMatrix)
}

doParallel と foreach の紹介を読んだ後、より多くのコアに対応するバージョンを作成しようとしました - 私の Mac ではこれは 8 - コアごとに 2 つのスレッドを持つクアッド コア - 8 つの仮想コア:

strip.invar <- function(x, coresnum=detectCores()){
  cat("
          Now removing invariant sites from DNA data matrix, this may take some time...
          ")
  prog <- txtProgressBar(min=0, max=ncol(x), style=3)
  removals<-c()
  if(coresnum > 1) {
    cl <- makeCluster(coresnum)
    registerDoParallel(cl)
    foreach(i=1:ncol(x)) %dopar% {
      setTxtProgressBar(prog, i)
      if(all(x[,i] == x[[1,i]])){
        removals <- append(removals, i)
      }
    }
  } else {
    for(i in 1:ncol(x)){
      setTxtProgressBar(prog, i)
      if(length(unique(x[,i])) == 1) { 
        removals <- append(removals, i)
      }
    }
  }
  newDnaMatrix <- x[,-removals]
  return(newDnaMatrix)
}

ただし、これを実行してコア数を 8 に設定すると、うまくいくかどうか完全にはわかりません。プログレス バーが何もしていないのを確認できませんが、画面への印刷やグラフィック デバイスを含むものは扱いにくいと聞いています。 Rでの並列計算を使用しています。しかし、まだ時間がかかるようで、ラップトップが「非常に」熱くなるので、これを正しく行ったかどうかはわかりません。いくつかの例を見た後に試しました(実行に成功しましたビネットの素敵なブートストラップの例)、しかし、私は学習バンプにぶつかるはずです. 余談ですが、人々の意見も聞いてみようと思いました。ループまたは適用が関係する R コードのボトルネックの最適なスピードアップはどれですか?それを並列化するか、Rcpp を使用しますか?

ありがとう。

4

2 に答える 2

0

コルメアンが最初の値に等しいことは、一意の値の数のテストとして十分ではないため、私の他の答えは正しくありませんでした。だからここに別の答えがあります:

を使用してループを最適化できますapply

set.seed(42)
dat <- matrix(sample(1:5,1e5,replace=TRUE),nrow=2)
res1 <- strip.invar(dat)


strip.invar2 <- function(dat) {
  ix <- apply(dat,2,function(x) length(unique(x))>1)
  dat[,ix]}

res2 <- strip.invar2(dat)

all.equal(res1,res2)
#TRUE
library(microbenchmark)
microbenchmark(strip.invar(dat),strip.invar2(dat),times=10)
#Unit: milliseconds
#             expr       min        lq    median       uq      max neval
#strip.invar(dat)  2514.7995 2529.2827 2547.6751 2678.464 2792.405    10
#strip.invar2(dat)  933.3701  945.5689  974.7564 1008.589 1018.400    10

これにより、パフォーマンスが大幅に向上しますが、ベクトル化が可能である場合に達成できるほどではありません。

ここでは、並列化によってパフォーマンスが向上することはありません。これは、各反復がそれ自体で多くのパフォーマンスを必要としないため、並列化のオーバーヘッドによって実際に必要な時間が長くなるためです。ただし、データを分割してチャンクを並行して処理することはできます。

于 2013-03-02T15:10:50.023 に答える
0

まず、実行してみますcl <- makeCluster( coresnum-1 )。マスター R プロセスは既にコアの 1 つを使用しており、スレーブ ジョブからディスパッチして結果を受け取るために使用されているため、スレーブ ジョブ用に 7 つの空きコアがあります。foreach ループの 1 つを効果的にキューに入れ、前のループの 1 つが終了するまで待機するため、ジョブの完了に時間がかかると思います。

次に、非並列環境でこの関数を実行しているコンソールに通常表示されるものは、コンソールに出力されます。各ジョブの出力がスレーブ プロセス コンソールに出力されるだけなので、表示されません。ただし、さまざまな foreach ループからの出力をテキスト ファイルに保存して、それらを調べることができます。コンソール出力を保存する方法の例を次に示します。foreachステートメント内にコードを貼り付けます。

このジョブの実行中はすべてのコアが 100% の容量で動作しているため、ラップトップは非常に熱くなります。

foreachこのパッケージは、単純な並列処理を提供するための優れた関数セットを提供することがわかりました。Rcppはるかに優れたパフォーマンスが得られる可能性があります (!) が、C++ コードをどのように記述しているか、この関数の実行時間と使用頻度はどれくらいですか? こういったことを常に第一に考えています。

于 2013-03-02T13:32:20.563 に答える