約300万行と40列のdata.tableがあります。次のSQLモックコードのように、グループ内で降順でこのテーブルを並べ替えたいと思います。
_sort by ascending Year, ascending MemberID, descending Month
_
Data.tableでこれを行うための同等の方法はありますか?これまでのところ、私はそれを2つのステップに分解しなければなりません:
_setkey(X, Year, MemberID)
_
これは非常に高速で、数秒しかかかりません。
_X <- X[,.SD[order(-Month)],by=list(Year, MemberID)]
_
このステップには非常に長い時間がかかります(5分)。
更新:誰かがX <- X[sort(Year, MemberID, -Month)]
を行うためのコメントを作成し、後で削除しました。このアプローチははるかに速いようです:
_user system elapsed
5.560 11.242 66.236
_
私のアプローチ:setkey()then order(-Month)
_ user system elapsed
816.144 9.648 848.798
_
私の質問は今です:sort(Year、MemberID、Month)の後にYear、MemberIdおよびMonthで要約したい場合、data.tableはソート順を認識しますか?
更新2:Matthew Dowleへの応答:
Year、MemberID、Monthを設定したsetkeyの後、グループごとに複数のレコードがあります。私が望むのは、グループごとに要約することです。つまり、X [order(Year、MemberID、Month)]を使用すると、合計はdata.tableのバイナリ検索機能を利用します。
_monthly.X <- X[, lapply(.SD[], sum), by = list(Year, MemberID, Month)]
_
更新3:マシューDはいくつかのアプローチを提案しました。最初のアプローチの実行時間は、order()アプローチよりも高速です。
_ user system elapsed
7.910 7.750 53.916
_
マシュー:私が驚いたのは、ほとんどの場合、月の記号を変換することです。それがなければ、setkeyは非常に高速です。
Data.table v1.9.3の現在の開発バージョンには、2つの新しい関数、つまりsetorder
とsetorderv
が実装されており、まさに必要なことを行います。これらの関数は、data.table
_を参照順に並べ替えます。各列の昇順または降順を選択して、並べ替えを行います。詳細については_?setorder
_をご覧ください。
さらに、DT[order(.)]
はデフォルトで、_data.table
_の代わりに_base:::order
_のinternal fast orderを使用するように最適化されています。これは、setorder
とは異なり、データのコピー全体を作成するため、メモリ効率が低下しますが、ベースの順序を使用して操作するよりも桁違いに高速です。
以下に、setorder
、data.tableの内部高速順序、および_base:::order
_を使用した速度の違いの図を示します。
_require(data.table) ## 1.9.3
set.seed(1L)
DT <- data.table(Year = sample(1950:2000, 3e6, TRUE),
memberID = sample(paste0("V", 1:1e4), 3e6, TRUE),
month = sample(12, 3e6, TRUE))
## using base:::order
system.time(ans1 <- DT[base:::order(Year, memberID, -month)])
# user system elapsed
# 76.909 0.262 81.266
## optimised to use data.table's fast order
system.time(ans2 <- DT[order(Year, memberID, -month)])
# user system elapsed
# 0.985 0.030 1.027
## reorders by reference
system.time(setorder(DT, Year, memberID, -month))
# user system elapsed
# 0.585 0.013 0.600
## or alternatively
## setorderv(DT, c("Year", "memberID", "month"), c(1,1,-1))
## are they equal?
identical(ans2, DT) # [1] TRUE
identical(ans1, ans2) # [1] TRUE
_
このデータでは、ベンチマークはdata.tableの順序が約〜79x速い _base:::order
_であり、setorder
が〜135x速い _base:::order
_こちら。
_data.table
_は常にCロケールでソート/順序付けします。別のロケールで注文する必要がある場合のみ、DT[base:::order(.)]
を使用する必要があります。
これらの新しい最適化と機能はすべて一緒に FR#2405 を構成します。 bit64 :: integer64サポートも追加されました 。
注:以前の回答と更新については、履歴/改訂を参照してください。
コメントは私のものだったので、答えを投稿します。既に持っているものと同等かどうかをテストできなかったため、削除しました。早く聞いて嬉しいです。
X <- X[order(Year, MemberID, -Month)]
要約は、行の順序に依存するべきではありません。