FireDucks
Compiler Accelerated DataFrame
Library with pandas API
2024/07/18
石坂一久

みんなのPython勉強会#106
1

はじめにFireDucksを使うために，本発表を聞く必要はありません
import fireducks.pandas as pd
あとはpandasだと思って使えば，数倍速いです．
※マシン環境やプログラムに依存します

本発表では，FireDucksがなぜ速いかをご紹介します．

本発表を聞いて，FireDucksを使ってみようかなと思って頂ければ幸いです
2

自己紹介
石坂 一久

Intel Xeon Phi（メニコア）（NEC セキュアシステムプラットフォーム研究所所属）＜これまでの関わってきた主な領域＞

自動並列化コンパイラ

並列処理・ベクトル処理
NEC SX-Aurora TSUBASA(スパコン)→ DataFrameコンパイラを作って，pandasを速くしよう！
https://pc.watch.impress.co.jp/docs/news/yajiuma/1238340.html
https://jpn.nec.com/hpc/sxauroratsubasa/specification/index.html

3

Demo
pd.read_csv(“data.csv”).rolling(60).mean()[“Close”].tail(1000).plot()

pandas （違いはimport文だけ） FireDucks

実行開始
ボタン

import pandas as pd

移動平均を計算するプログラム

import fireducks.pandas as pd

pandas: 4.06s

約15倍
FireDucks: 275ms
4

pandas高速化のニーズ
分析
収集

データ
レイク

データ
整備

学習用
データ

pandasが良く使われるデータ整備がデータ分析のボトルネックに⚫ 探索的データ解析，学習用データの作成などの前処理⚫ 単純な整形だけでなく，複雑なアルゴリズムも登場

学習モデル

活用

データサイエンティストの時間の40%以上

Anaconda The
State of Data
Science 2020

https://xtech.nikkei.com/atcl/learning/lectu
re/19/00110/00001/5大量のデータを使えるようになったけど...
扱うデータ量や処理の複雑化に伴い速度課題が顕在化
クラウドサーバーのメモリ容量

コモディティサーバーでも数百GBのメインメモリ[5] Ogleari, M. et al.: String figure: A scalable and elastic memory
network architecture, 2019 IEEE International Symposium on High
Performance Computer Architecture (HPCA), IEEE, pp. 647–660 (2019)6

pandasはなぜ遅い？
ほとんどの処理はシングルスレッド
実行

Eager実行（SQLのクエリプランナーが行うような最適化がされない）

遅い書き方ができてしまう

7

FireDucksのアプローチ
中間言語（IR）を介することで，APIの変更なく，最適化や実行を改善

ユーザープログラムを一度中間言語に変換

PythonFrontend
データフレーム用
中間言語（IR）

高速化1
pandasプログラムの高速化ノウハウを自動化

最適化パス
中間言語上での自動最適化

ユーザーAPIとは独立したバックエンドで実行

Multithreaded
Backend

高速化2
マルチスレッド実行
8

実行時コンパイラで実現
ライブラリ中に埋め込まれた実行時コンパイラで，使い勝手やAPIを変えずに高速化

ユーザープログラム

ユーザープログラム

pandas API

pandas API

pandasライブラリ関数groupbyjoin

dropnafiltersortcorr

FireDucks
ライブラリ関数groupbyjoin

dropnafilter

sort

corr

実行時
コンパイラ
9

データフレーム用中間言語
データフレームの要素処理を命令としたドメイン特化型の中間言語（IR）
pythonプログラム
pd.read_csv(“data.csv”).rolling(60).mean()[“Close”].tail(1000).plot()

FireDucks IR%t1 = read_csv('data.csv', %arg0)%t2 = rolling_aggregate(%t1, 60, 60, 'mean')%t3 = project(%t2, 'Close')%t4 = slice(%t3, -1000, None, 1)※: 最適化に適したSSA形式

1命令がデータフレーム操作の意味を持つので，データフレーム特化の最適化を行いやすい独自の中間言語を定義できるコンパイラフレームワークを利用（LLVMのサブプロジェクト）
10

Python Frontend
PythonFrontend

実際にデータフレーム処理をするのでなく，Define-by-run方式で中間言語の生成を行う

IR Builder

データフレーム用中間言語(IR)

最適化パス

IR Executor

Multithreaded
Backend

FireDucksの構造

現在のpython frontendはpandasと同じAPIを持つ
11

Define-by-runによる中間言語生成

read_csvを実行
pd.read_csv(“data.csv”).rolling(60).mean()[“Close”].tail(1000).plot()

