6

セル、値、座標の data.frame があります。それは地球環境に存在します。

> head(cont.values)
   cell value   x   y
1 11117    NA -34 322
2 11118    NA -30 322
3 11119    NA -26 322
4 11120    NA -22 322
5 11121    NA -18 322
6 11122    NA -14 322

私のカスタム関数は、個々のセルを計算するのにほぼ 1 秒かかるため (そして計算するセルが数万あるため)、既に値を持つセルの計算を複製したくありません。私の次の解決策はそれを回避しようとします。各セルは独立して計算でき、並列実行を叫ぶことができます。

私の関数が実際に行うことは、指定されたセル番号の値があるかどうかを確認し、それが NA の場合、それを計算して NA の代わりに挿入することです。

apply ファミリーの関数を使用して魔法の関数を実行できます (結果はvalue対応するです)。 内から、問題なく読み書きできます(グローバル環境にあります)。cellapplycont.values

これを ( を使用して) 並行して実行したいのですがsnowfall、個々のコアからこの変数を読み書きすることができません。

質問: 関数を並列で実行するときに、ワーカー (コア) 内からグローバル環境に存在する動的変数を読み書きできるソリューションはどれですか。これを行うためのより良いアプローチはありますか?

4

3 に答える 3

4

労働者が価値について相談する中央店舗のパターンは、CRANのrredisパッケージに実装されています。アイデアは、Redisサーバーがキーと値のペア(グローバルデータフレーム、再実装)のストアを維持することです。ワーカーはサーバーにクエリを実行して、値が計算されているかどうかを確認し(redisGet)、計算されていない場合は計算を行って保存し(redisSet)、他のワーカーが再利用できるようにします。ワーカーはRスクリプトにすることができるため、ワーカーを簡単に拡張できます。これは、非常に優れた代替並列パラダイムです。これは、各結果を「メモ化」するという概念を使用する例です。遅い機能があります(1秒間スリープします)

fun <- function(x) { Sys.sleep(1); x }

の値がすでに計算されているfunかどうかを確認する最初のチェックのバリアントを返す「メモ化」を作成し、計算されている場合はそれを使用しますx

memoize <-
    function(FUN)
{
    force(FUN) # circumvent lazy evaluation
    require(rredis)
    redisConnect()
    function(x)
    {
        key <- as.character(x)
        val <- redisGet(key)
        if (is.null(val)) {
            val <- FUN(x)
            redisSet(key, val)
        }
        val
    }
}

次に、機能をメモします

funmem <- memoize(fun)

じゃ、行け

> system.time(res <- funmem(10)); res
   user  system elapsed 
  0.003   0.000   1.082 
[1] 10
> system.time(res <- funmem(10)); res
   user  system elapsed 
  0.001   0.001   0.040 
[1] 10

これには、Rの外部で実行されているredisサーバーが必要ですが、インストールは非常に簡単です。rredisパッケージに付属のドキュメントを参照してください。

R内並列バージョンは

library(snow)
cl <- makeCluster(c("localhost","localhost"), type = "SOCK")
clusterEvalQ(cl, { require(rredis); redisConnect() })
tasks <- sample(1:5, 100, TRUE)
system.time(res <- parSapply(cl, tasks, funmem))
于 2011-06-06T16:49:41.493 に答える
4

もちろん、問題の機能が何であるかにもよりますが、それはsnowfallあまり役に立たないのではないかと心配しています。つまり、データフレーム全体をさまざまなコアにエクスポートし (「 」を参照?sfExport)、それを結合する方法を見つける必要があります。おそらくメモリ使用量をできるだけ低く抑えたいので、グローバル環境で値を変更するという目的全体に勝るものはありません。

の低レベル関数snowに飛び込んで、これを機能させることができます。次の例を参照してください。

#Some data
Data <- data.frame(
  cell = 1:10,
  value = sample(c(100,NA),10,TRUE),
  x = 1:10,
  y = 1:10
)
# A sample function
sample.func <- function(){
    id <- which(is.na(Data$value)) # get the NA values

    # this splits up the values from the dataframe in a list
    # which will be passed to clusterApply later on.
    parts <- lapply(clusterSplit(cl,id),function(i)Data[i,c("x","y")])

    # Here happens the magic
    Data$value[id] <<-
    unlist(clusterApply(cl,parts,function(x){
        x$x+x$y
      }
    ))
}
#now we run it
require(snow)
cl <- makeCluster(c("localhost","localhost"), type = "SOCK")
sample.func()
stopCluster(cl)
> Data
   cell value  x  y
1     1   100  1  1
2     2   100  2  2
3     3     6  3  3
4     4     8  4  4
5     5    10  5  5
6     6    12  6  6
7     7   100  7  7
8     8   100  8  8
9     9    18  9  9
10   10    20 10 10

ただし、コアにデータを取得するには、データ (の一部) をコピーする必要があります。ただし、とにかく低レベルの関数を使用するためsnowfall、データフレームで高レベルの関数を呼び出すと、とにかく発生します。snowfallsnow

さらに、データフレームの 1 つの値を変更すると、データフレーム全体も​​メモリにコピーされることを忘れてはなりません。そのため、値がクラスターから戻ってきたときに値を 1 つずつ追加しても、それほど多くは得られません。いくつかの異なるアプローチを試して、メモリ プロファイリングも実行することをお勧めします。

于 2011-06-06T12:54:44.803 に答える
1

データを他のコアにコピーする必要があるという Joris の意見に同意します。NA良い面としては、 がデータ内にあるかどうか、コア内にあるかどうかを心配する必要はありません。元のdata.frame名前がの場合cont.values:

nnaidx<-is.na(cont.values$value) #where is missing data originally
dfrnna<-cont.values[nnaidx,] #subset for copying to other cores
calcValForDfrRow<-function(dfrRow){return(dfrRow$x+dfrRow$y)}#or whatever pleases you
sfExport(dfrnna, calcValForDfrRow) #export what is needed to other cores
cont.values$value[nnaidx]<-sfSapply(seq(dim(dfrnna)[1]), function(i){calcValForDfrRow(dfrnna[i,])}) #sfSapply handles 'reordering', so works exactly as if you had called sapply

うまく動作するはずです(タイプミスを除く)

于 2011-06-06T13:41:15.390 に答える