data.table vs dplyr:一方がうまくできること、もう一方ができないこと、またはうまくいかないことはありますか?

787
BrodieG 2014-01-30 05:21.

概要概要

私は比較的よく知っていますがdata.table、はあまりよく知っていませんdplyr。SOに表示されたいくつかのdplyrビネットと例を読みましたが、これまでのところ、私の結論は次のとおりです。

  1. data.tableそしてdplyrスピードに匹敵する、多くの(すなわち> 10-100K)グループがある場合を除いて、いくつかの他の状況(下のベンチマークを参照)
  2. dplyr よりアクセスしやすい構文があります
  3. dplyr 潜在的なDBの相互作用を抽象化(または意志)
  4. いくつかの小さな機能の違いがあります(以下の「例/使用法」を参照)

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

質問

私が知りたいのは:

  1. パッケージに精通している人にとって、どちらかのパッケージでコーディングするのがはるかに簡単な分析タスクはありますか(つまり、必要なキーストロークと必要なレベルの秘教の組み合わせで、それぞれを少なくするのが良いことです)。
  2. あるパッケージと別のパッケージで大幅に(つまり2倍以上)効率的に実行される分析タスクはありますか?

Rの1つのベクトルに値を累積的に追加する方法1つで、これについてもう少し考えさせられました。それまでdplyrは、ですでにできることをはるかに超えるものは提供できないと思っていたからdata.tableです。これが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方法が大幅に簡潔であるか、パフォーマンスが大幅に向上しています。

使用法 ベンチマーク

データ

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

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

4 answers

553
Arun 2014-12-31 22:27.

:私たちは、(重要性の順不同)包括的な答え/比較を提供するために、少なくともこれらの側面をカバーする必要があるSpeedMemory usageSyntaxFeatures

私の意図は、data.tableの観点から、これらのそれぞれを可能な限り明確にカバーすることです。

注:特に明記されていない限り、dplyrを参照することにより、内部がRcppを使用してC ++であるdplyrのdata.frameインターフェースを参照します。


data.table構文は、その形式で一貫しています- DT[i, j, by]。維持するためにijそしてby一緒に設計によるものです。関連する操作をまとめることにより、構文の一貫性を維持しながら、速度とさらに重要なメモリ使用量について操作を簡単に最適化し、いくつかの強力な機能を提供することができます。

1.スピード

かなりの数のベンチマーク(ほとんどの操作をグループ化するにかかわらず)は、すでにdata.tableが取得する表示の質問に追加された高速化を含め、増加によりdplyrより基および/または行数などのグループにマットにより、ベンチマークからのグループ化にまで千万1億から1000万のグループとさまざまなグループ化列で20億行(RAMで100GB)pandas。これも比較します。およびを含む、更新されたベンチマークも参照してください。Sparkpydatatable

ベンチマークでは、これらの残りの側面もカバーするのが素晴らしいでしょう。

  • 行のサブセットを含むグループ化操作-つまり、DT[x > val, sum(y), by = z]タイプ操作。

  • 更新結合などの他の操作のベンチマーク。

  • また、ランタイムに加えて、各操作のメモリフットプリントをベンチマークします。

