Skip to content

Pandas MultiIndex: 階層型インデックス徹底ガイド

Updated on

MultiIndex は panel データや時系列データ、reshape 済みデータに対して整った階層構造を与えてくれますが、「スライスが壊れやすい」「level の順序がややこしい」と感じて敬遠されがちです。

  • 問題: region + yearsymbol + field のようなネストした次元を、単なる列や横持ちテーブルに詰め込むと管理が煩雑になる。
  • 悪化要因: 行き当たりばったりの reshape により、重複した列名、ソート順の崩れ、複数キーでの選択時のエラーが頻発する。
  • 解決策: いくつかの定型パターンに絞ること。set_index で MultiIndex を構築し、.loc / .xs で安全にスライスし、swaplevel / reorder_levels で並び替え、stack / unstack で自在に reshape する。

Want an AI agent that understands your pandas notebooks and MultiIndex slicing?

RunCell is a JupyterLab AI agent that can read your code, analyze DataFrames, understand notebook context, debug errors, and even generate & execute code for you. It works directly inside JupyterLab—no switching windows or copy-pasting.

👉 Try RunCell: runcell.dev (opens in a new tab)


クイックリファレンス

タスクメソッドスニペット
列から level を構築set_indexdf.set_index(["region", "year"]).sort_index()
デカルト積から生成pd.MultiIndex.from_productpd.MultiIndex.from_product([regions, years], names=["region", "year"])
level ごとにスライス.loc または .xsdf.loc[("EMEA", 2024)] または df.xs("EMEA", level="region")
level の並び替えswaplevel, reorder_levelsdf.swaplevel("region", "year")
level の削除・フラット化droplevel, reset_indexdf.droplevel("year"), df.reset_index()
wide / long の変形unstack / stackdf.unstack("field"), df.stack("field")

サンプルデータ

import pandas as pd
 
records = [
    ("EMEA", 2023, "revenue", 120),
    ("EMEA", 2023, "profit", 25),
    ("EMEA", 2024, "revenue", 140),
    ("NA", 2024, "revenue", 210),
    ("NA", 2024, "profit", 50),
]
 
df = (
    pd.DataFrame(records, columns=["region", "year", "metric", "value"])
      .set_index(["region", "year", "metric"])
      .sort_index()
)

MultiIndex 構造の作成

既存の列から作成する

sales = raw_df.set_index(["region", "year"]).sort_index()
  • 安定してスライスできるように、sort_index() をあらかじめ呼んでおく。
  • 金額など「通常の値」として扱いたい列は、index ではなく列のまま残しておく。

product や tuple から作成する

idx = pd.MultiIndex.from_product(
    [["EMEA", "NA"], [2023, 2024]],
    names=["region", "year"],
)
frame = pd.DataFrame(index=idx, columns=["revenue"]).sort_index()

from_product は全ての組み合わせが存在することを保証します。すでに (region, year) のペアを持っている場合は from_tuples を使います。


MultiIndex での選択

# 階層をフル指定した 1 パス
emea_2024 = df.loc[("EMEA", 2024)]
 
# ある level での断面を取り、残りの level は保持
emea = df.xs("EMEA", level="region")
 
# スライス記法による部分選択(sorted index が前提)
idx = pd.IndexSlice
subset = df.loc[idx[:, 2024, :], :]
  • .xs(cross-section)は、残りの level をそのまま保ったまま 1 つの level で切り出したいときに便利です。
  • 時系列ベースの階層では、index をソートし、IndexSlice を使ってスライスを書くと可読性が上がります。

level の並び替えと整理

# year を region より前に持ってくる
reordered = df.swaplevel("region", "year").sort_index(level=["year", "region"])
 
# 3 つ以上の level を明示的に並び替え
df_reordered = df.reorder_levels(["metric", "region", "year"])
 
# もう不要になった level を落とす
flat = df.droplevel("metric")
  • swaplevel は隣接する 2 つの level を入れ替える処理に向いており高速です。任意順の並び替えが必要な場合は reorder_levels を使います。
  • 並び替え後は sort_index(level=...) を呼んで、スライスしやすい単調な順序を回復させます。

Stack / Unstack による変形

index の level を pivot 軸として、wide 形式と tidy な long 形式の間を行き来できます。

wide = df.unstack("metric")  # metric の値が列になる
long_again = wide.stack("metric")
  • unstack 時に存在しない組み合わせを埋めたい場合は、fill_value= で欠損値の埋め方を指定します。
  • 列ベースの pivot をしたいときも、set_index([...]).unstack()stack() の組み合わせで処理すると、手書きのループより堅牢です。

MultiIndex と通常の列、どちらを使うべきか

シナリオMultiIndex通常の列
階層的ラベルでのスライス(region → year → metric).loc / .xs と相性が良い⚠️ filter / join を何度も書く必要がある
レポート用の横持ちレイアウト✅ 必要に応じて unstack で列に展開⚠️ 列名の重複リスクがある
キー列を使った頻繁な merge⚠️ 先に reset してから merge した方がよい✅ join 用には列として持っておくのが自然
CSV / Parquet への書き出し✅ 書き出し前に reset_index() する✅ そのまま書き出せる

実務的な指針としては、「他システムとのやりとり用の素データ」はキーを列として持ち、「Notebook などで階層的なスライスや reshape を多用する局面」で MultiIndex を活用する、という使い分けがおすすめです。


よくある落とし穴と対処法

  • index がソートされておらずスライスが失敗する: 部分スライスの前に sort_index(level=[...]) を呼ぶ。
  • level に名前がなく分かりづらい: index.names を設定するか、set_indexnames= 引数を使って明示的に名前を付ける。
  • 出力が読みにくい: df.index.to_frame() で level を列として観察できる。シンプルな表が欲しいときは reset_index() でフラットな列に戻す。

MultiIndex の「作る (set_index)」「選ぶ (.loc / .xs)」「並べ替える (swaplevel / reorder_levels)」「変形する (stack / unstack)」というパターンを標準化してしまえば、階層構造を保ったままデータを扱えてもやもやが大きく減ります。pandas-pivot-melt のような reshape 系ガイドや、pandas-resample のような時系列ヘルパーと組み合わせることで、多次元データを端から端まで一貫した形で扱えるようになります。