web-dev-qa-db-ja.com

data.tableとdplyr:ある人が何かうまくやることができますか、それともできませんか。

概要

私はdata.tableには比較的精通していますが、dplyrにはあまり慣れていません。私はいくつかの dplyr vignettes とSOに現れた例を読んできましたが、これまでのところ私の結論は次のとおりです。

  1. data.tabledplyrは、グループ数が多い(> 10-100Kを超える)場合、およびその他の状況(下記のベンチマークを参照)を除いて、速度が同等です。
  2. dplyrはよりアクセスしやすい構文を持っています
  3. dplyrは、潜在的なDBインタラクションを抽象化します(または、します)。
  4. 機能上の小さな違いがいくつかあります(下記の「例/使用方法」を参照)。

私の頭の中では2.私はdata.tableにかなり精通しているのでそれほど重要ではありませんが、両方に不慣れなユーザーにとってはそれが大きな要因になることを理解しています。 data.tableに精通している人の観点から尋ねられた私の特定の質問には無関係なので、どちらがより直観的であるかについての議論は避けたいと思います。また、「より直感的に」分析を高速化する方法についての議論も避けたいと思います(確かにそうですが、ここでも私が最も興味を持っていることではありません)。

質問

私が知りたいのは、

  1. パッケージに精通している人にとって、どちらか一方のパッケージでコーディングするのがはるかに簡単な分析タスクがありますか(つまり、必要なキーストロークと必要な難解度のレベルの組み合わせ、それぞれが少ないほうがよい)。
  2. 別のパッケージに対して、あるパッケージで実質的に(つまり2倍以上)実行される分析タスクがありますか。

これまで、私はdplyrdata.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に慣れていれば(つまり、もっと難解なトリックのいくつかを使わないのであれば)それは実際にはかなり簡単です。

理想的には、dplyrdata.tableの方法がより簡潔になるか、パフォーマンスが大幅に向上するという良い例がいくつかあります。

  • dplyrは任意の行数を返すグループ化された操作を許可しません(eddiの質問から、注:これはdplyr 0.5でも実装されるようです)。 @ eddiの質問に対する回答でdoを使用した場合の回避策を示しています。
  • data.tablerolling joins(thanks @dholstius)とoverlap joinsをサポートしています
  • data.tableは、同じ基本R構文を使いながら二分探索を使うspeedから自動索引付け _までの形式で、式DT[col == value]またはDT[col %in% values]の式を最適化します。 詳細と小さなベンチマークについては、ここ を参照してください。
  • dplyrは標準的な評価版の関数(例えばregroupsummarize_each_)を提供します。これはdplyrのプログラムによる使用を簡単にすることができます(data.tableのプログラムによる使用は間違いなく可能です。

データ

これは私が質問セクションで示した最初の例です。

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))
663
BrodieG

これは、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 をより簡単にすることに時間をかけています。

351
hadley

質問タイトル ...への直接の応答で.

dplyrdefinitelyは、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でボトルネックになっていることを確認できることを意味します。自分でレポートを提出する喜びを獲得しました。これは、dplyrdata.tableをバックエンドとして使用している場合にも当てはまります。あなたmay参照somedplyrからのオーバーヘッドですが、それはあなたのクエリです。

dplyrにバックエンドのパフォーマンスの問題がある場合は、ハイブリッド評価用の関数を登録するか、(データベースの場合)実行前に生成されたクエリを操作することで回避できます。

plyrがdata.tableよりも優れている場合 への受け入れられた回答も参照してください。

56
Thell