2.メモリ使用量

  1. dplyrに関連する、filter()またはslice()dplyr内の操作は、メモリ効率が悪くなる可能性があります(data.framesとdata.tablesの両方で)。この投稿を参照してください

    data.tableのdplyr、私は本当にdata.tableを使用していますか?速度data.tableのdplyr、私は本当にdata.tableを使用していますか?話していることに注意してください(dplyrは彼にとって十分に高速です)が、ここでの主な関心事はメモリです。

  2. 現時点では、data.tableインターフェイスを使用すると、参照によって列を変更/更新できます(結果を変数に再割り当てする必要がないことに注意してください)。

    # sub-assign by reference, updates 'y' in-place
    DT[x >= 1L, y := NA]
    

    ただし、dplyr参照によって更新されることはありません。同等のdplyrは次のようになります(結果を再割り当てする必要があることに注意してください)。

    # copies the entire 'y' column
    ans <- DF %>% mutate(y = replace(y, which(x >= 1L), NA))
    

    これに対する懸念は、参照透過性です。特に関数内で、参照によってdata.tableオブジェクトを更新することが常に望ましいとは限りません。しかし、これは非常に便利な機能です。興味深いケースについては、これ大規模なdata.table内のNAを置き換える最速の方法投稿を参照してください。そして、私たちはそれを維持したいと思います。

    したがってshallow()、ユーザーに両方の可能性を提供するdata.tableの関数のエクスポートに取り組んでいます。たとえば、関数内の入力data.tableを変更しないことが望ましい場合は、次のようにすることができます。

    foo <- function(DT) {
        DT = shallow(DT)          ## shallow copy DT
        DT[, newcol := 1L]        ## does not affect the original DT 
        DT[x > 2L, newcol := 2L]  ## no need to copy (internally), as this column exists only in shallow copied DT
        DT[x > 2L, x := 3L]       ## have to copy (like base R / dplyr does always); otherwise original DT will 
                                  ## also get modified.
    }
    

    を使用しないことによりshallow()、古い機能が保持されます。

    bar <- function(DT) {
        DT[, newcol := 1L]        ## old behaviour, original DT gets updated by reference
        DT[x > 2L, x := 3L]       ## old behaviour, update column x in original DT.
    }
    

    を使用して浅いコピーを作成することによりshallow()、元のオブジェクトを変更したくないことがわかります。絶対に必要な場合にのみ変更した列をコピーすることを保証しながら、内部ですべてを処理します。実装すると、これにより、ユーザーに両方の可能性を提供しながら、参照透過性の問題を完全に解決する必要があります。

    また、一度shallow()エクスポートされると、dplyrのdata.tableインターフェイスはほとんどすべてのコピーを回避する必要があります。したがって、dplyrの構文を好む人は、data.tablesでそれを使用できます。

    ただし、参照による(サブ)割り当てなど、data.tableが提供する多くの機能はまだ不足しています。

  3. 参加中に集計:

    次のように2つのdata.tablesがあるとします。

    DT1 = data.table(x=c(1,1,1,1,2,2,2,2), y=c("a", "a", "b", "b"), z=1:8, key=c("x", "y"))
    #    x y z
    # 1: 1 a 1
    # 2: 1 a 2
    # 3: 1 b 3
    # 4: 1 b 4
    # 5: 2 a 5
    # 6: 2 a 6
    # 7: 2 b 7
    # 8: 2 b 8
    DT2 = data.table(x=1:2, y=c("a", "b"), mul=4:3, key=c("x", "y"))
    #    x y mul
    # 1: 1 a   4
    # 2: 2 b   3
    

    そしてsum(z) * mul、列でDT2結合しながら、の各行を取得したいとしますx,y。次のいずれかを実行できます。

    • 1)DT1取得するための集計sum(z)、2)結合の実行、3)乗算(または)

      # data.table way
      DT1[, .(z = sum(z)), keyby = .(x,y)][DT2][, z := z*mul][]
      
      # dplyr equivalent
      DF1 %>% group_by(x, y) %>% summarise(z = sum(z)) %>% 
          right_join(DF2) %>% mutate(z = z * mul)
      
    • 2)すべてを一度に実行します(by = .EACHI機能を使用):

      DT1[DT2, list(z=sum(z) * mul), by = .EACHI]
      

    利点は何ですか?

    • 中間結果にメモリを割り当てる必要はありません。

    • グループ化/ハッシュを2回行う必要はありません(1つは集約用、もう1つは参加用)。

    • さらに重要なのは、j(2)を見ると、実行したい操作が明確になっていることです。

    の詳細な説明については、この投稿を確認してくださいby = .EACHI。中間結果は実現されず、join + aggregateは一度に実行されます。

    見ていこれをこれ2番目のデータフレームの各要素について、2つのデータフレーム間の最小距離を見つけます本当の使用シナリオのためのポスト。

    では、最初dplyr結合して集約または集約してから結合する必要がありますが、どちらもメモリの点で効率的ではありません(これは速度に変換されます)。

  4. 更新して参加します:

    以下に示すdata.tableコードについて考えてみます。

    DT1[DT2, col := i.mul]
    

    のキー列が一致する行のfromを使用して、DT1の列colを追加/更新します。つまり、新しい列を追加するためだけに全体をコピーする必要がある操作を回避せずに、この操作に完全に相当するものはないと思います。これは不要です。mulDT2DT2DT1dplyr*_joinDT1

    実際の使用シナリオについては、この投稿を確認してください。

