6

私は data.tables を初めて使用するので、これが非常に基本的な質問である場合は申し訳ありません。

data.tables を使用すると、大量のデータを処理する際の計算時間が大幅に短縮されると聞いたので、data.tables が rollapply 関数の高速化に役立つかどうかを確認したいと思います。

単変量データがある場合

xts.obj <- xts(rnorm(1e6), order.by=as.POSIXct(Sys.time()-1e6:1), tz="GMT") 
colnames(xts.obj) <- "rtns" 

幅が 100 で ap が 0.75 の単純なローリング分位点では、驚くほど長い時間がかかります...

つまり、コード行

xts.obj$quant.75 <- rollapply(xts.obj$rtns,width=100, FUN='quantile', p=0.75) 

永遠にかかりそうだ…

物事をスピードアップするためにdata.tableができることはありますか? つまり、適用できる一般的なロール機能はありますか?

おそらく、xts オブジェクトを data.table オブジェクトに変換して関数を高速に実行し、最後に xts に再変換するルーチンでしょうか?

前もって感謝します

ほら

ps data.table メーリング リストであまり反応がないようだったので、ここに投稿して、より良い反応が得られるかどうかを確認します。

pps がデータフレームを使用した別の例を簡単に試してみると、data.table ソリューションは rollapply 関数よりも時間がかかるようです。つまり、以下に示します。

> x <- data.frame(x=rnorm(10000))
> x.dt <- data.table(x)
> system.time(l1 <- as.numeric(rollapply(x,width=10,FUN=quantile,p=0.75)))   
   user  system elapsed 
   2.69    0.00    2.68 
> system.time(l <- as.numeric(unlist(x.dt[,lapply(1:((nrow(x.dt))-10+1), function(i){ x.dt[i:(i+10-1),quantile(x,p=0.75)]})])))
   user  system elapsed 
  11.22    0.00   11.51 
> identical(l,l1)
[1] TRUE
4

2 に答える 2

8

datatable はここではまったく関係ありません。基本的sapplyにベクトルで実行しています。これは、取得できる最も高速な操作です (C に行く以外)。データ フレームとデータ テーブルは常にベクトルより遅くなります。ストレート ベクトル (xts ディスパッチなし) を使用することで少し得をすることができますが、これをすばやく実行する唯一の簡単な方法は、並列化することです。

> x = as.vector(xts.obj$rtns)
> system.time(unclass(mclapply(1:(length(x) - 99),
                      function(i) quantile(x[i:(i + 99)], p=0.75), mc.cores=32)))
   user  system elapsed 
325.481  15.533  11.221 

それをさらに速くする必要がある場合は、特殊な関数を作成することをお勧めします。単純な適用アプローチでは、すべてのチャンクが再ソートされますが、これは明らかに無駄です。1 つの要素を削除して、次の要素をソートするだけで取得できます。これを行うと、約 50 倍のスピードアップが期待できますが、自分でコーディングする必要があります (したがって、より頻繁に使用する場合にのみ価値があります ...)。

于 2012-08-28T03:26:32.820 に答える
5

data.tableデータをキーで分割することにより、すばやく動作します。data.table現在、ローリング キー、またはこれを行うbyまたはi引数内の式はサポートされていないと思います。

data.tableサブセット化がより高速であるという事実を利用できますdata.frame

DT <- as.data.table(x)
.x <- 1:(nrow(DT)-9)
system.time(.xl <- unlist(lapply(.x, function(.i) DT[.i:(.i+10),quantile(x,0.75, na.rm = T)])))
   user  system elapsed 
   8.77    0.00    8.77 

または、ローリング ID を一意に識別するキー変数を作成することもできます。幅 = 10 なので、10 列が必要です ( で埋められますNA_real_)

library(plyr) # for as.quoted
.j <- paste0('x',1:10, ':= c(rep(NA_real_,',0:9,'),rep(seq(',1:10,',9991,by=10),each=10), rep(NA_real_,',c(0,9:1),'))')


 datatable <- function(){
   invisible(lapply(.j, function(.jc) x.dt[,eval(as.quoted(.jc)[[1]])]))
x_roll <- rbind(x.dt[!is.na(x1),quantile(x,0.75),by=x1],
  x.dt[!is.na(x2),quantile(x,0.75),by=x2],
  x.dt[!is.na(x3),quantile(x,0.75),by=x3],
  x.dt[!is.na(x4),quantile(x,0.75),by=x4],
      x.dt[!is.na(x5),quantile(x,0.75),by=x5],
      x.dt[!is.na(x6),quantile(x,0.75),by=x6],
      x.dt[!is.na(x7),quantile(x,0.75),by=x7],
      x.dt[!is.na(x8),quantile(x,0.75),by=x8],
      x.dt[!is.na(x9),quantile(x,0.75),by=x9],
      x.dt[!is.na(x10),quantile(x,0.75),by=x10],use.names =F)


setkeyv(x_roll,'x1')

invisible(x.dt[,x1:= 1:10000])
setkeyv(x.dt,'x1')
x_roll[x.dt][, list(x,V1)]}

l1 <- function()as.numeric(rollapply(x,width=10,FUN=quantile,p=0.75))
lapply_only <- function() unclass(lapply(1:(nrow(x) - 9), function(i) quantile(x[['x']][i:(i + 9)], p=0.75)))


benchmark(datatable(),l1(),lapply_only(), replications = 5)
##            test replications elapsed relative user.self 
## 1   datatable()            5    9.41 1.000000      9.40      
## 2          l1()            5   10.97 1.165781     10.85        
## 3 lapply_only()            5   10.39 1.104145     10.35 

編集 --- ベンチマーク

data.tablerollapply や raw lapply よりも高速です。並列ソリューションをテストできません。

于 2012-08-28T04:09:25.000 に答える