library(arrow) # 10.0.1
library(dplyr) # 1.0.10
library(data.table) # 1.14.6
library(readr) # 2.1.3
library(dtplyr) # 1.2.2
library(duckdb) # 0.6.1
大規模データの処理の実行速度の比較
この文書は2022年12月17日に開催されたR研究集会2022での発表「Rによる大規模データの処理」の補足資料です。 発表の中で扱った{arrow}
パッケージによる大規模データの処理の実行速度を複数のRパッケージと比較した結果を示します。
実行環境と検証内容
環境
ここでの検証結果は次の環境で行いました。
- Apple M1 Mac (メモリ: 64GB)
- R version 4.2.1 (2022-06-23)
検証内容
データ読み込みと2つのデータ操作の実行速度を、{arrow}といくつかのパッケージ間で比較します。具体的な検証用のコードと実行速度のベンチマークの計測方法に関してはGitHub上のコードを参照してください。
- csvファイルの読み込み…
arrow::read_csv_arrow()
,readr::read_csv()
,data.table::fread()
- グループ化と集計
- 結合
パッケージの読み込み
{arrow}
パッケージの他に、処理速度の比較対象となるパッケージを読み込みます。
library(ggplot2)
source(here::here("R/plot.R"))
source(here::here("R/schema.R")) # 断面交通量情報データのためのスキーマ定義
# ベンチマーク結果などの読み込み用
<-
pins_resources_local ::board_folder(here::here("data-raw")) pins
断面交通量情報データ
- 公益財団法人日本道路交通情報センター https://www.jartic.or.jp が提供
- 各都道府県警察が車両感知器などの計測機器で収集した断面交通量に関する情報を警察庁においてとりまとめたもの
- 毎月、都道府県警察(北海道警察は5方面)ごとに
.zip
ファイルが更新される
- 毎月、都道府県警察(北海道警察は5方面)ごとに
# 日本道路交通情報センター提供のデータを読み込むパッケージ
::install_github("uribo/jarticr") remotes
各ファイルの中身は次のようになっています。
::glimpse(
dplyr::read_jartic_traffic(
jarticr::here("data-raw/typeB_tokushima_2022_10/徳島県警_202210.csv"))) here
Rows: 2,384,773
Columns: 10
$ datetime <dttm> 2022-10-01, 2022-10-01, 2022-10-01, 2022-10-01, 2022-…
$ source_code <chr> "3028", "3028", "3028", "3028", "3028", "3028", "3028"…
$ location_no <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,…
$ location_name <chr> "徳島本町→県庁前", "県庁前→徳島本町", "新助任橋北詰→徳…
$ meshcode10km <chr> "513404", "513404", "513404", "513404", "513404", "513…
$ link_type <int> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ link_no <int> 710, 705, 681, 676, 679, 678, 11, 375, 6, 5, 6, 5, 842…
$ traffic <int> 21, 24, 25, 27, 25, 28, 30, 16, 42, 42, 27, 25, 16, 26…
$ to_link_end_10m <chr> "6", "6", "11", "27", "21", "29", "26", "8", "7", "92"…
$ link_ver <int> 202100, 202100, 202100, 202100, 202100, 202100, 202100…
datetime
: 時刻。5分単位で記録source_code
: 情報源コードlocation_no
: 計測地点番号location_name
: 計測地点名称meshcode10km
: 2次メッシュコードlink_type
: リンク区分link_no
: リンク番号traffic
: 断面交通量。ある道路断面をある方向に通過する単位時間当たりの交通量(単位: 台)to_link_end_10m
: リンク終端からの距離link_ver
: リンクバージョン
元データ(CSV)のサイズ
断面交通量情報データを48ヶ月(2018年11月から2022年10月、4年)分収集したデータを使います。
全体のcsvファイルの大きさは.zip
圧縮時で652Gとなります。
ベンチマークを測るために4つのデータを用意しました。なお、Large
、Huge
タイプでのcsvのファイルサイズは.zip
圧縮時の大きさです。実際はこれより大きなサイズになることが予想されます。
# A tibble: 4 × 7
type area period nrow ncol csv_size parquet_size
<chr> <chr> <chr> <dbl> <int> <fs::bytes> <fs::bytes>
1 Small 東京都 1ヶ月 19209389 10 1.59G 102.34M
2 Medium 東京都 1年 228012986 10 19.29G 1.17G
3 Large 全国 1年 3923767686 10 260.3G 13.49G
4 Huge 全国 4年 15677276121 10 643.2G 54.1G
実行速度の比較
処理1: csvの読み込み
Large, Hugeについてはcsvファイルを用意しなかったため、SmallとMediumでの結果を示します。
Small, Mediumともに読み込みの速度は{data.table}パッケージのfread()
関数が最も高速でした。2つのデータでの順位は{data.table}、{arrow}、{readr}の順となりました。
<-
task_input_small_res |>
pins_resources_local ::pin_read("benchmark_input_small")
pins task_input_small_res
expression min median mem_alloc total_time
1 readr::read_csv 10.049957 10.225336 1.43GB 51.097654
2 data.table::fread 1.547197 1.736462 1.12GB 8.597198
3 arrow::read_csv_arrow 1.240628 2.500344 586.23MB 11.946824
<-
task_input_medium_res |>
pins_resources_local ::pin_read("benchmark_input_medium")
pins task_input_medium_res
expression min median mem_alloc total_time
1 readr::read_csv 246.88505 275.81730 18.69GB 823.9328
2 data.table::fread 19.06432 20.78965 14.3GB 69.3234
3 arrow::read_csv_arrow 42.42040 90.66747 7.65GB 244.6827
処理2: グループ化と集計
データへの操作を行う場合、{arrow}および{duckdb}を使うと他のパッケージよりも高速に処理できました。
<-
task_gs_small_res |>
pins_resources_local ::pin_read("benchmark_task_gs_small")
pins task_gs_small_res
expression min median mem_alloc total_time
1 dplyr 0.3428026 0.3536854 423.54MB 1.7569683
2 data.table 0.1811426 0.1880294 513.3MB 0.9335495
3 dtplyr 0.1821969 0.1902379 514.72MB 0.7620701
4 arrow 0.1020080 0.1045941 4.37MB 0.4167648
5 duckdb 0.1407175 0.1432536 8.49MB 0.5723605
<-
task_gs_medium_res |>
pins_resources_local ::pin_read("benchmark_task_gs_medium")
pins task_gs_medium_res
expression min median mem_alloc total_time
1 dplyr 4.957989 4.957989 5.4GB 4.957989
2 data.table 2.304412 2.304412 5.95GB 2.304412
3 dtplyr 4.903621 4.903621 5.95GB 4.903621
4 arrow 1.060302 1.060302 114.96KB 1.060302
5 duckdb 1.412729 1.412729 329.88KB 1.412729
処理3: 結合
結合処理ではSmallサイズのデータでは{dplyr}が最も高速に処理を終えましたが、Mediumサイズでは{arrow}が一番早い結果となりました。{duckdb}の利用が共通して遅い、という結果を示していますが、これはto_duckdb()
関数の適用のタイミングの問題だと考えられます。タイミングを工夫することで{arrow}での処理速度に近づけることが期待できます。
<-
task_join_small_res |>
pins_resources_local ::pin_read("benchmark_task_join_small")
pins task_join_small_res
expression min median mem_alloc total_time
1 dplyr 0.002996526 0.003111982 189.12KB 0.01662111
2 data.table 1.285227656 1.308420823 1.79GB 7.08349923
3 dtplyr 1.300879160 1.345852880 1.86GB 5.38343706
4 arrow 0.387688661 0.399215606 146.62MB 1.98544878
5 duckdb 14.483744542 14.792288935 1.65GB 73.62826925
<-
task_join_medium_res |>
pins_resources_local ::pin_read("benchmark_task_join_medium")
pins task_join_medium_res
expression min median mem_alloc total_time
1 dplyr 15.28164 15.415448 17GB 53.12222
2 data.table 19.70175 22.478590 23.8GB 68.23863
3 dtplyr 21.09285 21.533735 24.6GB 64.93516
4 arrow 5.65726 6.706522 1.7GB 20.40648
5 duckdb 123.75605 131.078867 10.2GB 412.29235