FireDucks内部でread_csv opが生成される%t1 = read_csv('data.csv', %arg0)

この時点では実際のcsvファイルの読み込みは行われない

12

Define-by-runによる中間言語生成

read_csvを実行
pd.read_csv(“data.csv”).rolling(60).mean()[“Close”].tail(1000).plot()

FireDucks内部でread_csv opが生成される%t1 = read_csv('data.csv', %arg0)

この時点では実際のcsvファイルの読み込みは行われない

FireDucksのread_csvの実装（簡略版）
def read_csv(filename):value = irbuilder.build_op(OP_read_csv, filename)return DataFrame(value)13

Define-by-runによる中間言語生成

rolling.meanを実行
pd.read_csv(“data.csv”).rolling(60).mean()[“Close”].tail(1000).plot()rolling_aggregate opが生成される%t1 = read_csv('data.csv', %arg0)%t2 = rolling_aggregate(%t1, 60, 60, 'mean')14

Define-by-runによる中間言語生成__getitem__を実行（列の取り出し）pd.read_csv(“data.csv”).rolling(60).mean()[“Close”].tail(1000).plot()

rolling_aggregate opが生成される%t1 = read_csv('data.csv', %arg0)%t2 = rolling_aggregate(%t1, 60, 60, 'mean')%t3 = project(%t2, 'Close')15

Define-by-runによる中間言語生成

tailを実行pd.read_csv(“data.csv”).rolling(60).mean()[“Close”].tail(1000).plot()

slice opが生成される%t1 = read_csv('data.csv', %arg0)%t2 = rolling_aggregate(%t1, 60, 60, 'mean')%t3 = project(%t2, 'Close’)%t4 = slice(%t3, -1000, None, 1)

16中間言語の実行開始
特定のAPIが実行されると，中間言語の実行を開始（まとめて遅延実行）
plotを実行pd.read_csv(“data.csv”).rolling(60).mean()[“Close”].tail(1000).plot()%t1 = read_csv('data.csv', %arg0)%t2 = rolling_aggregate(%t1, 60, 60, 'mean')%t3 = project(%t2, 'Close’)%t4 = slice(%t3, -1000, None, 1)

plotはいくつかある評価ポイントの一つ（他には`__repr__`など）
print(df)__repr__はprint内で利用される
17

最適化パスでの自動最適化
PythonFrontend
IR Builder

データフレーム用
中間言語(IR)

最適化パスがIRをより良いIRに変換• IR変換として，各種のデータフレーム高速化テクニックを実装
最適化パス

IR Executor

Multithreaded
Backend

FireDucksの構造

現在も鋭意拡充中

18

1) projection pushdowns最適化
projection（列の抽出）を前出しすることで，中間データを削減
ユーザーが書いたプログラム実際に実行される処理

df = pd.read_csv("sample.csv")
sorted = df.sort_values("b")
result = sorted[["a"]]df = pd.read_csv("sample.csv")
df2 = df[[“a”, “b”]]
sorted = df2.sort_values("b")
result = sorted[["a"]]中間言語生成read_csv

read_csv

追加

sort_values“b”

project“a”

入力IR

projection
pushdown

project[“a”, “b”]

sort_values“b”

project“a”

出力IR

実行192) パターン最適化
特定の命令の組み合わせをより良い組み合わせに変換する
df[~df[“a”].isnull()]# a列がnulのl行を削除

df.dropna(“a”)
df[“timestamp”].dt.strftime(“%Y”).astype(int)# timestamp列から年の取り出し

df[“timestamp”].dt.year
groupby(“a”).sum().sort_values(“b”)
groupby(“a”, sort=False).sum().sort_values(“b”)# sort=Falseを追加

203) 集約特徴量計算向けの最適化集約特徴量計算の例

一時間単位の平均と最大値を元のテーブルに新しい列として追加する
time

元の計算フローval_max

10:20

100110120

10:30

120

10:30120110120

性能例（31列 x 2集約関数）

中間データを大幅削減（1/60）

x23

20

相対性能

groupby
max
join

join

val_mean

10025

groupbymean

groupby
max

val

10:20

最適化後のフロー

join
join

time

read_csv

read_csv
groupby
mean

val

追加

15
10x6.450

Pandas

FireDucks FireDucks
最適化なし 最適化あり

21

Backend
PythonFrontend
IR Builder

データフレーム用
中間言語

中間言語中の各命令を実行するカーネルの集合

