dplyrとdata.tableの比較

2022年8月25日

ホームに戻る

はじめに

Rにおけるデータを操作するパッケージとしてはdplyrがおそらく最もメジャーですが、 大規模なデータを扱う場合、data.tableを検討した方がよいかもしれません。 data.tableは高速かつ非常に簡潔な構文でデータを扱うことができます。 この記事では、dplyrに慣れ親しんでいたユーザーのために、 data.tableでのデータ操作と同等の操作をdplyrで行った場合を 確認しながら、data.tableでのデータ操作を学んでいきます。

練習課題としてdata.tableのvignette https://cran.r-project.org/web/packages/data.table/vignettes/datatable-intro.html を参照しました。 data.tableのソースコードは基本的にここに書かれているものと同じです。 dplyrのコードは、元記事のコードとだいたい同じものになるように 私が吟味して書きました。 では、まずライブラリを読み込んでいきます。

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff,
#>     setequal, union
library(data.table)
#> data.table 1.14.2 using 4 threads (see ?getDTthreads).  Latest news: r-datatable.com
#> 
#> Attaching package: 'data.table'
#> The following objects are masked from 'package:dplyr':
#> 
#>     between, first, last

使用するデータ

使用するデータは、 vignetteで使われているflights14を使います。 元々はhttps://github.com/arunsrinivasan/flightsで公開されているデータで、 以下のコードが示すように、csvとしても公開されているので、 いずれか好きな方法でダウンロードしてから利用します。 何度も読み込んだりするなら、 あらかじめバイナリデータとして保存しておいた方がよいかもしれません。 そうすれば、 load("data/flights.rda")でいつでもすぐにデータを呼び出すことができます。

input <- "https://raw.githubusercontent.com/Rdatatable/data.table/master/vignettes/flights14.csv"
download.file(input, "inst/extdata/flights14.csv")
flights <- fread("inst/extdata/flights14.csv")
save(flights, file = "data/flights.rda")

ちなみにflightsデータは、 2014 年にニューヨークにある3つの空港 JFK, LGA, EWR から出発した飛行機のデータで、発着の時間、飛行距離、遅延時間などが記録されています。

まず、最初の問題、 出発時間の遅れと到着時間の遅れを合わせたときに0より小さい、 つまり総合的には遅れがなかったといえるフライトは全体の何パーセントでしょうか。

これをdplyrで解くには

flights |> summarise(mean((arr_delay + dep_delay) < 0))
#>   mean((arr_delay + dep_delay) < 0)
#> 1                         0.5598304

data.tableで解くには

flights[, mean((arr_delay + dep_delay) < 0)]
#> [1] 0.5598304

となります。 念のため、計算の内訳を示してみましょう。 遅延時間の合計が0より小さいフライト数と、 全てのフライト数を数え、 その比が上記の計算結果と一致するか確認します。

flights |>
    summarise(
        delay = sum((arr_delay + dep_delay) < 0),
        n = n(),
        ratio = delay / n
    )
#>    delay      n     ratio
#> 1 141814 253316 0.5598304

data.tableでは

flights[, .(
    delay = sum((arr_delay + dep_delay) < 0),
    n = .N,
    ratio = sum((arr_delay + dep_delay) < 0) / .N
     )
]
#>     delay      n     ratio
#> 1: 141814 253316 0.5598304

となります。 dplyrでは、要約した変数の名前をdelay / nというふうに、 すぐに使うことができますが、 data.tableではこの機能はありません。 そのため、ちょっと冗長な書き方をしなくてはなりませんでした。 いずれにせよ、計算は一致しました。

つぎに、 6月にJFK(ジョン・F・ケネディ空港)から出発した飛行機の 出発時間と目的地の到着時間の遅延時間をそれぞれ計算します。 dplyrでは次のように書けるでしょう。

flights |>
  filter(origin == "JFK", month == 6) |>
  summarise(
    m_dep = mean(dep_delay),
    m_arr = mean(arr_delay)
  )
#>      m_dep    m_arr
#> 1 9.807884 5.839349

これをdata.tableでは

flights[
  origin == "JFK" & month == 6,
  .(
    m_dep = mean(dep_delay),
    m_arr = mean(arr_delay)
  )
]
#>       m_dep    m_arr
#> 1: 9.807884 5.839349

のように書きます。 ちなみにdplyrでは

flights |>
  filter(origin == "JFK", month == 6) |>
  summarise(across(matches("_delay"), mean))
#>   dep_delay arr_delay
#> 1  9.807884  5.839349

と書くこともでき、この場合、列名に"_delay"が含まれる列を一括で処理することができます。

inserted by FC2 system