R: 「group by」操作の高速化 質問する

R: 「group by」操作の高速化 質問する

途中に巨大な集約および結合ステップがあるシミュレーションがあります。私は plyr の ddply() 関数を使用してこのプロセスをプロトタイプ化しましたが、これは私のニーズの大部分にうまく対応しています。しかし、10K のシミュレーションを実行する必要があるため、この集約ステップを高速化する必要があります。私はすでにシミュレーションを並列でスケーリングしていますが、この 1 つのステップが高速化すれば、必要なノードの数を大幅に削減できます。

私がやろうとしていることを合理的に簡略化したものを以下に示します。

library(Hmisc)

# Set up some example data
year <-    sample(1970:2008, 1e6, rep=T)
state <-   sample(1:50, 1e6, rep=T)
group1 <-  sample(1:6, 1e6, rep=T)
group2 <-  sample(1:3, 1e6, rep=T)
myFact <-  rnorm(100, 15, 1e6)
weights <- rnorm(1e6)
myDF <- data.frame(year, state, group1, group2, myFact, weights)

# this is the step I want to make faster
system.time(aggregateDF <- ddply(myDF, c("year", "state", "group1", "group2"),
                     function(df) wtd.mean(df$myFact, weights=df$weights)
                                 )
           )

すべてのヒントや提案を歓迎します!

ベストアンサー1

通常の R データ フレームの代わりに、サブセット化時に元のデータへのポインターを返す不変データ フレームを使用することもできます。これにより、処理速度が大幅に向上します。

idf <- idata.frame(myDF)
system.time(aggregateDF <- ddply(idf, c("year", "state", "group1", "group2"),
   function(df) wtd.mean(df$myFact, weights=df$weights)))

#    user  system elapsed 
# 18.032   0.416  19.250 

この状況にぴったり合うようにカスタマイズされた plyr 関数を書くとしたら、次のようになります。

system.time({
  ids <- id(myDF[c("year", "state", "group1", "group2")], drop = TRUE)
  data <- as.matrix(myDF[c("myFact", "weights")])
  indices <- plyr:::split_indices(seq_len(nrow(data)), ids, n = attr(ids, "n"))

  fun <- function(rows) {
    weighted.mean(data[rows, 1], data[rows, 2])
  }
  values <- vapply(indices, fun, numeric(1))

  labels <- myDF[match(seq_len(attr(ids, "n")), ids), 
    c("year", "state", "group1", "group2")]
  aggregateDF <- cbind(labels, values)
})

# user  system elapsed 
# 2.04    0.29    2.33 

データのコピーを回避し、計算時に各計算に必要なサブセットのみを抽出するため、処理速度が大幅に向上します。データをマトリックス形式に切り替えると、マトリックスのサブセット化はデータ フレームのサブセット化よりもはるかに高速であるため、速度がさらに向上します。

おすすめ記事