関数呼び出しのオーバーヘッドがすごい・・・ような気がした時期が私にもありました(修正)

今、いろんな関数に対してxtsオブジェクトを返すようなラッパー関数群パッケージを作ろうと思っていたのですが、関数呼び出しを一個噛ませただけでオーバーヘッドがすごくてこりゃこのままのやり方だと使いものにならないものができそうだぞと。以下、具体的なコード

library(xts)
data(sample_matrix)
sample.xts <- as.xts(sample_matrix)
#rollapplyの結果をxtsとして返却するだけの関数
hoge <- function(data, width, FUN, ..., by = 1, ascending = TRUE, 
by.column = TRUE, na.pad = FALSE, align = c("center", "left", "right")){
  as.xts(rollapply(sample.xts, width, FUN, ..., by, ascending, by.column, na.pad, align))
}

このhogeと同じ動作を関数なしで書いたものと実行速度を比較すると

> system.time(class(as.xts(rollapply(sample.xts,3,mean))))
   ユーザ   システム       経過  
         0          0          0 
> #関数hogeの実行時間
> system.time(class(hoge(sample.xts,3,mean)))
   ユーザ   システム       経過  
      0.53       0.00       0.55 

ぜ、全然速度が違う。こりゃラッパー関数パッケージは諦めだな・・・


(2011/3/4更新)
・・・と、思った時期が私にもあったのですが、コメント欄でid:yatsutaさんに教えてもらったように引数を明示的に書くようにしたら劇的に速くなった!(そして、hoge関数は遅いだけじゃなくて結果がちがったようだ・・・orz)

具体的には以下のように引数を明示的に指定したhoge2関数を定義。

hoge2 <- function(data, width, FUN, ..., by = 1, ascending = TRUE, 
by.column = TRUE, na.pad = FALSE, align = c("center", "left", "right")){
  as.xts(rollapply(as.zoo(sample.xts), width = width, FUN = FUN, ..., 
    by = by, ascending = ascending, by.column = by.column, na.pad = na.pad, align = align))
}

もう一回実行速度比較をしてみると

> #関数hoge2と同じ動作をする関数の実行時間
> system.time(x.naked <- as.xts(rollapply(sample.xts,3,mean)))
   ユーザ   システム       経過  
         0          0          0 
> #関数hogeの実行時間
> system.time(x.hoge  <- hoge(sample.xts,3,mean))
   ユーザ   システム       経過  
      0.74       0.00       0.74 
> #関数hoge2の実行時間
> system.time(x.hoge2 <- hoge2(sample.xts,3,mean))
   ユーザ   システム       経過  
      0.05       0.00       0.05 

こんな感じで体感でもまぁ我慢できるかなレベルにはなった。結果をチェックしてみると

> head(x.naked)
               Open     High      Low    Close
2007-01-03 50.23041 50.32020 50.14835 50.28260
2007-01-04 50.34164 50.40543 50.23856 50.35487
2007-01-05 50.34625 50.34625 50.19879 50.28269
2007-01-06 50.24997 50.27780 50.10803 50.16919
2007-01-07 50.13733 50.18786 50.02426 50.05368
2007-01-08 50.05418 50.10471 49.92203 49.96442
> head(x.hoge)
               Open     High      Low    Close
2007-01-03 50.23050 50.42096 50.23050 50.33236
2007-01-04 50.37347 50.42096 50.23050 50.33459
2007-01-05 50.37347 50.37347 50.22103 50.33236
2007-01-06 50.24433 50.24433 50.11121 50.18112
2007-01-07 50.13211 50.21561 49.99185 49.99185
2007-01-08 50.03555 50.10363 49.96971 49.98806
> head(x.hoge2)
               Open     High      Low    Close
2007-01-03 50.23041 50.32020 50.14835 50.28260
2007-01-04 50.34164 50.40543 50.23856 50.35487
2007-01-05 50.34625 50.34625 50.19879 50.28269
2007-01-06 50.24997 50.27780 50.10803 50.16919
2007-01-07 50.13733 50.18786 50.02426 50.05368
2007-01-08 50.05418 50.10471 49.92203 49.96442

なぜかhoge関数ではズレてるなぁ…まぁ遅いし結果もいい加減だしこれはなしにしてhoge2のようにちゃんと明示的に引数を書きなさいということだ。