404 Not Found

404 Not Found


nginx

【MultiIndex】階層インデックスの作成・選択・変換を徹底解説

データに階層構造がある場合——都市別→カテゴリ別、年別→四半期別のようにグループ化されている場合——単一レベルのインデックスでは不十分です。MultiIndex(階層インデックス)は、階層化されたデータに階層的なインデックスを与えます。第1レベルを選択し、次に第2レベルへドリルダウンして、フォルダ階層のようにナビゲートできます。本セクションでは、MultiIndexの作成、選択、並べ替え、stack/unstackとの組み合わせについて解説します。

⚠️ 注意: 以下のコードを実行するには、ローカルのPython環境が必要です。

1. 学習内容



2. ボブの複数都市・複数カテゴリ売上データ

(1) 課題:2レベルのグループ化結果から選択するのが難しい

都市+カテゴリでグループ化した後、ボブは2レベルのインデックスを得ましたが、特定の都市を選択する方法がわかりません:

PYTHON
import pandas as pd

df = pd.DataFrame({
    'city': ['NYC', 'NYC', 'LA', 'LA', 'Chicago', 'Chicago'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing', 'Electronics', 'Clothing'],
    'sales': [5000, 800, 3000, 600, 2000, 400]
})
result = df.groupby(['city', 'category'])['sales'].sum()
print(result)
# city     category
# Chicago  Clothing       400
#          Electronics   2000
# LA       Clothing       600
#          Electronics   3000
# NYC      Clothing       800
#          Electronics   5000
# NYCだけを選択するには?
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

(2) 解決策:MultiIndexの選択

▶ サンプル

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

:MultiIndexの選択(難易度 ⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'city': ['NYC', 'NYC', 'LA', 'LA', 'Chicago', 'Chicago'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing', 'Electronics', 'Clothing'],
    'sales': [5000, 800, 3000, 600, 2000, 400]
})
result = df.groupby(['city', 'category'])['sales'].sum()

# MultiIndexのラベルで選択
print(result.loc['NYC'])
# category
# Clothing       800
# Electronics   5000

# 特定の(都市、カテゴリ)を選択
print(result.loc[('NYC', 'Electronics')])  # 5000

# xs:クロスセクション選択
print(result.xs('Electronics', level='category'))
# city
# Chicago    2000
# LA         3000
# NYC        5000
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


3. MultiIndexの作成

(1) 3つの作成方法

▶ サンプル

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

:MultiIndexの作成方法(難易度 ⭐⭐)

PYTHON
import pandas as pd

# 1. from_tuples — 明示的なペアの指定
index = pd.MultiIndex.from_tuples([
    ('NYC', 'Electronics'), ('NYC', 'Clothing'),
    ('LA', 'Electronics'), ('LA', 'Clothing')
], names=['city', 'category'])
df1 = pd.DataFrame({'sales': [5000, 800, 3000, 600]}, index=index)
print("from_tuples:")
print(df1)

# 2. from_product — 直積(最も一般的)
index2 = pd.MultiIndex.from_product(
    [['NYC', 'LA', 'Chicago'], ['Electronics', 'Clothing']],
    names=['city', 'category']
)
df2 = pd.DataFrame({
    'sales': [5000, 800, 3000, 600, 2000, 400]
}, index=index2)
print("\nfrom_product:")
print(df2)

# 3. from_frame — DataFrameから作成
df_index = pd.DataFrame({
    'city': ['NYC', 'NYC', 'LA', 'LA'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing']
})
index3 = pd.MultiIndex.from_frame(df_index)
df3 = pd.DataFrame({'sales': [5000, 800, 3000, 600]}, index=index3)
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


4. 階層選択

(1) locとxsの比較

▶ サンプル

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

:階層選択の方法(難易度 ⭐⭐)

PYTHON
import pandas as pd

index = pd.MultiIndex.from_product(
    [['NYC', 'LA'], ['Electronics', 'Clothing', 'Home']],
    names=['city', 'category']
)
df = pd.DataFrame({
    'sales': [5000, 800, 300, 3000, 600, 200],
    'profit': [1500, 200, 50, 800, 100, 30]
}, index=index)

# loc:第1レベルを選択
print(df.loc['NYC'])

# loc:両方のレベルを選択
print(df.loc[('NYC', 'Electronics')])

# xs:クロスセクション(任意のレベルで選択)
print(df.xs('Electronics', level='category'))
# 全都市のElectronicsデータを返す

# xsでdrop_level=Falseを指定
print(df.xs('NYC', level='city', drop_level=False))

# sliceを使った部分選択
print(df.loc[('NYC', slice(None)), :])  # NYCの全カテゴリ
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

(2) locとxsの比較表

機能 loc xs
1レベルの選択 loc['NYC'] xs('NYC', level=0)
第2レベルの選択 複雑 loc[(slice(None),'Elec')] 簡単 xs('Elec', level=1)
複数レベルの同時選択 loc[('NYC','Elec')] ❌ 1レベルずつのみ
レベルの保持 デフォルトで保持 drop_levelで制御


5. swaplevel / sort_index

(1) レベルの入れ替え

▶ サンプル

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

:swaplevelによるレベルの並べ替え(難易度 ⭐⭐)

PYTHON
import pandas as pd

index = pd.MultiIndex.from_product(
    [['NYC', 'LA'], ['Q1', 'Q2', 'Q3', 'Q4']],
    names=['city', 'quarter']
)
df = pd.DataFrame({
    'sales': [1200, 1300, 1100, 1400, 800, 900, 700, 1000]
}, index=index)

# レベルを入れ替え
df_swapped = df.swaplevel()
print(df_swapped.head(4))
# city    quarter
# Q1      NYC        1200
# Q2      NYC        1300
# Q3      NYC        1100
# Q4      NYC        1400

# 入れ替え後にsort_index(重要!)
df_sorted = df_swapped.sort_index()
print(df_sorted.head(4))

# reorder_levels:任意の順序に変更
df_reordered = df.reorder_levels(['quarter', 'city'])
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。
⚠️ 注意: swaplevelまたはreorder_levelsを実行した後は、必ずsort_index()を呼び出してください。そうしないと、後続の選択操作でエラーが発生したり、パフォーマンスが低下したりする可能性があります。



6. MultiIndexとstack/unstack

▶ サンプル

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

:MultiIndexとstack/unstack(難易度 ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'city': ['NYC', 'NYC', 'LA', 'LA'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing'],
    'Q1': [1200, 400, 800, 200],
    'Q2': [1300, 500, 900, 300]
})

# set_index → MultiIndexのDataFrame
multi_df = df.set_index(['city', 'category'])
print(multi_df)

# unstack:categoryレベル → 列
wide = multi_df.unstack(level='category')
print(wide)
#          Q1                 Q2
# category Clothing Electronics  Clothing Electronics
# city
# LA            200         800       300         900
# NYC           400        1200       500        1300

# stack:列 → インデックスレベル(逆操作)
back = wide.stack(level='category')
print(back)
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


7. reset_indexによるフラット化

▶ サンプル

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

:MultiIndexのフラット化(難易度 ⭐)

PYTHON
import pandas as pd

index = pd.MultiIndex.from_product(
    [['NYC', 'LA'], ['Q1', 'Q2']],
    names=['city', 'quarter']
)
df = pd.DataFrame({'sales': [1200, 1300, 800, 900]}, index=index)

# reset_index:MultiIndex → 通常の列
flat = df.reset_index()
print(flat)
#    city quarter  sales
# 0   NYC      Q1   1200
# 1   NYC      Q2   1300
# 2    LA      Q1    800
# 3    LA      Q2    900

# 列のMultiIndexをフラット化
wide = df.unstack()
flat_cols = wide.copy()
flat_cols.columns = [f'{a}_{b}' for a, b in flat_cols.columns]
print(flat_cols)
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


8. 総合例:複数都市・複数カテゴリの売上分析

(6) ▶ MultiIndexの階層構造

100%
graph TB
    A[DataFrame] --> B[外部インデックス:city]
    B --> C[NYC]
    B --> D[LA]
    B --> E[Chicago]
    C --> F[内部インデックス:category]
    F --> G[Electronics]
    F --> H[Clothing]
    F --> I[Home]
    D --> J[Electronics]
    D --> K[Clothing]
    E --> L[Electronics]
    E --> M[Clothing]
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

▶ サンプル

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

:MultiIndexの完全なワークフロー分析(難易度 ⭐⭐⭐)

PYTHON
import pandas as pd
import numpy as np

# ============================================
# 総合例:複数都市・複数カテゴリの
# MultiIndexを使った売上分析
# ============================================

# 1. 階層データの作成
np.random.seed(42)
index = pd.MultiIndex.from_product(
    [['NYC', 'LA', 'Chicago', 'Houston'],
     ['Electronics', 'Clothing', 'Home'],
     ['Q1', 'Q2', 'Q3', 'Q4']],
    names=['city', 'category', 'quarter']
)
df = pd.DataFrame({
    'sales': np.random.randint(100, 5000, 48),
    'profit': np.random.randint(10, 1500, 48)
}, index=index)

# 2. 構造の確認
print(f"レベル: {df.index.names}")
print(f"形状: {df.shape}")

# 3. 都市で選択
print("\n=== NYCの売上 ===")
print(df.loc['NYC', 'sales'].unstack(level='quarter'))

# 4. xs:全都市のElectronics
print("\n=== 都市別Electronics ===")
elec = df.xs('Electronics', level='category')[['sales']]
print(elec.unstack(level='quarter'))

# 5. swaplevel → sort → 選択
df2 = df.swaplevel('city', 'quarter').sort_index()
print("\n=== 全都市のQ1 ===")
print(df2.loc['Q1'])

# 6. unstackでワイド形式のレポート
report = df['sales'].unstack(level=['category', 'quarter'])
print("\n=== ワイドレポート(最初の2都市) ===")
print(report.head(2))

# 7. reset_indexでエクスポート用に変換
flat = df.reset_index()
print(f"\nフラット化後の形状: {flat.shape}")
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

❓ よくある質問

Q MultiIndexはいつ使うべきですか?
A データに自然な階層構造がある場合です——都市+カテゴリ、年+四半期、部門+チームなど。複数の列でグループ化すると自動的にMultiIndexが生成され、set_indexに複数の列を指定しても作成できます。シンプルなデータには単一レベルのインデックスの方が便利ですので、不要なMultiIndexを無理に使う必要はありません。
Q xsとlocの違いは何ですか?
A xsは任意のレベルで選択できます(例:都市を先に選ばずにcategory='Electronics'を直接選択)。locは外側のレベルから内側へ順番に選択することしかできません(先に都市、次にカテゴリ)。xsの方が柔軟ですが、複数レベルの同時選択はできません。locはloc[('NYC','Electronics')]をサポートしますが、第2レベルの選択構文はより複雑です。
Q swaplevelはデータを変更しますか?
A いいえ——swaplevelはインデックスのレベルの順序を入れ替えるだけで、データ自体は変更されません。ただし、入れ替え後に必ずsort_index()を呼び出す必要があります。そうしないと、後続の選択でエラーが発生したり、パフォーマンスが低下したりする可能性があります。推奨ワークフロー:swaplevel → sort_index → 選択。
Q MultiIndexをフラット化するにはどうすればよいですか?
A 行レベルのMultiIndex → df.reset_index()でレベルを通常の列に変換します。列レベルのMultiIndex → レベルの値を結合して列名を変更します:['_'.join(col) for col in df.columns]。groupby後はas_index=Falseを使ってMultiIndexの作成を回避できます(ただし階層選択の機能は失われます)。
Q MultiIndexのパフォーマンスはどうですか?
A MultiIndexの検索はO(1)(内部的にハッシュベース)なので、パフォーマンスは非常に優れています。ただし、sort_index()を実行した後でのみ効率が保証されます——ソートされていないMultiIndexの選択はO(n)に低下する可能性があります。大規模データセットの場合:作成直後にsort_index()を呼び出し、is_uniqueで一意性を確認してください。
Q get_level_valuesは何に使うのですか?
A df.index.get_level_values('city')は指定したレベルの全値を返します(例:['NYC','NYC','LA','LA',...])。条件付き選択に便利です:df[df.index.get_level_values('city') == 'NYC']。groupbyとも併用できます:df.groupby(df.index.get_level_values(0)).sum()
Q from_productとfrom_tuplesはどのように使い分けますか?
A from_productは直積(すべての組み合わせ)を生成します——完全なグリッドデータに最適です(3都市 × 4四半期 = 12行)。from_tuplesは正確な組み合わせを指定します——不完全なデータに最適です(一部の都市に特定のカテゴリがない場合)。from_productはより簡潔で、from_tuplesはより精密です。

📖 まとめ


📝 練習問題

  1. 基礎(難易度 ⭐):from_productを使って3都市 × 2カテゴリのMultiIndexデータフレームを作成し、locとxsでそれぞれ特定の都市と特定のカテゴリを選択してください。
  2. 応用(難易度 ⭐⭐):都市 × 四半期のMultiIndexデータフレームを作成し、swaplevelでレベルを入れ替え → sort_index → unstackでワイドテーブルに変換 → stackで元に戻し、ラウンドトリップを検証してください。
  3. 挑戦(難易度 ⭐⭐⭐):4地域 × 3カテゴリ × 4四半期の48行のデータをシミュレートし、以下を完成させてください:xsクロスレベル選択 → swaplevel並べ替え → 複数レベルのunstackでワイド形式に変換 → reset_indexでエクスポート用に変換 → groupbyで再集計。

← 前へ:高度な時系列 · 次へ:ウィンドウ関数 →

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%