[解決済み] dplyr on data.table、私は本当にdata.tableを使っているのでしょうか?
質問
もし私が dplyr 構文の上に データテーブル の構文を使用しながら、datatableのすべての速度の利点を得ることができますか?言い換えると、dplyr 構文でクエリを実行すると、datatable を誤って使用することになりますか? または、そのパワーをすべて利用するために、純粋な datatable 構文を使用する必要がありますか。
アドバイスをいただき、ありがとうございます。コード例です。
library(data.table)
library(dplyr)
diamondsDT <- data.table(ggplot2::diamonds)
setkey(diamondsDT, cut)
diamondsDT %>%
filter(cut != "Fair") %>%
group_by(cut) %>%
summarize(AvgPrice = mean(price),
MedianPrice = as.numeric(median(price)),
Count = n()) %>%
arrange(desc(Count))
結果
# cut AvgPrice MedianPrice Count
# 1 Ideal 3457.542 1810.0 21551
# 2 Premium 4584.258 3185.0 13791
# 3 Very Good 3981.760 2648.0 12082
# 4 Good 3928.864 3050.5 4906
以下は、私が思いついたdatatableの等価性です。DTのグッドプラクティスに準拠しているかどうかはわかりません。しかし、私は、このコードが裏でdplyr構文よりも本当に効率的であるかどうか疑問に思っています。
diamondsDT [cut != "Fair"
] [, .(AvgPrice = mean(price),
MedianPrice = as.numeric(median(price)),
Count = .N), by=cut
] [ order(-Count) ]
どのように解決するのですか?
これらのパッケージの哲学はある側面で異なっているため、単純明快な答えはありません。そのため、いくつかの妥協は避けられません。ここでは、対処または考慮する必要がある懸念事項をいくつか紹介します。
以下を含む操作
i
(==
filter()
と
slice()
を含む)
仮定
DT
に10個のカラムがあるとします。これらのdata.table式を考えてみましょう。
DT[a > 1, .N] ## --- (1)
DT[a > 1, mean(b), by=.(c, d)] ## --- (2)
(1)は
DT
ここで、列
a > 1
. (2) リターン
mean(b)
でグループ化された
c,d
にある同じ式に対して
i
を(1)と同じにする。
一般的に使われる
dplyr
の表現になります。
DT %>% filter(a > 1) %>% summarise(n()) ## --- (3)
DT %>% filter(a > 1) %>% group_by(c, d) %>% summarise(mean(b)) ## --- (4)
明らかに、data.tableのコードの方が短いです。加えて、それらは
よりメモリ効率が良い
1
. なぜか?なぜなら,(3)と(4)の両方で
filter()
は
の行を返します。
まず、(3)では行の数だけ、(4)では列の数だけ必要なときに
b, c, d
が必要なだけです。これを克服するために、我々は
select()
の列を事前に作成しておく必要があります。
DT %>% select(a) %>% filter(a > 1) %>% summarise(n()) ## --- (5)
DT %>% select(a,b,c,d) %>% filter(a > 1) %>% group_by(c,d) %>% summarise(mean(b)) ## --- (6)
2つのパッケージの間の主要な哲学的な違いを強調することが不可欠です。
で
data.table
を見ると、これらの関連する操作を一緒にしておきたいと思います。j-expression
(同じ関数呼び出しから)を見て、(1)の列が必要ないことに気づくことができます。の式はi
の式は計算され.N
は単に行数を与える論理ベクトルの和であり、部分集合全体が実現されることはない。(2)では、単に列b,c,d
だけがサブセットで実現され、他の列は無視されます。しかし
dplyr
では、関数が正確に1つのことを行うことが哲学です。 さて . の後の演算がうまくいくかどうかを判断する方法は(少なくとも今のところ)ありません。filter()
の後のオペレーションがフィルタリングした全てのカラムを必要とするかどうかを知る方法は(少なくとも現在は)ありません。このような作業を効率的に行いたいのであれば、先のことを考える必要があるでしょう。個人的にはこの場合、逆に直感的だと思います。
なお、(5)(6)では、まだサブセット列の
a
をサブセットしていることに注意してください。しかし、それを回避する方法はよくわからない。もし
filter()
関数に返す列を選択する引数があれば、この問題を避けることができますが、その場合、関数は1つのタスクだけを行うわけではありません(これはdplyrの設計上の選択でもあります)。
参照によるサブアサイン
dplyrは 決して を参照によって更新しません。これは、2つのパッケージの間のもう1つの大きな(哲学的な)違いです。
例えば、data.tableでは、こんなことができます。
DT[a %in% some_vals, a := NA]
カラムを更新する
a
参照で
を、条件を満たすこれらの行だけに適用します。現時点では、dplyrは新しい列を追加するために内部的にdata.table全体を深くコピーしています。@BrodieGは彼の回答ですでにこれに言及しました。
しかし、ディープコピーをシャローコピーに置き換えることができるのは、次のような場合です。 FR #617 が実装されている場合、ディープコピーをシャローコピーに置き換えることができます。また、関連する dplyr: FR#614 . それでも、あなたが変更したカラムは常にコピーされることに注意してください(したがって、より遅く/より少ないメモリ効率)。参照によってカラムを更新する方法はありません。
その他の機能
-
data.tableでは、結合しながら集約することができます。これはより分かりやすく、中間結合結果が実体化しないのでメモリ効率も良いです。確認 この記事 を参照してください。dplyrのdata.table/data.frame構文を使用してそれを行うことはできません(現時点では)。
-
data.tableの ローリングジョイン の機能は、dplyrの構文でもサポートされていません。
-
私たちは最近、data.tableにオーバーラップジョインを実装し、区間範囲にわたって結合するようにしました ( はその例です。 ) を実装しましたが、これは別の関数
foverlaps()
であり、したがってパイプ演算子(magrittr / pipeR? - 自分で試したことはありません)と一緒に使うことができます。しかし、最終的には、私たちの目標は、それを
[.data.table
に統合して、グループ化、集約、結合などのような他の機能を利用できるようにすることですが、これには上記のような制限があります。 -
1.9.4 以降、data.table は、通常の R 構文に基づくサブセットの高速なバイナリ検索用に、セカンダリキーを使用した自動インデックス作成を実装しています。例
DT[x == 1]
とDT[x %in% some_vals]
は、最初の実行で自動的にインデックスを作成し、それを同じ列からの連続したサブセットでバイナリサーチを使って高速にサブセットを作成します。この機能は今後も進化していく予定です。チェック この gist をご覧ください。方法から
filter()
がdata.tablesで実装されていることから、この機能を利用することはできません。 -
dplyrの特徴として、data.tablesの他に データベースへのインタフェース を提供することです。data.tableには今のところありません。
したがって、これら(およびおそらく他の点)を比較検討し、これらのトレードオフがあなたにとって許容できるかどうかに基づいて決定する必要があります。
ありがとうございました。
(1) ほとんどの場合、ボトルネックはメイン メモリからキャッシュにデータを移動すること (およびキャッシュ内のデータをできる限り使用し、キャッシュ ミスを減らすことで、メイン メモリへのアクセスを減らすこと) なので、メモリ効率は (特にデータが大きくなるほど) 速度に直接影響することに留意してください。詳細についてはここでは触れません。
関連
-
[R] is.data.frame(x) のエラー : (リスト) オブジェクトを 'double' 型に強制できない。
-
DEG解析で'row.names'に重複した名前を付けられない場合の解決法
-
[解決済み] 関数のソースコードを見るにはどうしたらいいですか?
-
[解決済み] 不足しているパッケージをチェックし、インストールするためのエレガントな方法?
-
[解決済み] Rで文字列から最後のn文字を抽出する
-
[解決済み】data.table vs dplyr:一方がうまくできない、またはうまくできないことを行うことができますか?
-
[解決済み】data.tableで名前を指定してカラムを削除する方法は?
-
[解決済み] `dplyr`で新しいカラム/変数に動的な名前を使用する
-
[解決済み] Rのdata.tableの.SDは何の略か?
-
[解決済み] dplyrを使用して重複した行を削除する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
R言語エラー:図の余白が大きすぎる 解決方法
-
R read.table Error:埋め込まれたヌルが含まれているようです。
-
[解決済み] HTML、PDF、DOCXで見栄えのするシンプルな手動のRMarkdownテーブル
-
[解決済み] Rで文字列から文字を削除する
-
[解決済み] データフレームを結合(マージ)する方法(内側、外側、左側、右側)
-
[解決済み] Rの代入演算子"="と"<-"の違いは何ですか?
-
[解決済み] リストをデータフレームに変換する
-
[解決済み] ベクトル中のある要素のインデックスを求めるR関数はありますか?
-
[解決済み】data.table vs dplyr:一方がうまくできない、またはうまくできないことを行うことができますか?
-
[解決済み】自作関数を書くときにRの省略機能を使うには?