Slide 1

Slide 1 text

Polars と遅延評価
 関西 Kaggler 会 in Osaka 2023#3
 johannyjm1


Slide 2

Slide 2 text

自己紹介
 ❖ johannyjm1 (Yoshitaka Tomiyama)
 ❖ 𝕏 で仲良くなった人と飲むのが趣味
 ❖ 好きなギタリストは
 Yngwie Johann Malmsteen (YJM)


Slide 3

Slide 3 text

弁財天参加者募集!
 ❖ AI ミュージックバトル!『弁財天〜第二幕〜』 
 ❖ 伴奏に AI でメロディを乗せる! 
 ❖ 皆で聴いて良い方に投票! 
 ❖ バトル型トーナメント!! 
 ❖ 10/28 土 (来週!!!)
 benzaiten-online.com で
 予選投票中!!!!!!!


Slide 4

Slide 4 text

Polars とは


Slide 5

Slide 5 text

Polars
 ❖ lightning-fast⚡なデータフレームライブラリ
 ➢ 実行も速いし、メモリ効率も良い 
 ❖ Kaggler 界隈には OTTO コンペを通して盛り上がりを見せる
 ❖ 現在 Polars の本を執筆中


Slide 6

Slide 6 text

Polars は何故速い?
 ❖ バックエンドが Rust で書かれている
 ➢ Polars の rs は Rust
 ❖ マルチコアでの並列処理を可能な限り利用する
 ➢ Embarrasingly parallel
 ❖ 遅延評価を提供する API、クエリ最適化
 https://www.pola.rs/posts/i-wrote-one-of-the-fastest-dataframe-libraries/

Slide 7

Slide 7 text

Polars は何故速い?
 ❖ バックエンドが Rust で書かれている
 ➢ Polars の rs は Rust
 ❖ マルチコアでの並列処理を可能な限り利用する
 ➢ Embarrasingly parallel
 ❖ 遅延評価を提供する API、クエリ最適化
 https://www.pola.rs/posts/i-wrote-one-of-the-fastest-dataframe-libraries/ 今日はこれについて話します!


Slide 8

Slide 8 text

遅延評価


Slide 9

Slide 9 text

遅延評価とは
 式の評価を「必要になるまで」行わない、サボる仕組みのこと


Slide 10

Slide 10 text

遅延評価とは
 式の評価を「必要になるまで」行わない、サボる仕組みのこと
 ❖ 逐次的に評価を行うのは正格評価
 ➢ これらの規則群を評価戦略などという 
 ❖ Polars の機能としては遅延評価:Lazy API、正格評価:Eager API として 提供される
 ❖ 
 ❖ ガチ目の内容は Haskell の話とかをする必要があるため、本日は「ざっく り」

Slide 11

Slide 11 text

遅延評価が嬉しいケース
 クソデカ配列を作成し、先頭の 5 要素を取得する


Slide 12

Slide 12 text

遅延評価が嬉しいケース
 クソデカ配列を作成し、先頭の 5 要素を取得する
 ❖ 正格評価の場合、クソデカ配列をちゃんと作るのでおそい
 ❖ 遅延評価の場合、配列作成は一旦サボる→要素が 5 個だけ必要と分 かってから処理を行うのですぐに終わる


Slide 13

Slide 13 text

Python における遅延評価


Slide 14

Slide 14 text

Python における遅延評価
 generator... の前に range オブジェクトから


Slide 15

Slide 15 text

Python における遅延評価
 generator... の前に range オブジェクトから
 5000 兆要素を
 作ってはいない


Slide 16

Slide 16 text

Python における遅延評価
 generator:クソデカ配列のように定義されるが、必要な分しか取得されない


Slide 17

Slide 17 text

Python における遅延評価
 おまけ:range でお手軽 generator の作成


Slide 18

Slide 18 text

Python における遅延評価
 おまけ:range でお手軽 generator の作成
 角カッコ [ ] を使うと
 5000 兆個作っちゃうので注意 


Slide 19

Slide 19 text

Python における遅延評価
 短絡評価(short-circuit evaluation)・・遅延評価の一種


Slide 20

Slide 20 text

Python における遅延評価
 短絡評価(short-circuit evaluation)・・遅延評価の一種
 ❖ and での評価なので片方が False なら式全体が False →もう片方は評価されない 
 ➢ こう書くことで idx に out of range な値が来ても右辺で IndexError にならない

Slide 21

Slide 21 text

Polars における遅延評価


Slide 22

Slide 22 text

Polars における遅延評価
 ❖ クソデカ CSV に対して
 ➢ データフレームとして読み込む 
 ➢ 先頭の N 行を取得する(もしくは 先頭の N 行を用いて値を計算する) 
 Polars でも同じようなことができる


Slide 23

Slide 23 text

Polars における遅延評価
 ❖ クソデカ CSV に対して
 ➢ データフレームとして読み込む 
 ➢ 先頭の N 行を取得する(もしくは 先頭の N 行を用いて値を計算する) 
 Polars でも同じようなことができる
 正格評価:Eager API
 693ms
 遅延評価:Lazy API
 33ms


Slide 24

Slide 24 text

