私の研究で遭遇する繰り返し分析パラダイムは、すべての異なるグループ ID 値に基づいてサブセット化し、各グループに対して順番に統計分析を実行し、さらに処理/要約するために結果を出力マトリックスに入れる必要があるというものです。
通常、R でこれを行う方法は次のようなものです。
data.mat <- read.csv("...")
groupids <- unique(data.mat$ID) #Assume there are then 100 unique groups
results <- matrix(rep("NA",300),ncol=3,nrow=100)
for(i in 1:100) {
tempmat <- subset(data.mat,ID==groupids[i])
# Run various stats on tempmat (correlations, regressions, etc), checking to
# make sure this specific group doesn't have NAs in the variables I'm using
# and assign results to x, y, and z, for example.
results[i,1] <- x
results[i,2] <- y
results[i,3] <- z
}
これでうまくいきましたが、データのサイズと作業しているグループの数によっては、最大 3 日かかる場合があります。
並列処理に分岐する以外に、このようなものをより速く実行するための「トリック」はありますか? たとえば、ループを別のもの (ループ内で実行したい統計を含む関数を適用するようなもの) に変換したり、データのサブセットを実際に変数に割り当てる必要をなくしたりしますか?
編集:
おそらくこれは一般的な知識 (またはサンプリング エラー) にすぎませんが、コードの一部で、subset コマンドを使用するのではなく、ブラケットを使用してサブセット化を試みたところ、パフォーマンスがわずかに向上したようで、驚きました。上記と同じオブジェクト名を使用して、以下に使用および出力したコードがいくつかあります。
system.time(for(i in 1:1000){data.mat[data.mat$ID==groupids[i],]})
user system elapsed 361.41 92.62 458.32
system.time(for(i in 1:1000){subset(data.mat,ID==groupids[i])})
user system elapsed 378.44 102.03 485.94
アップデート:
回答の 1 つで、jorgusch は、data.table パッケージを使用してサブセット化を高速化することを提案しました。それで、今週初めに実行した問題にそれを適用しました。1,500,000 を少し超える行と 4 つの列 (ID、Var1、Var2、Var3) を持つデータセットで、各グループ (「ID」変数でインデックス付け) で 2 つの相関を計算したいと考えました。50,000 をわずかに超えるグループがあります。以下は私の最初のコードです(これは上記と非常に似ています):
data.mat <- read.csv("//home....")
groupids <- unique(data.mat$ID)
results <- matrix(rep("NA",(length(groupids) * 3)),ncol=3,nrow=length(groupids))
for(i in 1:length(groupids)) {
tempmat <- data.mat[data.mat$ID==groupids[i],]
results[i,1] <- groupids[i]
results[i,2] <- cor(tempmat$Var1,tempmat$Var2,use="pairwise.complete.obs")
results[i,3] <- cor(tempmat$Var1,tempmat$Var3,use="pairwise.complete.obs")
}
どれくらいの時間がかかったかを正確に測定するために、今それを再実行していますが、覚えている限り、朝オフィスに着いたときに実行を開始し、午後半ばに終了しました。図 5-7 時間。
data.table を使用するようにコードを再構築しています....
data.mat <- read.csv("//home....")
data.mat <- data.table(data.mat)
testfunc <- function(x,y,z) {
temp1 <- cor(x,y,use="pairwise.complete.obs")
temp2 <- cor(x,z,use="pairwise.complete.obs")
res <- list(temp1,temp2)
res
}
system.time(test <- data.mat[,testfunc(Var1,Var2,Var3),by="ID"])
user system elapsed 16.41 0.05 17.44
data.table を使用した結果を for ループを使用してすべての ID をサブセット化し、結果を手動で記録した結果と比較すると、同じ答えが得られたようです (ただし、もう少し徹底的に確認する必要があります)。かなりのスピードアップになりそうです。
更新 2:
サブセットを使用してコードを実行すると、最終的に再び終了しました。
user system elapsed 17575.79 4247.41 23477.00
更新 3:
同じく推奨された plyr パッケージを使用して、何かが異なって機能するかどうかを確認したかったのです。これは初めての使用なので、多少効率が悪いかもしれませんが、サブセット化された for ループに比べてかなり役に立ちました。
以前と同じ変数と設定を使用して...
data.mat <- read.csv("//home....")
system.time(hmm <- ddply(data.mat,"ID",function(df)c(cor(df$Var1,df$Var2, use="pairwise.complete.obs"),cor(df$Var1,df$Var3,use="pairwise.complete.obs"))))
user system elapsed 250.25 7.35 272.09