20

一般的に言えば、使用し%>%ても速度に目立った影響はないと思いました。ただし、この場合は 4 倍遅くなります。

library(dplyr)
library(microbenchmark)

set.seed(0)
dummy_data <- dplyr::data_frame(
  id=floor(runif(10000, 1, 10000))
  , label=floor(runif(10000, 1, 4))
)

microbenchmark(dummy_data %>% group_by(id) %>% summarise(list(unique(label))))
microbenchmark(dummy_data %>% group_by(id) %>% summarise(label %>% unique %>% list))

パイプなし:

min       lq     mean   median       uq      max neval
1.691441 1.739436 1.841157 1.812778 1.880713 2.495853   100

パイプ付き:

min       lq     mean   median       uq      max neval
6.753999 6.969573 7.167802 7.052744 7.195204 8.833322   100

この状況でなぜ%>%そんなに遅いのですか?これを書く良い方法はありますか?

編集:

データ フレームを小さくし、Moody_Mudskipper の提案をベンチマークに組み込みました。

microbenchmark(
  nopipe=dummy_data %>% group_by(id) %>% summarise(list(unique(label))),
  magrittr=dummy_data %>% group_by(id) %>% summarise(label %>% unique %>% list),
  magrittr2=dummy_data %>% group_by(id) %>% summarise_at('label', . %>% unique %>% list),
  fastpipe=dummy_data %.% group_by(., id) %.% summarise(., label %.% unique(.) %.% list(.))
)

Unit: milliseconds
      expr       min        lq      mean    median        uq      max neval
    nopipe  59.91252  70.26554  78.10511  72.79398  79.29025 214.9245   100
  magrittr 469.09573 525.80084 568.28918 558.05634 590.48409 767.4647   100
 magrittr2  84.06716  95.20952 106.28494 100.32370 110.92373 241.1296   100
  fastpipe  93.57549 103.36926 109.94614 107.55218 111.90049 162.7763   100
4

4 に答える 4

4

それで、私はついにOPの質問で式を実行することに取り掛かりました:

set.seed(0)
dummy_data <- dplyr::data_frame(
  id=floor(runif(100000, 1, 100000))
  , label=floor(runif(100000, 1, 4))
)

microbenchmark(dummy_data %>% group_by(id) %>% summarise(list(unique(label))))
microbenchmark(dummy_data %>% group_by(id) %>% summarise(label %>% unique %>% list))

これには非常に時間がかかったので、バグに遭遇したのではないかと思い、R を強制的に中断しました。

繰り返し回数を減らして再試行すると、次の時間が得られました。

microbenchmark(
    b=dummy_data %>% group_by(id) %>% summarise(list(unique(label))),
    d=dummy_data %>% group_by(id) %>% summarise(label %>% unique %>% list),
    times=2)

#Unit: seconds
# expr      min       lq     mean   median       uq      max neval
#    b 2.091957 2.091957 2.162222 2.162222 2.232486 2.232486     2
#    d 7.380610 7.380610 7.459041 7.459041 7.537471 7.537471     2

時間は秒単位です!ミリ秒またはマイクロ秒についてはこれで終わりです。R が最初にハングアップしたように見えたのも不思議ではありません。デフォルト値はtimes=100です。

しかし、なぜそんなに時間がかかるのですか?まず、データセットの構築方法により、id列には約 63000 の値が含まれます。

length(unique(dummy_data$id))
#[1] 63052

第 2 に、順番に要約される式には複数のパイプが含まれており、グループ化されたデータの各セットは比較的小さくなります。

これは基本的に、パイプ式の最悪のシナリオです。非常に多くの回数が呼び出され、そのたびに、非常に小さな入力セットで処理されます。これにより、多くのオーバーヘッドが発生し、そのオーバーヘッドを償却するための計算はあまり行われません。

対照的に、グループ化および要約される変数を単に切り替えると、次のようになります。

microbenchmark(
    b=dummy_data %>% group_by(label) %>% summarise(list(unique(id))),
    d=dummy_data %>% group_by(label) %>% summarise(id %>% unique %>% list),
    times=2)

#Unit: milliseconds
# expr      min       lq     mean   median       uq      max neval
#    b 12.00079 12.00079 12.04227 12.04227 12.08375 12.08375     2
#    d 10.16612 10.16612 12.68642 12.68642 15.20672 15.20672     2

今では、すべてがより平等に見えます。

于 2018-05-02T16:08:28.680 に答える