2026年10月6日、Pythonの高速なデータ分析ライブラリPolarsの2.0.0が公開されました。2024年の1.0以来となる、メジャーバージョンの更新です。
速くなるのは嬉しい話です。けれども今回の2.0には、エラーを出さずに計算結果だけが変わる変更がいくつか含まれています。
公式の移行ガイドでも、そうした変更には赤い警告マークが付けられています。今回は、その中でも初心者が出会いやすいものを中心に見ていきます。
まずは何が変わったのかを整理しよう¶
移行ガイドに並ぶ変更はとても多いので、最初に今回取り上げるものを表にまとめます。どれも、Polarsの公式リポジトリにある移行ガイドに書かれた内容です。
| 変更 | 中身 | 結果が静かに変わるか |
|---|---|---|
| Lazy APIの標準エンジン | インメモリからストリーミングへ | 行の順番が変わることがある |
| explode() | 空のリストが行を作らなくなった | 行数が変わる |
| 整数の型の組み合わせ | Int64とUInt64の計算結果がFloat64からInt128へ | 型と値が変わる |
| read_csv() | 内部でscan_csv().collect()を使う形に | 一部の引数がなくなった |
| 非推奨だった機能 | melt()など古い書き方を削除 | エラーになる |
Polarsそのものがまだよくわからない方は、先にこちらを読んでおくと話がつながります。【関連記事】PythonのPolarsとは?
Lazy APIはストリーミングが標準に¶
いちばん大きな変更は、Lazy APIの標準エンジンです。LazyFrameのcollect()は、これまでどおりengine="auto"が既定ですが、そのautoが選ぶエンジンが変わりました。
1.xではautoがインメモリエンジンを選んでいたのに対し、2.0ではストリーミングエンジンを選びます。DataFrameを直接操作するEager APIは、これまでどおりインメモリのままです。
ストリーミングとは何か¶
インメモリエンジンは、データを全部メモリに載せてから処理します。ストリーミングエンジンは、データを小分けにして流しながら処理する方式です。
小分けに処理するぶん、メモリに収まらないほど大きなデータでも扱いやすくなります。Polarsが新しいエンジンに力を入れてきたのは、こうした大きなデータへの対応のためです。
行の順番に頼っていると危ない¶
ここで注意したいのが、行の順番です。移行ガイドには、ストリーミングエンジンはunpivotやgroup_by、結合などで、順番が必要ない操作では行の順番を保証しないと書かれています。
たまたま同じ順番で出てきていた結果に頼ったコードは、2.0で順番が入れ替わるおそれがあります。順番が大事なら、明示的にsortするか、maintain_orderを指定するよう案内されています。
私は10年ほどエンジニアとして開発に関わってきましたが、SQLでORDER BYを書き忘れたまま、たまたま正しい順で返っていた画面が、データベースの更新でいきなり崩れたことがあります。順番は、指定しない限り約束されていないと考えるのが安全です。
profile()は削除された¶
ストリーミングが標準になったことにともない、LazyFrameのprofile()も削除されました。処理の各段階にかかった時間を測るメソッドです。
移行ガイドによると、profile()はインメモリエンジン向けに作られたものでした。並行して動くストリーミングエンジンでは、段階ごとの時間がかえって誤解を招くため、外されたと説明されています。
explode()は空のリストで行を作らなくなった¶
2つ目は、explode()の動きです。explode()は、リストが入った列を、要素ごとの行に展開する操作です。
1.xでは、空のリストを展開すると、nullが1行できていました。2.0では、空のリストは0行になります。
実際に、新しい仮想環境に1.44.2と2.0.0をそれぞれ入れて、同じコードを動かしてみました。
import polars as pl
print("Polars", pl.__version__)
df = pl.DataFrame({"user": ["a", "b", "c"], "tags": [["x", "y"], [], ["z"]]})
print(df.explode("tags"))
try:
df.melt(id_vars="user")
print("melt() は使えました")
except AttributeError as e:
print(type(e).__name__)
まずは1.44.2での結果です。警告の部分は短く省略しています。
Polars 1.44.2
DeprecationWarning: In Polars 2.0, the default behavior for `empty_as_null` will change to `False`. ...
shape: (4, 2)
│ a ┆ x │
│ a ┆ y │
│ b ┆ null │
│ c ┆ z │
DeprecationWarning: `DataFrame.melt` is deprecated; use `DataFrame.unpivot` instead, ...
melt() は使えました
続いて2.0.0での結果です。bの行が消えて、3行になっているのがわかります。
Polars 2.0.0
shape: (3, 2)
│ a ┆ x │
│ a ┆ y │
│ c ┆ z │
AttributeRemovedError
空のリストしか持たないユーザーbは、2.0では結果から消えました。集計の前にexplode()している処理では、件数がずれる可能性があります。
1.xのままでも以前の動きを残したいときは、移行ガイドのとおりempty_as_null=Trueを明示すれば同じ結果になります。2.0でも、この引数を指定すれば1.xの動きを再現できます。
1.xの警告は、2.0の予告だった¶
先ほどの1.44.2の結果をよく見ると、DeprecationWarningが2つ出ていました。1つはexplode()の動きが2.0で変わること、もう1つはmelt()が非推奨であることを知らせるものです。
そして2.0では、予告どおりexplode()の結果が変わり、melt()はAttributeRemovedErrorというエラーになりました。移行ガイドによると、AttributeRemovedErrorは2.0で新しく加わった例外で、AttributeErrorの仲間です。
つまり、1.xの最新版で警告をきちんと消しておけば、2.0への移行はぐっと楽になります。警告は未来のエラーの予告だと考えてください。
DeprecationWarningの正体と、警告をエラーにして洗い出す方法は、こちらで詳しく解説しています。【関連記事】Pythonのwarningsとは?
削除された主な古い書き方¶
移行ガイドには、削除された機能と代わりの書き方が一覧になっています。その中から、よく使われていたものを2つ紹介します。
| 削除された書き方 | 代わりの書き方 |
|---|---|
| melt() | unpivot()。id_varsはindexに、value_varsはonに |
| with_row_count() | with_row_index()。列名の既定は"index" |
ネット上の古い記事やAIが出したコードには、まだmelt()がよく出てきます。2.0で動かないときは、まずこの表を思い出してください。
型の扱いや読み込みの細かな変更¶
ほかにも、気づきにくい変更がいくつかあります。代表的なものを見ておきましょう。
Int64のような符号付きの整数と、UInt64を組み合わせて計算した結果の型が、Float64からInt128に変わりました。移行ガイドによると、これまでは精度が落ちるFloat64だったものが、正確なInt128になります。
実際に、Int64の列とUInt64の列を足し算して比べてみました。
import polars as pl
df = pl.DataFrame(
{"a": [-1, 2], "b": [10, 20]},
schema={"a": pl.Int64, "b": pl.UInt64},
)
out = df.select(total=pl.col("a") + pl.col("b"))
print(pl.__version__, out["total"].dtype, out["total"].to_list())
1.44.2と2.0.0で実行した結果です。同じ計算でも、型と値の見た目が変わっています。
1.44.2 Float64 [9.0, 22.0]
2.0.0 Int128 [9, 22]
正確になるのはよいことですが、エラーは出ずに型と値が変わります。後ろの処理で型をFloat64だと決め打ちしていると、思わぬところで食い違いが起きるかもしれません。
read_csv()は、内部でscan_csv().collect()を呼ぶ形に変わりました。その結果、n_threadsやbatch_size、sample_size、rechunkといった引数はなくなっています。
さらに、columnsで列を指定したときは、ファイルの並びではなく指定した順番で列が返るようになりました。列の位置に頼ったコードを書いている方は確認しておきましょう。
pandasから来た人が気をつけたいこと¶
pandasからPolarsに乗り換えた方も多いと思います。そうした方にも関わる変更として、DataFrame Interchange Protocolへの対応が外されました。
これは、異なるデータフレームのライブラリどうしでデータを受け渡すための共通の約束ごとです。2.0では、DataFrame.__dataframe__()が削除され、pl.from_dataframe()はArrowのPyCapsuleという仕組みに対応したオブジェクトだけを受け付けます。
日常的にPolarsとpandasを行き来している方は、変換の部分で影響が出ないか確かめておくと安心です。pandasの基本は、こちらで紹介しています。【関連記事】pandasとは?
上げる前にやっておきたいこと¶
最後に、1.xから2.0へ上げるときの確認ポイントを整理します。移行ガイドの内容を、初心者向けに順番を付けて並べたものです。
| 順番 | 確認すること |
|---|---|
| 1 | 1.xの最新版に上げて、DeprecationWarningを全部消す |
| 2 | 行の順番に頼っている処理に、sortやmaintain_orderを入れる |
| 3 | explode()の前後で件数が変わらないか確かめる |
| 4 | 整数の型を決め打ちしている箇所を見直す |
| 5 | テストを2.0で一通り流して、結果を1.xと比べる |
準備ができるまでは、requirements.txtなどでpolars<2と上限を決めておくのも手です。先日紹介したSQLAlchemy 2.1と同じく、上げるタイミングは自分で決めるのが安全です。【関連記事】SQLAlchemy 2.1がリリース
以前、データ集計のバッチでライブラリを上げた直後、件数がわずかに合わないという報告を受けたことがあります。エラーが出ない変更ほど、上げる前と後の結果を突き合わせるひと手間が効いてきます。
まとめ¶
Polars 2.0.0が2026年10月6日に公開されました。Lazy APIの標準がストリーミングエンジンになり、explode()や整数の型の扱いなど、結果が静かに変わる変更も含まれています。
いちばん効く準備は、1.xの最新版で警告を消しておくことです。あとは、行の順番と件数を意識しながら、自分のタイミングで移行を進めてください。
ここまでお読みいただきありがとうございました。