要約すると、最適化のあらゆるビットが重要であることを認識することが重要です。以下のようグレース・ホッパーは言うでしょう、あなたのナノ秒マインド

3.構文

構文を見てみましょう。ハドリーはここにコメントしました

データテーブルは非常に高速ですが、その簡潔さは学習難しくし、それを使用するコードはあなたがそれを書いた後に読むのを難しくすると思います...

この発言は非常に主観的であるため、無意味だと思います。おそらく試すことができるのは、構文の一貫性を対比することです。data.table構文とdplyr構文を並べて比較します。

以下に示すダミーデータを使用します。

DT = data.table(x=1:10, y=11:20, z=rep(1:2, each=5))
DF = as.data.frame(DT)
  1. 基本的な集計/更新操作。

    # case (a)
    DT[, sum(y), by = z]                       ## data.table syntax
    DF %>% group_by(z) %>% summarise(sum(y)) ## dplyr syntax
    DT[, y := cumsum(y), by = z]
    ans <- DF %>% group_by(z) %>% mutate(y = cumsum(y))
    
    # case (b)
    DT[x > 2, sum(y), by = z]
    DF %>% filter(x>2) %>% group_by(z) %>% summarise(sum(y))
    DT[x > 2, y := cumsum(y), by = z]
    ans <- DF %>% group_by(z) %>% mutate(y = replace(y, which(x > 2), cumsum(y)))
    
    # case (c)
    DT[, if(any(x > 5L)) y[1L]-y[2L] else y[2L], by = z]
    DF %>% group_by(z) %>% summarise(if (any(x > 5L)) y[1L] - y[2L] else y[2L])
    DT[, if(any(x > 5L)) y[1L] - y[2L], by = z]
    DF %>% group_by(z) %>% filter(any(x > 5L)) %>% summarise(y[1L] - y[2L])
    
    • data.table構文はコンパクトで、dplyrは非常に冗長です。(a)の場合、物事は多かれ少なかれ同等です。

    • (b)の場合filter()要約しながらdplyrで使用する必要がありました。ただし、更新中に、ロジックを内部に移動する必要がありましたmutate()。ただし、data.tableでは、両方の操作を同じロジックで表現します。つまりx > 2、最初のケースではgetsum(y)である行を操作し、2番目のケースではそれらの行をy累積合計で更新します。

      これは、DT[i, j, by]フォームが一貫していると言うときの意味です。

    • 同様に、ケース(c)の場合、if-else条件がある場合、data.tableとdplyrの両方でロジックを現状のまま表現できます。ただし、if条件が満たされる行だけを返し、それ以外の場合はスキップする場合は、summarise()直接使用できません(AFAICT)。常に単一の値を期待するfilter()ため、最初に要約summarise()する必要があります

      同じ結果が返されますが、filter()ここを使用すると実際の操作がわかりにくくなります。

      filter()最初のケースでも使用できる可能性は十分にありますが(私には明らかではないようです)、私のポイントは、使用する必要はないということです。

  2. 複数の列の集約/更新

    # case (a)
    DT[, lapply(.SD, sum), by = z]                     ## data.table syntax
    DF %>% group_by(z) %>% summarise_each(funs(sum)) ## dplyr syntax
    DT[, (cols) := lapply(.SD, sum), by = z]
    ans <- DF %>% group_by(z) %>% mutate_each(funs(sum))
    
    # case (b)
    DT[, c(lapply(.SD, sum), lapply(.SD, mean)), by = z]
    DF %>% group_by(z) %>% summarise_each(funs(sum, mean))
    
    # case (c)
    DT[, c(.N, lapply(.SD, sum)), by = z]     
    DF %>% group_by(z) %>% summarise_each(funs(n(), mean))
    
    • (a)の場合、コードは多かれ少なかれ同等です。data.tableはおなじみの基本関数を使用しますがlapply()、は一連の関数とともにをdplyr導入*_each()funs()ます。

    • data.table:=では列名を指定する必要がありますが、dplyrでは列名が自動的に生成されます。

    • (b)の場合、dplyrの構文は比較的単純です。複数の関数の集計/更新の改善は、data.tableのリストにあります。

    • ただし、(c)の場合、dplyrはn()1回だけではなく、何倍もの列を返します。data.tableで行う必要があるのは、でリストを返すことだけですj。リストの各要素が結果の列になります。したがって、もう一度、おなじみの基本関数c()を使用.Nして、listを返すに連結することができますlist

    注:ここでも、data.tableで、リストを返すだけですj。リストの各要素は、結果として列になります。あなたは使用することができc()as.list()lapply()list()など...基本機能をすべての新しい機能を学ぶことなく、これを達成するために。

    特別な変数だけを学ぶ必要があります-.Nそして.SD少なくとも。dplyrで同等であるn().

  3. 参加する

    dplyrは、結合のタイプごとに個別の関数を提供しますが、data.tableは、同じ構文を使用してDT[i, j, by](そして理由を付けて)結合を許可します。またmerge.data.table()、代替として同等の機能を提供します。

    setkey(DT1, x, y)
    
    # 1. normal join
    DT1[DT2]            ## data.table syntax
    left_join(DT2, DT1) ## dplyr syntax
    
    # 2. select columns while join    
    DT1[DT2, .(z, i.mul)]
    left_join(select(DT2, x, y, mul), select(DT1, x, y, z))
    
    # 3. aggregate while join
    DT1[DT2, .(sum(z) * i.mul), by = .EACHI]
    DF1 %>% group_by(x, y) %>% summarise(z = sum(z)) %>% 
        inner_join(DF2) %>% mutate(z = z*mul) %>% select(-mul)
    
    # 4. update while join
    DT1[DT2, z := cumsum(z) * i.mul, by = .EACHI]
    ??
    
    # 5. rolling join
    DT1[DT2, roll = -Inf]
    ??
    
    # 6. other arguments to control output
    DT1[DT2, mult = "first"]
    ??
    
    • 結合ごとに個別の関数(左、右、内部、アンチ、セミなど)がはるかに優れている場合もあれば、data.tableのDT[i, j, by]、またはmerge()ベースRに類似している場合もあります。

    • ただし、dplyr結合はまさにそれを行います。これ以上何もない。それ以下ではありません。

    • data.tablesは結合中に列を選択でき(2)、dplyrでは、select()上記のように結合する前に、最初に両方のdata.framesで行う必要があります。そうしないと、不要な列との結合をマテリアライズして後で削除するだけであり、非効率的です。

    • data.tablesは、機能を使用して、結合中に集約でき(3)、結合中に更新することもできます(4)by = .EACHI。結合結果全体をマテリアル化して、ほんの数列を追加/更新するのはなぜですか?

    • data.tableができるローリング参加する(5) -ロールフォワード、LOCF後方ロール、NOCB最寄りの

    • data.tableには、最初最後、またはすべての一致mult =を選択する引数もあります(6)。

    • data.tableにはallow.cartesian = TRUE、偶発的な無効な結合から保護するための引数があります。

