Slide 1

Slide 1 text

『改訂新版前処理大全』の話と Apache Parquet の話 Tokyo.R #113 2024/06/08 @bob3bob3

Slide 2

Slide 2 text

『改訂新版前処理大全』 ● 2018年に発売されてデータ分析界隈で 大きな話題となった『前処理大全』のアッ プデート版。
 ● データサイエンスに取り組む上で欠かせ ない前処理の効率的な処理方法を網羅 的に習得できる構成。
 ● サンプルデータがApache Parquet形式 で提供されているのも特徴。
 ● 旧版ではR、Python、SQLを用いた実装 方法を紹介していたが、改訂新版では BigQuery準拠のSQL、最新バージョンの Pandas、Rの代わりに高速なPolarsに変 更しました。


Slide 3

Slide 3 text

『改訂新版前処理大全』 Rの代わりに高 速なPolarsに変 更しました。


Slide 4

Slide 4 text

というわけで、Rで『改訂新版前処理大全』 のサンプルコードを書いています。

Slide 5

Slide 5 text

例1

Slide 6

Slide 6 text

例1)ビジネスホテルかつ宿泊人数が1名の予約履歴の抽出 reservation(200万件、11列) hotel(5千件、39列)

Slide 7

Slide 7 text

例1)ビジネスホテルかつ宿泊人数が1名の予約履歴の抽出 reservation(200万件、11列) hotel(5千件、39列)

Slide 8

Slide 8 text

例1)ビジネスホテルかつ宿泊人数が1名の予約履歴の抽出 # Not Awesome reservation |> inner_join(hotel, by = "hotel_id") |> dplyr::filter(hotel_type == "ビジネスホテル" & people_num == 1) # Awesome reservation |> dplyr::filter(people_num == 1) |> inner_join( hotel |> dplyr::filter(hotel_type == "ビジネスホテル") |> select(hotel_id), by = "hotel_id" )

Slide 9

Slide 9 text

例1)ビジネスホテルかつ宿泊人数が1名の予約履歴の抽出 # Not Awesome reservation |> inner_join(hotel, by = "hotel_id") |> dplyr::filter(hotel_type == "ビジネスホテル" & people_num == 1) reservationとhotelをすべて結合してから条件指定によってデータの抽出を行っている。 また必要な列に絞らずhotelマスターのすべての列を出力している。

Slide 10

Slide 10 text

例1)ビジネスホテルかつ宿泊人数が1名の予約履歴の抽出 # Awesome reservation |> dplyr::filter(people_num == 1) |> inner_join( hotel |> dplyr::filter(hotel_type == "ビジネスホテル") |> select(hotel_id), by = "hotel_id" ) reservationとhotelそれぞれを必要な行と列に絞ってからjoinしている。

Slide 11

Slide 11 text

例1)ビジネスホテルかつ宿泊人数が1名の予約履歴の抽出 Awesomeなコードの方が中央値で6倍 ぐらい速い。 joinする前にそれぞれのデータをできる 限り小さくしておくこと!

Slide 12

Slide 12 text

Apache Parquet による前処理の高速化

Slide 13

Slide 13 text

Apache Parquet による前処理の高速化 ● Apache Parquet はオープンソースの列指向データファイルフォーマットで、効率的 なデータの保存と検索のために設計されています。 ● 複雑なデータを一括処理するための高性能な圧縮とエンコード方式を提供し、多く のプログラミング言語と分析ツールでサポートされています。 ● Rではarrowパッケージで Apache Parquet を扱うことができます。

Slide 14

Slide 14 text

Apache Parquet による前処理の高速化 # データフレームとして reservation_df <- read_parquet( "https://github.com/ghmagazine/awesomebook_v2/raw/main/data/reservation.parquet" ) # Arrow Table として reservation_at <- read_parquet( "https://github.com/ghmagazine/awesomebook_v2/raw/main/data/reservation.parquet", as_data_frame = FALSE ) parquet形式のデータをarrowパッケージのread_parquet()関数で読み込む。 デフォルトではデータフレームとして読み込まれるが、引数に as_data_frame = FALSE を付けるとArrow Tableとして読み込まれる。

Slide 15

Slide 15 text

Apache Parquet による前処理の高速化 # データフレームの処理 reservation_df |> dplyr::filter(status != "canceled") |> summarise(reservation_cnt = n(), .by = c(hotel_id, customer_id)) # Arrow Table の処理 reservation_at |> dplyr::filter(status != "canceled") |> summarise(reservation_cnt = n(), .by = c(hotel_id, customer_id)) |> collect() #この処理が加わっただけ ホテルごと顧客ごとの予約数の集計処理。 Arrow Table も tidyverse で処理できるが、最後に collect()を実行することで結果が得られる。

Slide 16

Slide 16 text

Apache Parquet による前処理の高速化 中央値で約35倍の速さ! Tidyverseのすべての機能が ApacheParquetで使えるわけではない ようですが、積極的に使っていきましょ う! eitsupiさんの以前の発表やuriboさんの 資料もご参考に。

Slide 17

Slide 17 text

Apache Parquet の資料 @eitsupi さん @uribo さん https://eitsupi.github.io/tokyorslide/tokyor_97 https://uribo.quarto.pub/hello-r-arrow/

Slide 18

Slide 18 text

例2

Slide 19

Slide 19 text

例2)予約履歴データに対象キャンペーン情報を付与 reservation(200万件、11列) campaign(30件、3列)

Slide 20

Slide 20 text

例2)予約履歴データに対象キャンペーン情報を付与 reservation(200万件、11列) campaign(30件、3列)

Slide 21

Slide 21 text

例2)予約履歴データに対象キャンペーン情報を付与 # Not Awesome reservation |> cross_join(campaign) |> dplyr::filter(reserved_at >= starts_at & reserved_at <= ends_at) |> select(!c(starts_at, ends_at)) # Awesome campaign_expanded <- campaign |> rowwise() |> mutate(reserve_date = list(seq(date(starts_at), date(ends_at), by="day"))) |> unnest(reserve_date) reservation |> mutate(reserve_date = date(reserved_at)) |> left_join(campaign_expanded, by = "reserve_date",relationship = "many-to-many") |> select(!reserve_date)

Slide 22

Slide 22 text

# Not Awesome reservation |> cross_join(campaign) |> dplyr::filter(reserved_at >= starts_at & reserved_at <= ends_at) |> select(!c(starts_at, ends_at)) 例2)予約履歴データに対象キャンペーン情報を付与 予約履歴にキャンペーンマスターをクロス結合、その後キャンペーン期間の行のみを抽 出。最後に不要な列を削除。

Slide 23

Slide 23 text

# Awesome campaign_expanded <- campaign |> rowwise() |> mutate(reserve_date = list(seq(date(starts_at), date(ends_at), by="day"))) |> unnest(reserve_date) reservation |> mutate(reserve_date = date(reserved_at)) |> left_join(campaign_expanded, by = "reserve_date",relationship = "many-to-many") |> select(!reserve_date) 例2)予約履歴データに対象キャンペーン情報を付与 キャンペーンマスターにキャンペーン期間のすべての日付の列を追加。 日付をキーに予約履歴にキャンペーンマスターを結合。

Slide 24

Slide 24 text

例2)予約履歴データに対象キャンペーン情報を付与 Awesomeなコードの方がおよそ6倍速い!

Slide 25

Slide 25 text

全編はこちらで順次公開予定 https://morimotoosamu.github.io/awesomebook_v2/

Slide 26

Slide 26 text

Enjoy!