0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Polars 2.0.0で追加されたMap型

0
Last updated at Posted at 2026-10-06

Polars 2.0.0でMap型が追加されましたので紹介します。

PolarsでJSONのような辞書型データを扱うには、pl.Structとpl.Mapの2つが候補になります。
この2つは似ていますが、明確な違いがあります。

比較

どちらの要素も、複数の「キー(名前)と値」で構成されます。
決定的な違いは決まった構造があるかどうかです。

比較項目 pl.Struct pl.Map
要素の識別子 フィールド名(固定) キー(行ごと・動的に変更可能)
キー/フィールド名の型 String(固定) 任意の型(1つのキー型を指定)
値の型 フィールドごとに異なる型が可能 1つの値型を指定
主な用途 スキーマが固定されたオブジェクト(レコード) 任意のキーバリュー(タグ、属性データなど)

pl.Struct

pl.Structは、構造体のようなデータを扱えます。

import polars as pl

df_struct = pl.DataFrame(
    {
        "user": [
            {"id": None, "name": "Alice", "age": 30},
            {"id": 2, "name": "Bob", "age": None},
        ]
    },
    schema={"user": pl.Struct({"id": pl.Int64, "name": pl.String, "age": pl.Int64})},
)
print(df_struct)
print(
    df_struct.select(
        id=pl.col("user").struct.field("id"),
        name=pl.col("user").struct.field("name"),
        age=pl.col("user").struct.field("age"),
    )
)

出力

shape: (2, 1)
┌───────────────────┐
│ user              │
│ ---               │
│ struct[3]         │
╞═══════════════════╡
│ {null,"Alice",30} │
│ {2,"Bob",null}    │
└───────────────────┘
shape: (2, 3)
┌──────┬───────┬──────┐
│ id   ┆ name  ┆ age  │
│ ---  ┆ ---   ┆ ---  │
│ i64  ┆ str   ┆ i64  │
╞══════╪═══════╪══════╡
│ null ┆ Alice ┆ 30   │
│ 2    ┆ Bob   ┆ null │
└──────┴───────┴──────┘

pl.Map

pl.Mapは、Pythonの辞書に似たデータ構造ですが、キーと値にそれぞれ型が指定されます。キーの種類や数を固定せず、行ごとに異なるキーを持たせたい場合に適しています。

ただし、値の型は同一である必要があります(ここではidやageを文字列として揃えています)。
また、DataFrame作成時はPythonの通常の辞書のほかに、内部表現である[{"key": ..., "value": ...}]形式でも記述可能です。

map.get()で指定したキーの値を取得できます。存在しないキーの場合はnullになります。

df_map = pl.DataFrame(
    {
        "user": [
            {"name": "Alice", "age": "30"},
            {"id": "2", "name": "Bob"},
        ],
    },
    schema={"user": pl.Map(pl.String, pl.String)},
)
print(df_map)
print(
    df_map.select(
        id=pl.col("user").map.get("id"),
        name=pl.col("user").map.get("name"),
        age=pl.col("user").map.get("age"),
    )
)

出力

shape: (2, 1)
┌────────────────────────────────┐
│ user                           │
│ ---                            │
│ map[str, str]                  │
╞════════════════════════════════╡
│ {"name": "Alice", "age": "30"} │
│ {"id": "2", "name": "Bob"}     │
└────────────────────────────────┘
shape: (2, 3)
┌──────┬───────┬──────┐
│ id   ┆ name  ┆ age  │
│ ---  ┆ ---   ┆ ---  │
│ str  ┆ str   ┆ str  │
╞══════╪═══════╪══════╡
│ null ┆ Alice ┆ 30   │
│ 2    ┆ Bob   ┆ null │
└──────┴───────┴──────┘

使い分けの基準

キー(フィールド)が固定されている場合はpl.Structのほうが適しています。フィールドがあらかじめ決まっているため、Polarsの列指向の処理を活かしやすくなります。

キーが行ごとに変化する場合はpl.Mapを使いましょう。ただしpl.Mapでは以下の制約があります。

  • キーと値はそれぞれ一定の型である
  • 1行の中でキーは一意である
  • キーにnullを指定できない

mapネームスペース

pl.Mapの列のExprはmapネームスペースを持ちます。
mapネームスペースには以下のメソッドがあります。

  • keys: キーのリスト
  • values: 値のリスト
  • len: 要素数
  • get: 特定のキーの値
  • contains_key: 特定のキーがあるか
  • entries: keyとvalueを持つ構造体のリスト
df_map2 = pl.DataFrame(
    {
        "tag": [{5: "e", 10: "j"}, {20: "t"}, {10: "c"}],
    },
    schema={"tag": pl.Map(pl.Int64, pl.String)},
)
print(
    df_map2.select(
        keys=pl.col("tag").map.keys(),
        values=pl.col("tag").map.values(),
        len=pl.col("tag").map.len(),
        get_10=pl.col("tag").map.get(10),
        contains_key_10=pl.col("tag").map.contains_key(10),
        entries=pl.col("tag").map.entries(),
    )
)

出力

shape: (3, 6)
┌───────────┬────────────┬─────┬────────┬─────────────────┬─────────────────────┐
│ keys      ┆ values     ┆ len ┆ get_10 ┆ contains_key_10 ┆ entries             │
│ ---       ┆ ---        ┆ --- ┆ ---    ┆ ---             ┆ ---                 │
│ list[i64] ┆ list[str]  ┆ u32 ┆ str    ┆ bool            ┆ list[struct[2]]     │
╞═══════════╪════════════╪═════╪════════╪═════════════════╪═════════════════════╡
│ [5, 10]   ┆ ["e", "j"] ┆ 2   ┆ j      ┆ true            ┆ [{5,"e"}, {10,"j"}] │
│ [20]      ┆ ["t"]      ┆ 1   ┆ null   ┆ false           ┆ [{20,"t"}]          │
│ [10]      ┆ ["c"]      ┆ 1   ┆ c      ┆ true            ┆ [{10,"c"}]          │
└───────────┴────────────┴─────┴────────┴─────────────────┴─────────────────────┘

map.get(key)やmap.contains_key(key)は、keyにExprを指定できます。
つまり、「別の列の値をキーとして動的に検索する」ことが可能です。

some_df.select(
    val=pl.col("tag").map.get(pl.col("target_key"))
)

map.entries()の逆変換としてlist.to_map()があります。

まとめ

Polars 2.0.0で追加されたpl.Map型について、pl.Struct型との違いや使い分けを解説しました。

ポイントは以下の2点です。

  • キーが固定されている場合: pl.Structを使う
  • キーが動的に変わる場合: 柔軟なpl.Mapを使う

従来、可変キーのJSONデータやParquet/Delta Lake/Icebergに保存されたMap型データを扱う際、PolarsではList[Struct]として扱うか文字列化する必要がありました。
Polars 2.0.0でネイティブなpl.Map型が導入されたことで、Arrow/Parquetのエコシステムとの相互運用性が大幅に向上し、直感的なクエリ操作が可能になりました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?