私はdata.table
には比較的精通していますが、dplyr
にはあまり慣れていません。私はいくつかの dplyr
vignettes とSOに現れた例を読んできましたが、これまでのところ私の結論は次のとおりです。
data.table
とdplyr
は、グループ数が多い(> 10-100Kを超える)場合、およびその他の状況(下記のベンチマークを参照)を除いて、速度が同等です。dplyr
はよりアクセスしやすい構文を持っていますdplyr
は、潜在的なDBインタラクションを抽象化します(または、します)。私の頭の中では2.私はdata.table
にかなり精通しているのでそれほど重要ではありませんが、両方に不慣れなユーザーにとってはそれが大きな要因になることを理解しています。 data.table
に精通している人の観点から尋ねられた私の特定の質問には無関係なので、どちらがより直観的であるかについての議論は避けたいと思います。また、「より直感的に」分析を高速化する方法についての議論も避けたいと思います(確かにそうですが、ここでも私が最も興味を持っていることではありません)。
私が知りたいのは、
これまで、私はdplyr
がdata.table
でできることをはるかに超えるものを提供するとは思わなかったので、1つの 最近のSO question はこれについてもう少し考えさせてくれました。これがdplyr
の解法です(Qの終わりにデータ):
dat %.%
group_by(name, job) %.%
filter(job != "Boss" | year == min(year)) %.%
mutate(cumu_job2 = cumsum(job2))
これは私のdata.table
解決策の試みよりはるかに優れていました。そうは言っても、良いdata.table
解決策もまたかなり良いものです(Jean-Robert、Arun、そしてここで私は厳密に最も最適な解決策よりも単一のステートメントを支持しました)。
setDT(dat)[,
.SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)],
by=list(id, job)
]
後者の構文は非常に難解に思えるかもしれませんが、もしあなたがdata.table
に慣れていれば(つまり、もっと難解なトリックのいくつかを使わないのであれば)それは実際にはかなり簡単です。
理想的には、dplyr
やdata.table
の方法がより簡潔になるか、パフォーマンスが大幅に向上するという良い例がいくつかあります。
dplyr
は任意の行数を返すグループ化された操作を許可しません(eddiの質問から、注:これはdplyr 0.5でも実装されるようです)。 @ eddiの質問に対する回答でdo
を使用した場合の回避策を示しています。data.table
はrolling joins(thanks @dholstius)とoverlap joinsをサポートしていますdata.table
は、同じ基本R構文を使いながら二分探索を使うspeedから自動索引付け _までの形式で、式DT[col == value]
またはDT[col %in% values]
の式を最適化します。 詳細と小さなベンチマークについては、ここ を参照してください。dplyr
は標準的な評価版の関数(例えばregroup
、summarize_each_
)を提供します。これはdplyr
のプログラムによる使用を簡単にすることができます(data.table
のプログラムによる使用は間違いなく可能です。data.table
がかなり速くなる場合を除いて、両方のパッケージが「分割適用結合」スタイル分析で同等であることがわかりました。data.table
はdplyr
よりもスケーラビリティが高いことを示しています(最近のパッケージとRの両方のバージョンの最新の機能強化で更新されました)。 unique valuesを得るにはdata.table
の最大6倍の速さです。data.table
が75%速くなりましたが、小規模なグループではdplyr
は40%速くなりました(another SO comments from commentsダナ)。data.table
の主執筆者であるMattは、 data.table
、dplyr
、およびpython pandas
のベンチマークによるグループ化操作を最大20億行(RAM内で最大100GB)) にしています。data.table
が〜8倍速いこれは私が質問セクションで示した最初の例です。
dat <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L), name = c("Jane", "Jane", "Jane", "Jane",
"Jane", "Jane", "Jane", "Jane", "Bob", "Bob", "Bob", "Bob", "Bob",
"Bob", "Bob", "Bob"), year = c(1980L, 1981L, 1982L, 1983L, 1984L,
1985L, 1986L, 1987L, 1985L, 1986L, 1987L, 1988L, 1989L, 1990L,
1991L, 1992L), job = c("Manager", "Manager", "Manager", "Manager",
"Manager", "Manager", "Boss", "Boss", "Manager", "Manager", "Manager",
"Boss", "Boss", "Boss", "Boss", "Boss"), job2 = c(1L, 1L, 1L,
1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("id",
"name", "year", "job", "job2"), class = "data.frame", row.names = c(NA,
-16L))
これは、Arunの回答の概要を説明した上で、dplyrの観点から包括的な回答を試みることです(ただし、優先順位の違いに基づいて多少並べ替えました)。
構文には主観がありますが、data.tableを簡潔にすると習得が難しくなり、読むのが難しくなるという私の主張を支持します。これは、dplyrがはるかに簡単な問題を解決しているためです。
Dplyrがあなたのためにする1つの本当に重要なことはそれが 制約 あなたのオプションであるということです。私は、ほとんどの単一表の問題は、「グループ別」副詞とともに、5つの主要動詞のフィルター、選択、変更、配置および要約だけで解決できると主張します。この制約は、データ操作を学ぶときには大きな助けになります。それは、問題についてのあなたの考えを整理するのに役立つからです。 dplyrでは、これらの各動詞は単一の関数にマップされます。各機能は1つの役割を果たし、単独で理解するのは簡単です。
これらの単純な操作を%>%
と一緒にパイプ処理することによって複雑さを作り出します。これは、投稿Arun linked to の一例です。
diamonds %>%
filter(cut != "Fair") %>%
group_by(cut) %>%
summarize(
AvgPrice = mean(price),
MedianPrice = as.numeric(median(price)),
Count = n()
) %>%
arrange(desc(Count))
これまでにdplyrを見たことがなくても(あるいはR!でさえ)、関数はすべて英語の動詞なので、何が起こっているのかという要旨を得ることができます。英語の動詞の不利な点は、それらが[
よりも多くのタイピングを必要とすることですが、私はそれがより良いオートコンプリートによって大部分軽減されることができると思います。
これは同等のdata.tableコードです。
diamondsDT <- data.table(diamonds)
diamondsDT[
cut != "Fair",
.(AvgPrice = mean(price),
MedianPrice = as.numeric(median(price)),
Count = .N
),
by = cut
][
order(-Count)
]
Data.tableに慣れていない限り、このコードに従うのは難しいです。 (私はまた、私の目には良く見えるような方法で繰り返しの[
をインデントする方法を理解することができませんでした)。個人的には、私が6か月前に書いたコードを見ると、見知らぬ人によって書かれたコードを見ているようなものなので、冗長であれば、わかりやすいコードを好むようになりました。
私が読みやすさをわずかに低下させると思う2つの他のマイナーな要因:
ほとんどすべてのデータテーブル操作は[
を使用するので、何が起こっているのかを理解するために追加のコンテキストが必要です。たとえば、x[y]
は2つのデータテーブルを結合しているのか、それともデータフレームから列を抽出しているのでしょうか。よく書かれたコードでは、変数名は何が起こっているのかを示唆するはずなので、これは小さな問題です。
group_by()
はdplyrでは別の操作であることが好きです。それは計算を根本的に変えるので、私はコードを読み飛ばすとき明らかになるべきであると思う、そしてそれは[.data.table
へのby
引数よりgroup_by()
を見つけるのが簡単である。
私はまた、 パイプ がただひとつのパッケージに限定されていないのも好きです。あなたのデータを tidyr で片付けることから始めて、そして ggvis の中のプロットで終わることができます。そして、あなたは私が書いたパッケージに限定されていません - 誰でもデータ操作パイプのシームレスな部分を形成する関数を書くことができます。実際、私は以前のdata.tableコードを%>%
に書き換えたほうが好きです。
diamonds %>%
data.table() %>%
.[cut != "Fair",
.(AvgPrice = mean(price),
MedianPrice = as.numeric(median(price)),
Count = .N
),
by = cut
] %>%
.[order(-Count)]
そして%>%
を使ったパイプの考え方はデータフレームだけではなく、他のコンテキストに簡単に一般化されます: インタラクティブウェブグラフィック 、 ウェブスクレイピング 、 要旨 、 ランタイムコントラクト 、...)
私にとって、それらはそれほど重要ではないので、私はこれらをまとめました。ほとんどのRユーザーは100万行をはるかに下回るデータを処理しますが、dplyrはそのサイズのデータには十分な速度で処理時間はわかりません。私たちはメディアデータの表現力のためにdplyrを最適化します。大きなデータでは、data.tableをそのままの速度で使用してください。
Dplyrの柔軟性は、同じ構文を使用してパフォーマンス特性を簡単に調整できることも意味します。データフレームバックエンドでのdplyrのパフォーマンスがあなたにとって十分ではない場合、data.tableバックエンドを使うことができます(多少制限された機能のセットではありますが)。作業中のデータがメモリに収まらない場合は、データベースバックエンドを使用できます。
そうは言っても、dplyrのパフォーマンスは長期的に向上するでしょう。基数の順序付けや結合とフィルタに同じインデックスを使用するなど、data.tableの素晴らしいアイデアを確実に実装します。私たちは並列化にも取り組んでいるので、複数のコアを利用することができます。
2015年に取り組む予定のものがいくつかあります。
fread()
と同様に、ファイルをディスクからメモリに取り込むのを容易にするためのreadr
パッケージ。
非等結合のサポートを含む、より柔軟な結合。
ブートストラップサンプル、ロールアップなどのより柔軟なグループ化
私はまた、Rの データベースコネクタ 、 web apis と会話する能力、そして sct html pages をより簡単にすることに時間をかけています。
dplyr
definitelyは、data.table
ができないことを行います。あなたのポイント#3
dplyrは、潜在的なDBインタラクションを抽象化する(またはする)
はあなた自身の質問に対する直接的な答えですが、十分に高いレベルに引き上げられていません。 dplyr
は、複数のデータストレージメカニズムに対する拡張可能なフロントエンドであり、data.table
は単一の拡張機能です。
dplyr
をバックエンドに依存しないインターフェースとして見てください。すべてのターゲットが同じグラマーを使用しており、ターゲットとハンドラーを自由に拡張できます。 data.table
は、dplyr
の観点から、それらのターゲットの1つです。
data.table
がクエリを翻訳して、ディスク上またはネットワーク上のデータストアで動作するSQLステートメントを作成しようとする日は決してないでしょう。
dplyr
はおそらくできることdata.table
はできない、またはできないかもしれない。メモリー内での作業の設計に基づいて、data.table
は、dplyr
よりもはるかに困難な時間をクエリの並列処理に拡張できます。
どちらか一方のパッケージでコーディングするのがはるかに簡単な分析タスクはありますか?パッケージに精通している人向け(つまり、必要なキーストロークの組み合わせと必要な難解性のレベル。良いこと)。
これはパントのように見えるかもしれませんが、本当の答えはノーです。 familiarツールを使用している人は、最も馴染みのあるものか、実際の仕事に適したものを使用しているようです。そうは言っても、特定の読みやすさ、時にはパフォーマンスのレベルを提示したい場合があり、両方の十分なレベルが必要な場合は、すでにより明確な抽象化を行うために別のツールが必要な場合があります。
あるパッケージと別のパッケージで大幅に(つまり2倍以上)効率的に実行される分析タスクはありますか?.
繰り返しますが、いいえ。 data.table
はすべてにおいて効率的であることに優れていますitは、dplyr
が、基礎となるデータストアおよび登録済みハンドラーに制限されるという負担を負います。
これは、data.table
でパフォーマンスの問題が発生した場合、クエリ関数内にあることと、isが実際にdata.table
でボトルネックになっていることを確認できることを意味します。自分でレポートを提出する喜びを獲得しました。これは、dplyr
がdata.table
をバックエンドとして使用している場合にも当てはまります。あなたmay参照somedplyr
からのオーバーヘッドですが、それはあなたのクエリです。
dplyr
にバックエンドのパフォーマンスの問題がある場合は、ハイブリッド評価用の関数を登録するか、(データベースの場合)実行前に生成されたクエリを操作することで回避できます。
plyrがdata.tableよりも優れている場合 への受け入れられた回答も参照してください。