繰り返しになりますが、構文はDT[i, j, by]追加の引数と一致しており、出力をさらに制御できます。

  1. do()..。

    dplyrの要約は、単一の値を返す関数用に特別に設計されています。関数が複数の/等しくない値を返す場合は、に頼る必要がありますdo()。すべての関数の戻り値について事前に知っておく必要があります。

    DT[, list(x[1], y[1]), by = z]                 ## data.table syntax
    DF %>% group_by(z) %>% summarise(x[1], y[1]) ## dplyr syntax
    DT[, list(x[1:2], y[1]), by = z]
    DF %>% group_by(z) %>% do(data.frame(.$x[1:2], .$y[1]))
    
    DT[, quantile(x, 0.25), by = z]
    DF %>% group_by(z) %>% summarise(quantile(x, 0.25))
    DT[, quantile(x, c(0.25, 0.75)), by = z]
    DF %>% group_by(z) %>% do(data.frame(quantile(.$x, c(0.25, 0.75))))
    
    DT[, as.list(summary(x)), by = z]
    DF %>% group_by(z) %>% do(data.frame(as.list(summary(.$x))))
    
    • .SDの同等物は .

    • data.tableでは、ほとんど何でもスローできます。j覚えておくべきことは、リストの各要素が列に変換されるようにリストを返すことだけです。

    • dplyrでは、それはできません。do()関数が常に単一の値を返すかどうかについて、確信度に応じて頼る必要があります。そして、それはかなり遅いです。

