Ibis(読み方はアイビス)は、DuckDBやBigQuery、PostgreSQLなど22種類のデータ処理エンジンを、同じPythonコードのまま操作できるデータフレームライブラリです。PyPIでの配布名はibis-frameworkで、鳥のトキやイビスホテル、お絵かきアプリのアイビスペイントとは関係ありません。
2026年10月29日時点の最新版は12.0.0です。ただし10月21日にDuckDB 2.0.0が公開されたことで、手順どおりpip installするとIbisの一部APIが例外で止まる環境ができあがります。この記事では、Ibisの仕組みと対応バックエンド、掲載コードで動作確認したバージョンの指定方法、出力付きの基本操作、11.0と12.0で変わった書き方までを、手元で実行した結果をもとに解説します。
まとめ:Ibis(Python)の要点
- Ibisは計算をしないデータフレームAPIです。式を組み立て、SQLバックエンドではSQLGlotでSQLへ、PolarsバックエンドではLazyFrameへ変換して実行させます。
- 12.0.0の対応バックエンドは22種類で、既定はDuckDBです。pandasとDaskのバックエンドは10.0で削除されました。
- 2026年10月29日時点では、
pip install "ibis-framework[duckdb]"だけで入れるとDuckDB 2.0.0とsqlglot 30.25.0が入り、Table.sql()・con.sql()・list_tables()・DataFrameからのcreate_table()が失敗します。"duckdb<2" "sqlglot<30.18"を同時に指定してください。 - 11.0で
ibis.case()が削除され(代わりはibis.cases())、12.0でPython 3.9のサポートが終わりました。古い記事のコードはこの2点で止まりやすくなっています。 - メモリに載らないデータを扱う場合や、ローカルで書いた集計を本番のDWHへそのまま持っていきたい場合に向きます。単一環境の小さなデータならpandasかPolarsを直接使うほうが速く書けます。
Ibis(Python)とは:計算をバックエンドに任せるデータフレームAPI
Ibis自身はデータを計算しません。Pythonで書いた絞り込みや集計を「式(expression)」として組み立て、実行を指示された時点で接続先のエンジンが理解できる形に変換して渡します。計算はDuckDBやBigQueryの中で走るため、数十GBのテーブルでも全行をPythonのメモリに読み込まずに集計できます。
SQLバックエンドの仕組み:SQLGlotによる式の変換
公式のWhy Ibis?には、IbisはSQLGlotを使ってIbisの式をSQL文字列へ変換すると書かれています。2024年4月30日公開の9.0.0でSQLバックエンドのSQLGlot移行が進み、SQLAlchemyはコードベースから外されました。SQLGlot単体の使い方はSQLGlotとは?Python SQLパーサの使い方|parse_one・transpile・方言変換を30.24で実測で扱っています。
この構造のため、IbisはSQLGlotの版にも影響を受けます。後述するsqlglot 30.18.0以降での失敗はその一例です。
開発元・ライセンス・最新版
| 項目 | 内容 |
|---|---|
| 最新版 | 12.0.0(2026-02-07) |
| 対応Python | 3.10以上 |
| ライセンス | Apache License 2.0 |
| 作者 | Wes McKinney(pandasの作者) |
| 主要スポンサー | Voltron Data |
| PyPIの配布名 | ibis-framework |
版と対応PythonはPyPIのibis-framework、作者とスポンサーは公式のWho supports Ibis?によります。12.0.0の公開から8か月以上たちますが、GitHubのmainブランチには2026年10月も複数のコミットがあり、開発は続いています。次の13.0.0の準備を追うissue #12102には、Polars 2.0とDuckDB 2.0への対応が項目として並んでいます。
「ibis」の読み方と、同じ名前の別物
読み方は「アイビス」です。英語のibisはトキ科の鳥を指し、宿泊チェーンのイビス(ibis)やアイビスペイント(ibisPaint)も同じ綴りですが、本記事のIbisとは無関係です。
Python環境で注意したいのはPyPIのibisパッケージです。こちらはテンプレートエンジン(最終版3.3.0・2023年11月)で、pip install ibisと打つとデータフレームのIbisではなくこちらが入ります。公式のBasicsチュートリアルも、ibis-frameworkはPyPIのibisとは別物だと注意しています。どちらもimport ibisで読み込むため、同じ環境に入れると片方が上書きされます。
対応バックエンド22種とDuckDBが既定である理由
12.0.0をインストールした環境でバックエンドの登録(entry points)を数えると22種類でした。公式トップページの「20以上」と一致します。
| 実行場所 | バックエンド |
|---|---|
| ローカル・組み込み | DuckDB(既定), Polars, DataFusion, SQLite |
| クラウドDWH | BigQuery, Snowflake, Databricks, Athena |
| 分散処理・クエリエンジン | PySpark, Trino, Impala, Druid |
| ストリーミング | Flink, RisingWave, Materialize |
| RDB | PostgreSQL, MySQL, Oracle, MS SQL Server |
| 分析DB | ClickHouse, Exasol, SingleStoreDB |
接続先を指定せずにibis.read_csv()やibis.memtable()を使うと、プロセス内のDuckDBで動きます。DuckDBはサーバーを立てずにCSVやParquetを直接集計できるため、ノートブックで試してから本番のBigQueryへ向ける流れの出発点になります。DuckDB自体の特徴はDuckDBとは?特徴・用途とSQLite・PostgreSQLとの違いを実測で解説【1.5.6対応】、DataFusionはApache DataFusionとは?Rust製SQLクエリエンジンの実行計画と導入手順【2026年9月版】を参照してください。
pandas・Daskバックエンドは10.0で削除
以前の記事にあるpandasバックエンドとDaskバックエンドは、公式のpandasバックエンドのページのとおりIbis 10.0で削除されています。ibis.pandas.connect()を含むコードは12.0.0では動きません。pandasのDataFrameは入力(ibis.memtable(df))と出力(to_pandas())として引き続き使えるので、計算はDuckDBに任せて結果だけpandasで受け取る形に書き換えます。
Ibisのインストール:DuckDB・SQLGlotの互換性とバージョン指定
2026年10月29日時点で公式どおりにインストールすると、Ibisが対応していない新しい依存パッケージが入ります。12.0.0の依存指定はDuckDBがduckdb!=1.3.0,>=0.10.3、SQLGlotがsqlglot!=26.32.0,>=23.4で、どちらも上限がありません。実際に空の環境でpip install "ibis-framework[duckdb]"を解決させると、DuckDB 2.0.0とsqlglot 30.25.0が選ばれました。
次のように両方の上限を付けて入れてください。
pip install "ibis-framework[duckdb]==12.0.0" "duckdb<2" "sqlglot<30.18"
この指定で入るのはDuckDB 1.5.6とsqlglot 30.17.0です。この組み合わせで、本記事のコードと下の表のAPIがすべて動くことを確認しました。DuckDB公式のIbisガイドもIbis 12.0.0以前はDuckDB 2.0に対応していないと警告し、'duckdb<2'を付けたインストールを案内しています。SQLGlotとの組み合わせについては、今回の検証環境で失敗を確認しました。Polarsバックエンドも使うなら[duckdb,polars]とします。
DuckDB 2.0.0で失敗するAPI
Ibis 12.0.0(sqlglot 30.17.0)で、DuckDBだけを1.5.6と2.0.0に差し替えて、APIごとに新しい接続を作って実行しました。
| API | DuckDB 1.5.6 | DuckDB 2.0.0 |
|---|---|---|
| filter・group_by・aggregate→execute | 成功 | 成功 |
| to_pandas・to_pyarrow・to_parquet・to_csv | 成功 | 成功 |
| read_csv・read_parquet・con.table | 成功 | 成功 |
| Table.sql・con.sql | 成功 | AttributeError |
| list_tables | 成功 | AttributeError |
| to_pyarrow_batches | 成功 | AttributeError |
エラーの内容は'_duckdb.DuckDBPyConnection' object has no attribute 'fetch_arrow_table'(to_pyarrow_batchesではfetch_record_batch)です。DuckDB 2.0でPython接続オブジェクトからこれらのメソッドがなくなったためで、to_pyarrow_batchesについてはissue #12196で報告されています。
やっかいなのは、失敗した後も接続が使えなくなる点です。Table.sql()が落ちた直後に同じ接続でcon.table()を呼ぶと、今度はResourceInUseException(未完了の結果が残っている)になりました。最初のエラーを見落とすと、無関係な箇所が壊れたように見えます。DuckDB 2.0側の変更点はDuckDB 2.0とは:2.0.0 LTSの変更点・Quackサーバーモード・新ストレージ形式と1.x系からの移行手順【2026年10月】にまとめています。
sqlglot 30.18.0〜30.25.0でのcreate_tableの失敗
DuckDBを1.5.6に固定しても、sqlglotが新しいままだとcon.create_table("s", df)のようにpandas・PyArrow・PolarsのDataFrameからテーブルを作る処理がParserException: syntax error at end of inputで止まります。sqlglotの版を1つずつ入れ替えたところ、30.17.0(2026-08-12)までは成功し、30.18.0(2026-09-03)から失敗しました。30.25.0まで同じ結果です。
同じデータでもibis.memtable(df)を経由したテーブル式や、create_table()にIbisのテーブル式を渡す場合は成功します。版を固定できない環境では、DataFrameを一度ibis.memtable()で包んでから渡すと回避できます。
Ibisの使い方:filter・group_by・aggregateによる集計
ここからは上の推奨構成(Python 3.12.13・Ibis 12.0.0・DuckDB 1.5.6)で実行したコードと出力です。外部ファイルを使わずに再現できるよう、データはibis.memtable()で作ります。CSVならibis.read_csv("sales.csv")、Parquetならibis.read_parquet("sales.parquet")に置き換えるだけです。
import ibis
from ibis import _
# メモリ上のデータからテーブル式を作る
t = ibis.memtable({
"store": ["東京", "東京", "大阪", "大阪", "福岡"],
"item": ["A", "B", "A", "C", "A"],
"sales": [120, 80, 230, 50, 90],
})
# 絞り込み→店舗別集計→並べ替え(ここではまだ実行されない)
expr = (
t.filter(_.sales >= 80)
.group_by("store")
.aggregate(total=_.sales.sum(), n=_.count())
.order_by(ibis.desc("total"))
)
# 実行して pandas.DataFrame で受け取る
print(expr.to_pandas())
store total n
0 大阪 230 1
1 東京 200 2
2 福岡 90 1
filterからorder_byまでを書いた時点では何も計算されません。to_pandas()を呼んだときに初めてIbisがSQLを生成し、DuckDBが集計して結果を返します。
deferred式「_」によるテーブル変数の省略
上のコードの_.salesは、from ibis import _で読み込むdeferred式です。公式のメソッドチェーンの解説にあるとおり、直前のテーブルを変数で指さずに列を参照できます。テーブル変数を使う書き方(t.sales)では、aggregateで作ったtotalのような新しい列を次の処理で参照するときに、中間結果をいったん変数で受け取ることになります。_を使えばチェーンを切らずに書けます。
ibis.to_sqlによる生成SQLの確認
ibis.to_sql()は実行せずにSQLだけを返します。dialectを指定すると、接続していないエンジン向けのSQLも出せます。上のexprをBigQuery向けに出力した結果です(一時テーブル名は実行ごとに変わります)。
print(ibis.to_sql(expr, dialect="bigquery"))
SELECT
*
FROM (
SELECT
`t1`.`store`,
SUM(`t1`.`sales`) AS `total`,
COUNT(*) AS `n`
FROM (
SELECT
*
FROM `ibis_pandas_memtable_xxxx` AS `t0`
WHERE
`t0`.`sales` >= 80
) AS `t1`
GROUP BY
1
) AS `t2`
ORDER BY
`t2`.`total` DESC
識別子がバッククォートで囲まれ、BigQueryの書式になっています。dialect="duckdb"では二重引用符になり、dialect="postgres"では並べ替えにNULLS LASTが付きました。既存のSQLとの突き合わせや、DWHの課金前にクエリを確認したいときに使います。
Table.sql・con.sqlによるSQLとPython式の併用
既存のSQLを生かしたい場合は、con.sql("SELECT ...")やt.sql("SELECT ...")でSQLの結果をテーブル式として受け取り、その後ろにPythonのメソッドをつなげられます。この2つは前述のとおりDuckDB 2.0.0で失敗するAPIなので、使う前にduckdb.__version__が1系かを確認してください。
結果の受け取り方とinteractiveモード
式を実行するメソッドは、受け取りたい形式で選びます。以下のto_pandas()・to_polars()・to_pyarrow()の戻り値はテーブル式の場合です。列式ではSeriesやArrowの配列、スカラー式では単一の値になります。
| メソッド | 戻り値 |
|---|---|
| execute() | pandasのDataFrame・Series・スカラー |
| to_pandas() | pandasのDataFrame |
| to_polars() | PolarsのDataFrame |
| to_pyarrow() | PyArrowのTable |
| to_parquet() ・ to_csv() | ファイルへ書き出し |
execute()はPolarsバックエンドでもpandasのDataFrameを返します。Polarsバックエンドのリファレンスにもそう書かれており、実際にpcon.execute(expr)の戻り値はpandasのDataFrameでした。Polarsの形式で欲しいときはto_polars()を使います。
ノートブックで中身を見ながら進めるならibis.options.interactive = Trueにします。公式の設定ガイドのとおり、式を表示したときに実行して結果を表で出すモードで、既定の表示行数(ibis.options.repr.interactive.max_rows)は10でした。バッチ処理では既定のFalseのままにして、最後にto_parquet()などで明示的に実行します。
DuckDB・Polars間での処理関数の再利用
使用する演算とデータ型を両方のバックエンドがサポートしていれば、テーブルの作り方を変えて同じ関数を別のエンジンで実行できます。次のコードは、同じtop_stores()をDuckDBとPolars(2.1.0)で実行した例です。
import ibis
from ibis import _
import polars as pl
df = pl.DataFrame({"store": ["東京", "大阪", "福岡"], "sales": [200, 250, 90]})
def top_stores(t):
return t.filter(_.sales >= 100).order_by(ibis.desc("sales"))
for con in (ibis.duckdb.connect(), ibis.polars.connect()):
t = con.create_table("sales", df)
print(con.name, top_stores(t).to_pyarrow().to_pydict())
duckdb {'store': ['大阪', '東京'], 'sales': [250, 200]}
polars {'store': ['大阪', '東京'], 'sales': [250, 200]}
本番のBigQueryやSnowflakeでは、ibis.bigquery.connect(...)のように接続部分を差し替え、con.table("テーブル名")で既存のテーブルを参照します。集計ロジックの関数は、移植先が使用する演算とデータ型に対応している場合に再利用できます。移植時には生成SQLと実行結果も確認してください。なお、Polars 2.0への対応修正(PR #12147)は2026年10月18日にmainへ入ったもので、12.0.0には含まれていません。上の単純な絞り込みと並べ替えは12.0.0とPolars 2.1.0の組み合わせで動きましたが、配列の展開など一部の関数はPolars 2.0で挙動が変わっているので、Polarsバックエンドを本番で使うなら"polars<2"での固定も検討してください。
11.0・12.0で変わった書き方
2024年以前の記事やサンプルを写すと、次の箇所で止まります。
| 版 | 変更 | 書き換え |
|---|---|---|
| 10.0 | pandas・Daskバックエンド削除 | DuckDBで計算しto_pandas() |
| 11.0 | ibis.case()削除 | ibis.cases() |
| 11.0 | memtableの名前指定を廃止 | create_table()かcreate_view() |
| 12.0 | Python 3.9のサポート終了 | Python 3.10以上 |
| 12.0 | PySpark 3.5未満のサポート終了 | PySpark 3.5以上 |
| 12.0 | decimalの桁数・小数桁を推論 | 型を明示している箇所を確認 |
11.0の変更は11.0.0のリリースノート、12.0の変更は公式のリリースノートによります。12.0.0ではibis.caseは存在せず、ibis.memtableの引数にも名前の指定はありませんでした。ibis.cases()は条件と値の組を並べて書きます。
t.mutate(size=ibis.cases((_.sales >= 100, "大"), else_="小"))
12.0.0で増えた機能には、MERGE INTOを使うupsert()、MaterializeとSingleStoreDBのバックエンド追加、pandas 3.0.0への対応があります。
pandas・Polarsとの使い分け:Ibisを選ぶ条件と避ける場面
Ibisはpandasの上位互換ではなく、SQLへ変換する層が1枚入るぶん向く場面が限られます。
Ibisを選ぶ条件
次のどちらかに当てはまるなら、Ibisを入れる価値があります。1つ目は、データがPythonのメモリに載らず、DuckDBやBigQueryの側で集計させたい場合です。2つ目は、ローカルで書いた集計ロジックを、BigQueryやSnowflakeなど別のエンジンでも、対応する演算の範囲で同じコードを動かしたい場合です。エンジンごとにSQLの方言を書き分ける手間が減り、ibis.to_sql()で生成SQLのレビューもできます。DWHやデータ基盤の設計からまとめて見直したい場合は、データ分析基盤構築・MLOps構築支援のような外部支援を使う選択肢もあります。
Ibisを避ける場面
データがメモリに収まり、実行先を変える予定がなく、既存のpandas・Polars処理にも支障がないなら、Ibisの新規導入は勧めません。pandasかPolarsを直接使うほうが、学習することも依存パッケージも少なく済みます。行ごとの細かな加工や、NumPy配列などを入力に取るscikit-learn等のライブラリへの受け渡しが中心の処理も、SQLへの変換が回り道になります。
依存の固定ができない環境も避けたほうが無難です。本記事で見たとおり、12.0.0はDuckDBとsqlglotの新版で一部APIが落ちます。requirements.txtやロックファイルで版を固定する運用がない現場では、ある日突然動かなくなるリスクを抱えます。単一環境での高速化が目的ならPolarsとは?pandasとの違い・高速化の仕組みと実務での採用判断【実装目線】を、pandas自体の最新動向はPandasとは?できること・使い方とPandas 3.1の変更点【2026年10月】を参照してください。
よくある質問
Ibisの読み方は?
「アイビス」と読みます。プロジェクト名はibis-project、PyPIの配布名はibis-framework、Pythonで読み込むときのモジュール名はibisです。
pip install ibisでインストールしてもよいですか?
いいえ。PyPIのibisはテンプレートエンジンという別のパッケージです。データフレームのIbisはpip install "ibis-framework[duckdb]==12.0.0" "duckdb<2" "sqlglot<30.18"のようにibis-frameworkを指定して入れます。
Ibisは無料で使えますか?
はい。Apache License 2.0のオープンソースで、無料で使えます。BigQueryやSnowflakeを接続先にした場合は、そのエンジンの利用料金が別にかかります。
IbisはDuckDB 2.0で使えますか?
2026年10月29日時点の12.0.0では、Table.sql()・con.sql()・list_tables()・to_pyarrow_batches()が例外になります。"duckdb<2"で1系に固定してください。
Ibisでpandasバックエンドは使えますか?
使えません。pandasバックエンドとDaskバックエンドはIbis 10.0で削除されました。ローカルではDuckDB・Polars・DataFusionのいずれかで計算し、結果をto_pandas()で受け取ります。