回答:
rbindlist
は最適化されたバージョンでありdo.call(rbind, list(...))
、を使用すると低速になることが知られていますrbind.data.frame
どこrbindlist
が輝いているかを示すいくつかの質問
do.callとldplyを使用して、data.framesの長いリスト(約100万)を単一のdata.frameに変換する際の問題
これらには、それがどれほど高速かを示すベンチマークがあります。
rbind.data.frame
多くのチェックを行い、名前で一致します。(つまり、rbind.data.frameは、列が異なる順序にあり、名前で一致する可能性があるという事実を説明します)、rbindlist
この種のチェックを行わず、位置で結合します
例えば
do.call(rbind, list(data.frame(a = 1:2, b = 2:3), data.frame(b = 1:2, a = 2:3)))
## a b
## 1 1 2
## 2 2 3
## 3 2 1
## 4 3 2
rbindlist(list(data.frame(a = 1:5, b = 2:6), data.frame(b = 1:5, a = 2:6)))
## a b
## 1: 1 2
## 2: 2 3
## 3: 1 2
## 4: 2 3
以前はバグが修正されていたため、これに対処するのに苦労しfactors
ていました:
rbindlist 2つのdata.tablesで、1つは因子を持ち、もう1つは列の文字タイプを持ちます(バグ#2650)
列名の重複に関する問題があります
警告メッセージを参照してください :rbindlist(allargs)内:強制によって導入されたNA:data.tableのバグの可能性?(バグ#2384)
rbindlist
lists
data.frames
およびを処理できdata.tables
、行名なしでdata.tableを返します
あなたはdo.call(rbind, list(...))
see を使用して行名の混乱に入ることができます
do.call内でrbindを使用するときに行の名前を変更しないようにするにはどうすればよいですか?
メモリに関してrbindlist
はで実装されているC
ため、メモリ効率がよく、setattr
参照によって属性を設定するために使用されます
rbind.data.frame
はに実装されておりR
、多くの割り当てと使用を行いますattr<-
(そしてclass<-
そのrownames<-
すべてが(内部で)作成されたdata.frameのコピーを作成します。
DF = data.frame(a=1:3); .Internal(inspect(DF)); tracemem(DF); attr(DF,"test") <- "hello"; .Internal(inspect(DF))
。
rbind.data.frame
特別な「ハイジャック」ロジックがあります。最初の引数がの場合、代わりにをdata.table
呼び出し.rbind.data.table
ます。これは、少しチェックを行ってからrbindlist
内部的に呼び出します。したがって、data.table
バインドするオブジェクトがすでにある場合、rbind
とのパフォーマンスの違いはほとんどありませんrbindlist
。
dplyr::rbind_list
これもかなり似ています
によってv1.9.2
、rbindlist
かなり進化し、次のような多くの機能を実装しました。
さらに、ではv1.9.2
、Rに実装されている、欠落している列を埋めることでバインドできるようにする引数rbind.data.table
も取得しfill
ました。
現在ではv1.9.3
、これらの既存の機能がさらに改善されています。
rbindlist
引数を取得しますuse.names
。これは、デフォルトではFALSE
下位互換性のためです。rbindlist
また、引数も取得しますfill
。これは、デフォルトではFALSE
下位互換性のためにも使用されます。- これらの機能はすべてCで実装されており、機能を追加する際に速度が低下しないように注意深く書かれています。
rbindlist
名前で一致し、欠落している列を埋めることができるので、今rbind.data.table
すぐ呼び出すだけrbindlist
です。唯一の違いは、の下位互換性のuse.names=TRUE
ためにrbind.data.table
、デフォルトでになっていることです。
rbind.data.frame
(Cに移動することで)回避できるコピー(@mnelも指摘)が原因で、かなり遅くなります。それが唯一の理由ではないと思います。で列名をチェック/照合するための実装rbind.data.frame
data.frameあたりの列数が多く、バインドするdata.framesが多い場合にも遅くなる可能性があります(以下のベンチマークを参照)。
ただし、rbindlist
特定の機能(因子レベルのチェックや名前のマッチングなど)が欠けている(欠けている)場合、に比べて非常に小さい(またはまったくない)ことに重点が置かれますrbind.data.frame
。これは、速度とメモリを最適化してCで慎重に実装したためです。
以下は、列名で照合しながら、rbindlist
のuse.names
機能を使用して効率的なバインディングを強調するベンチマークですv1.9.3
。データセットは、サイズが10 * 500の10000個のdata.framesで構成されています。
NB:このベンチマークではとの比較含むように更新されたdplyr
のをbind_rows
library(data.table) # 1.11.5, 2018-06-02 00:09:06 UTC
library(dplyr) # 0.7.5.9000, 2018-06-12 01:41:40 UTC
set.seed(1L)
names = paste0("V", 1:500)
cols = 500L
foo <- function() {
data = as.data.frame(setDT(lapply(1:cols, function(x) sample(10))))
setnames(data, sample(names))
}
n = 10e3L
ll = vector("list", n)
for (i in 1:n) {
.Call("Csetlistelt", ll, i, foo())
}
system.time(ans1 <- rbindlist(ll))
# user system elapsed
# 1.226 0.070 1.296
system.time(ans2 <- rbindlist(ll, use.names=TRUE))
# user system elapsed
# 2.635 0.129 2.772
system.time(ans3 <- do.call("rbind", ll))
# user system elapsed
# 36.932 1.628 38.594
system.time(ans4 <- bind_rows(ll))
# user system elapsed
# 48.754 0.384 49.224
identical(ans2, setDT(ans3))
# [1] TRUE
identical(ans2, setDT(ans4))
# [1] TRUE
名前をチェックせずに列をバインドするのにかかった時間は1.3でしたが、列名のチェックとバインドを適切に行うには1.5秒しかかかりませんでした。基本ソリューションと比較して、これはdplyr
のバージョンより14倍高速で、18倍高速です。
attr<-
、class<-
そして(私が思うに)rownames<-
すべてが適切に変更されます。