繰り返しになりますが、data.tableの構文はDT[i, j, by]。と一致しています。jこれらのことを気にすることなく、表現を投入し続けることができます。

1つの関数から複数の列を計算し、それらをdata.frameに追加しますグループによるdata.table外部結合見てください。dplyrの構文を使用して答えを簡単に表現することは可能でしょうか...

要約すると、dplyrの構文が非効率的であるか、制限されているか、操作を簡単にできない場合のいくつかの例を特に強調しました。これは特に、data.tableが「読みにくい/学習しにくい」構文(上記の貼り付け/リンクのような)についてかなりの反発を受けるためです。dplyrをカバーするほとんどの投稿は、最も簡単な操作について説明しています。そしてそれは素晴らしいことです。しかし、その構文と機能の制限を理解することも重要であり、私はまだそれについての投稿を見ていません。

data.tableにも癖があります(修正しようとしていることを指摘したものもあります)。ここで強調しように、data.tableの結合の改善も試みています

ただし、data.tableと比較してdplyrに欠けている機能の数も考慮する必要があります。

4.機能

私はこことこの投稿でもほとんどの機能を指摘しました。加えて:

  • fread-高速ファイルリーダーは長い間利用可能でした。

  • fwriteの-並列化高速ファイルライターが利用可能になりました。実装の詳細な説明についてはこの投稿を、今後の開発を追跡するための#1664を参照してください。

  • 自動インデックス作成-ベースR構文をそのまま内部的に最適化するためのもう1つの便利な機能。

  • アドホックグループ化:のdplyrsummarise()に変数をグループ化することによって結果を自動的にソートしますが、これは必ずしも望ましいとは限りません。

  • 上記のdata.table結合(速度/メモリ効率と構文)には多くの利点があります。

  • 非エクイが参加する:他の演算子を使用してジョインできます<=, <, >, >=data.tableの他のすべての利点と一緒に参加します。

  • 最近、重複する範囲結合がdata.tableに実装されました。ベンチマークの概要については、この投稿を確認してください。

  • setorder() 参照によるdata.tablesの非常に高速な並べ替えを可能にするdata.tableの関数。

  • dplyrは、同じ構文を使用してデータベースへのインターフェイスを提供しますが、 data.tableは現時点では提供していません。

  • data.table速い同等提供集合演算- (月Goreckiによって書かれた)fsetdifffintersectfunionおよびfsetequal追加のとall引数(SQLのように)。

  • data.tableはマスキング警告なしでクリーンにロードされ、Rパッケージに渡されたときの互換性のためにここで説明さているメカニズムがあり[.data.frameます。dplyrは、基本機能を変更しfilterlagそして[問題が発生する可能性があり、たとえば、ここここ


最後に:

  • データベースの場合-data.tableが同様のインターフェースを提供できない理由はありませんが、これは現在の優先事項ではありません。ユーザーがその機能を非常に好む場合、それはぶつかるかもしれません..わからない。

  • 並列処理について-誰かが先に進んでそれを実行するまで、すべてが困難です。もちろん、それは努力を要します(スレッドセーフであること)。

    • 現在(v1.9.7開発では)、を使用してパフォーマンスを向上させるために、既知の時間のかかる部分を並列化する方向に進んでいますOpenMP
396
hadley 2015-01-09 02:39.

これは、アルンの答えの大まかな概要に従って、dplyrの観点から包括的な答えを試みたものです(ただし、優先順位の違いに基づいて多少再配置されています)。

構文

構文にはある程度の主観がありますが、data.tableの簡潔さにより、学習が困難になり、読みにくくなるという私の声明を支持します。これは、dplyrがはるかに簡単な問題を解決しているためです。

dplyrがあなたのために行う本当に重要なことの1つは、オプションを制約すること です。私は、ほとんどの単一テーブルの問題は、「グループ別」副詞とともに、5つの主要な動詞のフィルター、選択、変更、配置、および要約で解決できると主張しています。この制約は、問題についての考えを整理するのに役立つため、データ操作を学習するときに大きな助けになります。dplyrでは、これらの動詞のそれぞれが単一の関数にマップされます。各機能は1つの仕事をし、単独で理解するのは簡単です。

これらの単純な操作をと一緒にパイプすることにより、複雑さを生み出します %>%。Arunがdata.tableのdplyr、私は本当にdata.tableを使用していますか?いる投稿の1つからの例を次に示します。

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の別の操作であることが好きです。これは計算を根本的に変えるので、コードをスキミングするときに明白になるはずでありgroup_by()、のby引数よりも簡単に見つけることができます[.data.table

また、パイプ が1つのパッケージだけに限定されていないことも気に入っています。tidyrでデータを整理することから始めて、ggvisのプロットで終了することができます 。そして、あなたは私が書いたパッケージに限定されません-誰でもデータ操作パイプのシームレスな部分を形成する関数を書くことができます。実際、私は以前のdata.tableコードを次のように書き直したほうが好きです%>%

diamonds %>% 
  data.table() %>% 
  .[cut != "Fair", 
    .(AvgPrice = mean(price),
      MedianPrice = as.numeric(median(price)),
      Count = .N
    ), 
    by = cut
  ] %>% 
  .[order(-Count)]

また、パイプのアイデアは%>%データフレームだけに限定されず、インタラクティブなWebグラフィックWebスクレイピング要点ランタイムコントラクトなど、他のコンテキストにも簡単に一般化できます。

メモリとパフォーマンス

私にとって、これらはそれほど重要ではないので、これらをまとめました。ほとんどのRユーザーは、100万行をはるかに下回るデータを処理します。また、dplyrは、処理時間に気付かないほどのサイズのデータ​​に対して十分に高速です。中程度のデータで表現力を高めるためにdplyrを最適化します。より大きなデータの生の速度については、data.tableを自由に使用してください。

dplyrの柔軟性は、同じ構文を使用してパフォーマンス特性を簡単に調整できることも意味します。データフレームバックエンドでのdplyrのパフォーマンスが十分でない場合は、data.tableバックエンドを使用できます(機能のセットは多少制限されていますが)。使用しているデータがメモリに収まらない場合は、データベースバックエンドを使用できます。

とはいえ、dplyrのパフォーマンスは長期的には向上します。基数の順序付けや結合とフィルターに同じインデックスを使用するなど、data.tableの優れたアイデアのいくつかを確実に実装します。複数のコアを活用できるように、並列化にも取り組んでいます。

特徴

2015年に取り組む予定のいくつかのこと:

  • readrに類似したメモリにディスクからと内のファイルを取得するために簡単にそれを作るためのパッケージ、、 fread()

  • 非等結合のサポートを含む、より柔軟な結合。

  • ブートストラップサンプル、ロールアップなどのより柔軟なグループ化

また、Rのデータベースコネクタの改善、Web APIとの通信機能 の改善、およびhtmlページのスクレイピングの容易化にも時間を費やしてい ます

65
Thell 2014-11-17 12:39.

質問のタイトルに直接応答して...

dplyr 絶対にdata.tableできないことをします。

あなたのポイント#3

dplyrは潜在的なDBの相互作用を抽象化します(またはそうします)

あなた自身の質問に対する直接の答えですが、十分に高いレベルに引き上げられていません。dplyrは、複数のデータストレージメカニズムへの拡張可能なフロントエンドであり、単一のデータストレージメカニズムへdata.tableの拡張です。

dplyrすべてのターゲットが同じ文法を使用しているバックエンドにとらわれないインターフェースとして見てください。ここでは、ターゲットとハンドラーを自由に拡張できます。観点data.tableからは、dplyrそれらのターゲットの1つです。

data.tableクエリを変換して、ディスク上またはネットワーク化されたデータストアで動作するSQLステートメントを作成しようとする日は決してありません(私は願っています)。

dplyrできることdata.tableはできないかもしれないし、できないかもしれない。

インメモリでの作業の設計に基づくと、data.tableクエリの並列処理に拡張するのは、よりもはるかに困難な場合がありdplyrます。


体内の質問に答えて...

使用法

パッケージに精通している人にとって、どちらかのパッケージコーディングするのがはるかに簡単な分析タスクはありますか(つまり、必要なキーストロークと必要なレベルの秘教の組み合わせで、それぞれを少なくするのが良いことです)。

これはパントのように見えるかもしれませんが、本当の答えはノーです。ツールに精通している人は、ツールに最も馴染みのあるものか、実際に目前の仕事に適したもののどちらかを使用しているようです。そうは言っても、特定の読みやすさ、場合によってはパフォーマンスのレベルを提示したい場合もあれば、両方のレベルを十分に高くする必要がある場合は、より明確な抽象化を行うためにすでに必要なものに対応するための別のツールが必要な場合もあります。 。

パフォーマンス

あるパッケージと別のパッケージで大幅に(つまり2倍以上)効率的に実行される分析タスクはありますか?

繰り返しますが、違います。 基盤となるデータストアと登録済みハンドラーにいくつかの点で制限されるという負担がかかる場合data.table、すべての作業で効率的であることに優れdplyrます。

これは、パフォーマンスの問題が発生したときに、data.tableそれがクエリ関数にあることをかなり確信で​​きることを意味し、それ実際にボトルネックであるdata.table場合は、レポートを提出する喜びを勝ち取ったことになります。これは、がバックエンドとしてdplyr使用さdata.tableれている場合にも当てはまります。あなたがかもしれ参照いくつかのオーバーヘッドがdplyrなく、オッズは、それはあなたのクエリです。

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

また、plyrがdata.tableより優れているのはいつですか?[閉まっている]についての受け入れられた答えを参照してくださいplyrがdata.tableより優れているのはいつですか?[閉まっている]

6
Iyar Lin 2020-06-15 07:00.

HadleyとArunの回答を読むと、dplyrの構文を好む人は、場合によっては、data.table長時間の実行に切り替えたり、妥協したりする必要があるという印象を受けます。

しかし、すでに述べたように、バックエンドとしてdplyr使用できますdata.table。これは、dtplyr最近バージョン1.0.0リリースがリリースされたパッケージを使用して実現さます。学習にdtplyrは、実質的にゼロの追加作業が必要です。

dtplyr使用する場合は、関数lazy_dt()を使用して遅延data.tableを宣言し、その後、標準dplyr構文を使用してその操作を指定します。これは次のようになります。

new_table <- mtcars2 %>% 
  lazy_dt() %>%
  filter(wt < 5) %>% 
  mutate(l100k = 235.21 / mpg) %>% # liters / 100 km
  group_by(cyl) %>% 
  summarise(l100k = mean(l100k))

  new_table

#> Source: local data table [?? x 2]
#> Call:   `_DT1`[wt < 5][, `:=`(l100k = 235.21/mpg)][, .(l100k = mean(l100k)), 
#>     keyby = .(cyl)]
#> 
#>     cyl l100k
#>   <dbl> <dbl>
#> 1     4  9.05
#> 2     6 12.0 
#> 3     8 14.9 
#> 
#> # Use as.data.table()/as.data.frame()/as_tibble() to access results

new_tableオブジェクトは、それに呼び出すまでは評価されませんas.data.table()/ as.data.frame()/as_tibble()基礎となるその時点でdata.tableの動作が実行されます。

2018年12月に著者のMattDowleが行ったベンチマーク分析を再現しました。data.tableこれは、多数のグループにわたる運用のケースを対象としています。dtplyr実際、dplyr構文を好む人は、によって提供される速度を楽しみながら、構文を使い続けることができることがわかりましたdata.table

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

ねえNFL、ジョーバロウとカイラーマレーは女性の権利をサポートするために少しの助けを使うことができます

ねえNFL、ジョーバロウとカイラーマレーは女性の権利をサポートするために少しの助けを使うことができます

ジョー・バロウロー対ウェイド事件の転覆に対応するNFLは、言葉を言わないことで、腹立たしいが予測可能なPRの結果でした。

別の日、別のヒンジのないLIV記者会見

別の日、別のヒンジのないLIV記者会見

(lから)パット・ペレス、ブルックス・ケプカ、パトリック・リードサウジアラビアのLIVゴルフリーグのさらに別の信じられないほどの記者会見で、スポーツのファンはブルックス・ケプカからでたらめな吐き気と質問回避の驚異的なマスタークラスを受けました。パトリックリード、ブライソンデシャンボー、パットペレス、最近のPGAツアーの脱北者。

ミズ・マーベルの家族の帰郷は悪役よりも激しく打撃を与える

ミズ・マーベルの家族の帰郷は悪役よりも激しく打撃を与える

レッドダガーとマーベルさんがチームを組んでいます。

6億7500万ドルのビットコインローンのデフォルト後にすべての資産を清算するように命じられたスリーアローズキャピタル

6億7500万ドルのビットコインローンのデフォルト後にすべての資産を清算するように命じられたスリーアローズキャピタル

暗号業界最大の沈没船の1つであるスリーアローズキャピタルは、ついにその悲惨さから解放されています。火曜日に、不良債権ヘッジファンドは、債権者からの返済を要求する訴訟の高まりに応えて、バージンアイランド裁判所によって清算を命じられました彼らが3ACに行ったローン。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

Suffragettes Indicam #3: Junho

Suffragettes Indicam #3: Junho

Mais um mês se findando — e metade do ano de 2022 já passou. Sabe o que isso significa? Não, não é hora de verificar se você está cumprindo com suas resoluções de Ano Novo.

多元宇宙—Junø

多元宇宙—Junø

チェーン間アカウントがJunoに登場します。異なるブロックチェーン間でスマートコントラクトの構成可能性と真の相互運用性を提供します。

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

1.ドラマを見た後、起業する考えはありますか?あなたのビジネスはボトルネックに遭遇しましたか?方向性がなくてわからない場合は、ドラマを追いかけて行くことを心からお勧めします。(?)ブラフではなく、最も完璧なビジネス例を隠すドラマがあります。2.ブレイキング・バッドとその弁護士ドラマ「ブレイキング・バッド」を見た友人たちは、演劇の中で、穏やかな表情で、弁護士のソウル・グッドマンに深く感銘を受けなければなりません。口を開けて、感覚の弱い傭兵の性格を持っています。道徳の面で、サル・グッドマンは無意識のうちに劇に欠かせない役割を果たし、彼自身のシリーズ「絶望的な弁護士」(ベター・コール・ソール)を生み出しました。ウェントウのテキストとビデオは、劇中のソウル・グッドマンのテレビコマーシャルです。製品(サービス)、競争戦略、市場ポジショニング、ブランド名、ターゲット顧客グループ、コミュニケーション軸から広告まで、サル・グッドマンの役割のビジネス設定は、「最低」と見なすことができる超超超超超超完全です。ブランドコミュニケーションのコスト」「変化」のモデル。なぜ?私の分析をご覧ください。3.ソウル・グッドマンの「事業戦略」1.基本情報ブランド名:Saul Goodman製品:法律相談サービス対象顧客:麻薬中毒、飲酒運転、事故など。法律知識の欠如は、一般的に公立弁護士にしか余裕がなく、真面目な弁護士も「特別な法律を持つ消費者」を避けます。恐れてはいけない「​​ニーズ」。コミュニケーションの主軸:この国のすべての男性、女性、子供は有罪判決を受けるまで無実だと思います。地域:アルバカーキ市スローガン:Thrallに電話したほうがいいです!(ベター・コール・ソール)広告:2つの可能性のある犯罪状況をシミュレートします+サウルの主張+サウルのスローガン2をより適切に呼び出します。

メインネットガイド— Arbitrum Odyssey Week 2

メインネットガイド— Arbitrum Odyssey Week 2

最新のアップデートを受け取るために私たちに従ってください。ニュースレター:https://www。

Language