CPU用のマルチスレッドバックエンド（C++）• データ構造にApache Arrowを利用• Arrowが提供するカーネルに加えて，並列化・最適化を強化したカーネルを追加

IR Executor

Multithreaded
Backend

FireDucksの構造22

Backendでの最適化例: groupby
df.groupby(“x”).sum()

グループ数推定グループ数が少ないときに向いた
並列groupbyアルゴリズム
元データ
xxya0c1b2b3a4c5c6a7

最初に均等分割

グループ数が多いときに向いた
並列groupbyアルゴリズム
xya0c1b2b3a4c5c6a7

localgroupby

キーで結合
local
groupby

最初にキーで分割

ya0b2b3a4

a7c1c5c6

localgroupby
単純に結合
localgroupby23互換性向上の仕組み: Fallback
PythonFrontend
IR Builder
データフレーム用
中間言語

Fallback
中間言語を作らずに，Frontendからpandasを直接呼び出す

互換性は上がるけど，性能は上がらない（FireDucksで速くならないときはほぼこれ）$ FIREDUCKS_FLAGS="-Wfallback" python -mfireducks.imhook demo.py
demo.py:4: FallbackWarning: Series.plot 0.201566 sec ...

※ Warningを出すことは可能（ご報告して下さい）
24

Tips
applyやループを利用しない

時間計測の注意（A列が2より大きい行のB列の合計）

ループ

s = 0
for i in range(len(df)):
if df["A"][i] > 2:s += df["B"][i]t0 = time.time()
df.sort_values(“a”)
t1 = time.time()
print(t1 – t0)
正しい時間計測ができない（遅延実行）

apply

s = 0
def func(row):
if row[“a”] > 2:s += row[“B”]
df.apply(func)s = df[df["A"] > 2]["B"].sum()df._evaluate()
t0 = time.time()
df.sort_values(“a”)._evaluate()
t1 = time.time()
print(t1 – t0)
明示的な実行の指示

25

FireDucksの性能 (要素処理 groupby, join)
Database-like ops benchmark (https://duckdblabs.github.io/db-benchmark)1位

3位

GroupbyJoin

26

FireDucksの性能 (TPC-Hベンチマーク Scale Factor=10)
100

評価環境
インテル® Xeon® Gold
5317 プロセッサー

10(12コア x 2ソケット)

10geomean

q22

q21

q20

q19

q18

q17

q16

q15

q14

q13

q12q11q10q09

q08

q07

q06

q05

q04

q03

Polars比: 最大12倍，平均1.9倍

メモリ: 256GB
OS: Linux
pandas 2.2.0
polars 0.20.7
FireDucks 0.10.1

ベンチマークコード
q22q21

q20

q19

q18

q17

q16

q15

q14

q13

q12

q11

q10

q09

q08

q07

q06

q05

q04

q03

geomean

0.1

q02

1q01

速度
向上率

q02

1q01

速度
向上率

pandas比: 最大104倍，平均25倍

https://github.com/fireducks-dev/polarstpch/tree/fireducks

27

FireDucksの性能（TPCx-BBベンチマーク）
ETL(抽出、変換、ロード)および機械学習のワークフロー• pandas-2.1.4• fireducks-0.9.3• CPU: Intel(R) Xeon(R) Gold 5317 CPU @ 3.00GHz x 2sockets （合計48HWスレッド）• メインメモリ: 256GB

28

DataFrameライブラリの比較

FireDucks
PolarsModin
Dask/Vaex
Pandaspandas互換性

シングルノード性能

マルチノード性能〇×〇△〇〇〇△△×××〇〇×29

FireDucksの利用
pipコマンドでインストール可能（BSDライセンス）$ pip install fireducks※ 現在はLinuxのみサポート（WSL可）import文の書き換えだけでなく，pandasからの自動変換も可能
pythonコマンドの引数で指定$ python3 -m fireducks.pandas program.py
jupyter notebookではマジックコマンド%load_ext fireducks.pandas
import pandas
30

Resource
Webサイトhttps://fireducks-dev.github.io/ja/

slack (Q&A，雑談)（ユーザーガイド，ベンチマークなど）

github (issue report)

twitter/X (リリース情報)
https://x.com/fireducksdev

https://github.com/fireducks-dev/fireducks

31

おわりに
FireDucksは，pandasのdrop-in replacementで使える高速データフレームライブラリです
実行時コンパイラ技術の活用により，pandasの弱点であるマルチスレッド実行，自動最適化を行います
ぜひご活用下さい32