遅延評価とクエリ最適化
 必要になるまで評価をしない→蓄積されたクエリを最適化してくれる
 正格評価:Eager API
 2.89s
 遅延評価:Lazy API
 445ms


Slide 25

Slide 25 text

遅延評価機能 Lazy API の使い方


Slide 26

Slide 26 text

遅延評価機能 Lazy API の使い方
 いつもの df に対し df.lazy() とするだけで LazyFrame クラスになってくれる


Slide 27

Slide 27 text

遅延評価機能 Lazy API の使い方
 いつもの df に対し df.lazy() とするだけで LazyFrame クラスになってくれる
 ❖ 最初から LazyFrame で読み込むことも可(この時点でデータは読まれない)


Slide 28

Slide 28 text

遅延評価機能 Lazy API の使い方
 ➢ 一部 pandas-like な書き方をサポートしていないがち( df["col"] みたいな列抽出とか) 
 ■ pivot もできない(代替手段はある) 
 LazyFrame は DataFrame と「基本的」に同様に操作できる


Slide 29

Slide 29 text

遅延評価機能 Lazy API の使い方
 ➢ 蓄積されたクエリはいい感じに最適化される 
 ■ filter や select は最初にやる、みたいなシンプルなものから最適な型への変換や結合順序 の推定までさまざま。詳しくは Polars book へ
 一連の操作(エクスプレッション)はクエリとして蓄積されていく


Slide 30

Slide 30 text

遅延評価機能 Lazy API の使い方
 ➢ 蓄積されたクエリはいい感じに最適化される 
 ■ filter や select は最初にやる、みたいなシンプルなものから最適な型への変換や結合順序 の推定までさまざま。詳しくは Polars book へ
 一連の操作(エクスプレッション)はクエリとして蓄積されていく
 正格評価:Eager API
 1.06s(処理完了)
 遅延評価:Lazy API
 391μs(クエリ蓄積のみ)


Slide 31

Slide 31 text

遅延評価機能 Lazy API の使い方
 ➢ こうすることでようやく中身が見えるので、 EDA や初期構築時など中身を頻繁に確認したい場面に は向かないかも
 lf.collect() とすることで式が評価され、データフレームが具体化


Slide 32

Slide 32 text

遅延評価機能 Lazy API の使い方
 ➢ こうすることでようやく中身が見えるので、 EDA や初期構築時など中身を頻繁に確認したい場面に は向かないかも
 lf.collect() とすることで式が評価され、データフレームが具体化
 LazyFrame を表示すると
 蓄積されたクエリが見える 
 LazyFrame.collect()
 で具体化


Slide 33

Slide 33 text

Streaming API
 ❖ Lazy API の機能の一つ(開発中だけど使える)
 ❖ collect の引数に streaming=True を渡すだけ
 ❖ クエリ最適化の結果「結局使うデータ」のみを処理する。爆速
 ❖ すべての操作でサポートされているわけでない
 ➢ Eager API、Lazy API、Streaming API における「この記述はできるけど、これはできない」みたい なやつはチョットわからない(アップデートでどんどん変わりそう) 


Slide 34

Slide 34 text

Lazy API が嬉しいケース


Slide 35

Slide 35 text

Lazy API が嬉しいケース
 ❖ Lazy API を使うことで顕著にパフォーマンス向上が見込めるケースについて johannyjm1 が確認しているのは以下
 ➢ ① Streaming API を利用している、かつ具体化されるデータ件数が元データより減っている場合 
 ➢ ②相当“無駄のある”クエリを書いちゃっているとき 
 ■ しかし、一連の記述においては気づかないがち 
 ①クソデカ CSV 読 み込み
 ↓
 先頭 100 行取得 
 
 Eager API: 693ms
 Lazy API: 33ms
 ②無駄クエリ
 
 
 Eager API: 2.89s
 Lazy API: 445ms


Slide 36

Slide 36 text

Lazy API が嬉しいケース
 ❖ というか Eager API も裏で普通に Lazy API を呼んでいる
 ❖ 余計なことしなくても全部 Eager API で良い日は来るかもしれない
 それ以外はまちまち... Eager API も普通に速い


Slide 37

Slide 37 text

Lazy API が嬉しいケース
 Lazy API でしか書けない記述 ≒ 並列化などの最適化も受けやすい記述だと信じ
 df.lazy() する習慣をつけるのはきっと良いこと である
 しかし、この LT で一番言いたいこと


Slide 38

Slide 38 text

まとめ


Slide 39

Slide 39 text

まとめ
 ❖ Polars はさまざまな理由で高速だが、今回は遅延評価に注目した
 ➢ 遅延評価とは Python を普段書いてると意識しにくいが、案外身近な便利評価戦略である 
 ❖ Polars の遅延評価機能は Lazy API として非常にシンプルに導入できる
 ➢ Lazy API の性能はそこそこだが、使ってるときっと良いことがある 
 ❖ 弁財天をお楽しみに!!!!!!!!!!!!!!!


Slide 40

Slide 40 text

EOF
 Lazy API を感じられる Colab. を作成しました!
 是非試してみてください!
 (後ほど X でも投稿します)