"Python Polars: The Definitive Guide"への期待


# 初めに
2022年12月にPolarsの紹介記事を書いて以来、2023年はPolarsの"Blazingly fast"な更新に対し、自分のキャッチアップがなかなか追いつけない状態にありました。(当時はpython polars v0.15.3だったのに本記事の編集時点ではv0.20.0 🤯)

https://zenn.dev/hiro_torii/articles/06d7e845e146ee

そんな中ではありましたが6月に発表された、Python Polarsの技術書籍がオライリーから2024年に出版されるというニュース[^1]はインパクトが大きかったです。
今回はアドベントカレンダーの力を借りて、この"Python Polars: The Definitive Guide"への期待を書いてみます！



[^1]: https://twitter.com/jeroenhjanssens/status/1666072496121032706


# Python Polars: The Definitive Guide
"Python Polars: The Definitive Guide"は約400ページで2024Q3に発売予定となっています。O’Reilly側の[ページ](https://www.oreilly.com/library/view/python-polars-the/9781098156077/)やEarly Release版を見ると11月頃と思われるのですが、正確な時期はまだ不明です。

https://jeroenjanssens.com/pp/

上記の著者ページでは書籍の経緯[^2]や概要について説明があります。
[^2]: Polarsの作者であるRitchie Vink氏も序文を寄稿するようです。Ritchie氏は[PyData Amsterdam 2023の登壇](https://youtu.be/NJbBWDzZuWs?si=f3pYRY4qqYcx1EXJ)でもスライドの末尾で本書を宣伝していたので本書への期待が伺えます。

> Get ready to speed up your data analysis and start working with larger-than-memory datasets. Polars offers a blazingly fast, multi-threaded, elegant API for data loading, manipulation, and processing. Authors Jeroen Janssens and Thijs Nieuwdorp walk you through every aspect of Python Polars as they tackle practical use cases using real-world datasets. You’ll not only learn the syntax, but also understand the underlying concepts. You don’t need to have any experience with Pandas or Spark, but if you do, this book will help you make a smooth transition.

Python Polarsの構文だけでなく基礎的な概念について、実際のデータセットやユースケースを用いて学べる書籍らしく期待が膨らみます。
書籍の対象となるバージョンについて記載がなかったのですが、Polarsは爆速でアップデートされ続けているため、おそらく出版近くまで動作確認を並行して進めていくのではと推測しています。



## 章構成
まだ暫定ですが大筋として以下構成が考えられているようです。
~~~
- Part I: Getting Started
    - Chapter 1: Introducing Polars
    - Chapter 2: First Steps
    - Chapter 3: Transitioning from Pandas or Spark to Polars
- Part II: Concepts and Syntax
    - Chapter 4: Data Types and Data Structures
    - Chapter 5: Eager, Lazy, and Streaming APIs
    - Chapter 6: Reading and Writing Data
    - Chapter 7: Expressions
    - Chapter 8: Selecting and Creating Columns
    - Chapter 9: Filtering and Sorting Rows
    - Chapter 10: Working with Special Data Types
    - Chapter 11: Summarizing and Aggregating
    - Chapter 12: Joining and Concatenating
    - Chapter 13: Reshaping
- Part III: Advanced Topics
    - Chapter 14: Extending Polars
    - Chapter 15: SQL with Polars
    - Chapter 16: Debugging and Testing with Polars
    - Chapter 17: Polars Internals
    - Chapter 18: Integrating with Other Tools
~~~
Part IIを見ると、Polarsの概念や基本的なメソッドを網羅的に説明していく気配を感じます。個人的にはPart IIIのChapter 16, 17が特に気になります。
Chapter 16ではPolarsを使ったUnit Testや例外など、Polarsコードのデバッグとテスト方法について説明するとあり、普段なかなか類似の例を見ないので楽しみです。
Chapter 17では最適化や並列化といった、Rustで実装されたPolarsのコアな部分について1章でどれくらい説明できるのか期待しています。



## Early Release版を読んで

PolarsのDiscordコミュニティ[^3]から"Python Polars: The Definitive Guide"のEarly Release版を入手することができるので読んでみました。
Early Release版は2023/11/30にver.2が公開され、上記Chapter2, 4, 6を先行して読むことができます。

[^3]:Polarsの[GitHubリポジトリー](https://github.com/pola-rs/polars)にDiscordへのリンクが記載されています。

### First Steps
Polarsのセットアップや設定について説明しています。セットアップについてはDockerやJupyterを使用する場合、ソースからコンパイルする場合など一通りの手順が記載されています。
設定についてはコンテキストマネージャーやデコレーターで有効範囲を指定できるのと、JSON形式の文字列やファイルで設定を入出力できるといった見落としがちな部分まで補足がありました。
<details><summary>手元の環境でも試してみました</summary>

~~~python
>>> df = pl.DataFrame({"abc": [1.0, 2.5, 3.5, 5.0], "xyz": [True, False, True, False]})
>>> with pl.Config(tbl_rows=2):
...     df
... 
shape: (4, 2)
┌─────┬───────┐
│ abc ┆ xyz   │
│ --- ┆ ---   │
│ f64 ┆ bool  │
╞═════╪═══════╡
│ 1.0 ┆ true  │
│ …   ┆ …     │
│ 5.0 ┆ false │
└─────┴───────┘
# withブロックの外では設定が元に戻ります
>>> df
shape: (4, 2)
┌─────┬───────┐
│ abc ┆ xyz   │
│ --- ┆ ---   │
│ f64 ┆ bool  │
╞═════╪═══════╡
│ 1.0 ┆ true  │
│ 2.5 ┆ false │
│ 3.5 ┆ true  │
│ 5.0 ┆ false │
└─────┴───────┘

# 設定を出力
>>> pl.Config.set_tbl_rows(3)
<class 'polars.config.Config'>
>>> pl.Config.save()
'{"environment":{"POLARS_FMT_MAX_ROWS":"3"},"direct":{"set_fmt_float":"mixed","set_float_precision":null,"set_thousands_separator":"","set_decimal_separator":".","set_trim_decimal_zeros":false}}'
# 設定を入力
>>> pl.Config.load('{"environment":{"POLARS_FMT_MAX_ROWS":"5"},"direct":{"set_fmt_float":"mixed","set_float_precision":null,"set_thousands_separator":"","set_decimal_separator":".","set_trim_decimal_zeros":false}}')
<class 'polars.config.Config'>
>>> pl.Config.save()
'{"environment":{"POLARS_FMT_MAX_ROWS":"5"},"direct":{"set_fmt_float":"mixed","set_float_precision":null,"set_thousands_separator":"","set_decimal_separator":".","set_trim_decimal_zeros":false}}'
>>>
~~~
</details>

### Data Types and Data Structures
Polarsのデータ構造の土台であるApache Arrow形式と使用できるデータ型について説明しています。細かな補足や概念まで説明されていて自分の理解も深まりました。
例えば、以下のような説明が印象に残っています。

- Arrow形式では異なる言語間、プロセス間でデータセットの共有が可能なよう仕様定義されている(IPC; Inter Process Communication)
- Polarsの最適化を適用するためにも、Object型の使用は一般的に推奨されない
- Seriesは内部的にはChunkedArray(メモリがallocateされたデータ配列)で表され、チャンク単位で最適化や並列化が実行される(チャンクの管理は基本的にquery optimizerが行う)

コードを交えた実例では、適切なデータ型を使うことでメモリ使用量を効率化できる例を`cast()`を使って解説していました。

<details><summary>手元の環境でも試してみました</summary>

何かをパースした際に数値が文字列として読み込まれた場合、数値型にキャストをすると使用メモリも効率化されます。以下例は整数型`UInt8`と`UInt16`にキャストした場合です。
~~~python
>>> string_df = pl.DataFrame({"id": ["1", "2", "3"]})
>>> string_df
shape: (3, 1)
┌─────┐
│ id  │
│ --- │
│ str │
╞═════╡
│ 1   │
│ 2   │
│ 3   │
└─────┘
>>> string_df.estimated_size('b')
35 # bytes
>>> int_df = string_df.select(pl.col("id").cast(pl.UInt8))
>>> int_df
shape: (3, 1)
┌─────┐
│ id  │
│ --- │
│ u8  │
╞═════╡
│ 1   │
│ 2   │
│ 3   │
└─────┘
>>> int_df.estimated_size('b')
3 # bytes
>>> int_df = string_df.select(pl.col("id").cast(pl.UInt16))
>>> int_df
shape: (3, 1)
┌─────┐
│ id  │
│ --- │
│ u16 │
╞═════╡
│ 1   │
│ 2   │
│ 3   │
└─────┘
>>> int_df.estimated_size('b')
6 # bytes
~~~
キャストできないデータが含まれている場合はエラーになります。
~~~python
>>> string_df = pl.DataFrame({"id": ["1", "b", "3"]})
>>> string_df.estimated_size('b')
35
>>> int_df = string_df.select(pl.col("id").cast(pl.UInt8))
Traceback (most recent call last):
  (略)
polars.exceptions.ComputeError: conversion from `str` to `u8` failed in column 'id' for 1 out of 3 values: ["b"]

~~~
</details>

### Reading and Writing Data
データの入出力について代表的なケースへフォーカスして説明しています。とはいえ、以下のような説明が記載されていて十分に網羅的だと感じました。
- CSV, Excel, Parquet, JSON, NDJSON, その他(Arrow形式やAvro形式など)の読み込み
- CSV, Excel, Parquet, JSON, Avro形式での書き込み
- 欠損値の扱いについて
- UTF-8以外の文字エンコーディングの扱いについて[^4]
- 複数CSVに渡るファイルの一括読み込みやDataFrameの連結について
- Pandas DataFrameからPolars DataFrameへの変換について
- RDBとの接続方法

[^4]: UTF-8以外の文字エンコーディングを読み込む節では、EUC-CNかEUC-JPか判定する例が取り上げられていて、文字コードややこしくて申し訳ない…という気持ちになりました。


# 終わりに
Python Polarsの概念を深く理解できそうな書籍で期待が膨らみます。2024年の後半になるとは思うのですが、"Python Polars: The Definitive Guide"の発売が今から楽しみです。さらに、別の書籍で"Polars Cookbook"[^5]というPython Polarsの"How"によりフォーカスした実践的な書籍も出版されるらしく、こちらも楽しみです。

また、エンタープライズでのPolars活用を促進するための会社設立が2023年8月に発表されたり[^6]と、2024年もPolarsの進化に注目していきたいと思います！

https://twitter.com/RitchieVink/status/1687041562964901889


[^5]: https://www.linkedin.com/feed/update/urn:li:activity:7109891408701886464/
2024Q2頃に出版予定らしいです。

[^6]: https://pola.rs/posts/company-announcement/
ちなみにPolars自体はMITライセンスを持ったOSSとして、これからも継続的に開発されます。