PandasのMultiIndex:階層的なデータの扱い

プログラミング

Pandas MultiIndex:階層的なデータの扱い

PandasのMultiIndex(マルチインデックス)は、DataFrameやSeriesのインデックスとして複数のレベルを持つことができる強力な機能です。これにより、表形式データにおける階層構造を効率的に表現し、操作することが可能になります。例えば、時系列データで「年」「月」「日」といった複数の時間軸を持つ場合や、地理情報で「国」「地域」「都市」といった階層を持つ場合などに非常に役立ちます。

MultiIndexの作成

MultiIndexを作成するには、主に以下の方法があります。

tuplesを利用した作成

最も基本的な方法は、タプルのリストをインデックスとして指定することです。各タプルがMultiIndexの1つのレベルを表します。

import pandas as pd

index_tuples = [(‘A’, ‘X’), (‘A’, ‘Y’), (‘B’, ‘X’), (‘B’, ‘Y’)]
multi_index = pd.MultiIndex.from_tuples(index_tuples, names=[‘Level1’, ‘Level2’])
print(multi_index)

from_arraysを利用した作成

複数の配列(リスト)からMultiIndexを作成することもできます。各配列がインデックスの1つのレベルに対応します。

import pandas as pd

array1 = [‘A’, ‘A’, ‘B’, ‘B’]
array2 = [‘X’, ‘Y’, ‘X’, ‘Y’]
multi_index = pd.MultiIndex.from_arrays([array1, array2], names=[‘Level1’, ‘Level2’])
print(multi_index)

from_productを利用した作成

複数のリストの直積(すべての組み合わせ)からMultiIndexを作成する場合に便利です。

import pandas as pd

list1 = [‘A’, ‘B’]
list2 = [‘X’, ‘Y’]
multi_index = pd.MultiIndex.from_product([list1, list2], names=[‘Level1’, ‘Level2’])
print(multi_index)

MultiIndexを持つDataFrame/Seriesの作成

作成したMultiIndexをDataFrameやSeriesのインデックスとして使用することで、階層的なデータ構造を作成できます。

import pandas as pd

index_tuples = [(‘A’, ‘X’), (‘A’, ‘Y’), (‘B’, ‘X’), (‘B’, ‘Y’)]
multi_index = pd.MultiIndex.from_tuples(index_tuples, names=[‘Level1’, ‘Level2’])
data = {‘col1’: [1, 2, 3, 4], ‘col2’: [5, 6, 7, 8]}
df = pd.DataFrame(data, index=multi_index)
print(df)

MultiIndexのデータへのアクセス

MultiIndexを持つDataFrameやSeriesでは、階層構造を利用してデータを効率的に選択・操作できます。

locによるアクセス

locアクセサを使用すると、インデックスのレベルを指定してデータを取得できます。単一レベル、複数レベル、スライスなど、様々な方法でアクセス可能です。

単一レベルでのアクセス

最上位レベルのインデックスを指定してデータを選択します。

print(df.loc[‘A’])

複数レベルでのアクセス

タプルで複数のレベルのインデックスを指定して、より詳細にデータを絞り込みます。

print(df.loc[(‘A’, ‘X’)])

スライスによるアクセス

特定のレベルでスライスを利用して、範囲内のデータを取得できます。

print(df.loc[(‘A’, slice(None)), :]) # Level1が’A’で、Level2は全て
print(df.loc[(‘A’, ‘X’):(‘B’, ‘Y’), :]) # 範囲指定

xsによるアクセス

xs(cross-section)メソッドは、特定のレベルのインデックスを固定して、反対側の軸からデータを抽出するのに特化しています。特に、DataFrameの列にもMultiIndexがある場合に便利です。

# 行にMultiIndex、列にもMultiIndexを持つDataFrameを例に
columns = pd.MultiIndex.from_product([[‘ColA’, ‘ColB’], [‘Val1’, ‘Val2’]], names=[‘ColLevel1’, ‘ColLevel2’])
df_multi_col = pd.DataFrame([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]], index=multi_index, columns=columns)
print(df_multi_col)

print(df_multi_col.xs(‘X’, level=’Level2′, axis=0)) # 行のLevel2が’X’のデータを抽出
print(df_multi_col.xs(‘ColA’, level=’ColLevel1′, axis=1)) # 列のColLevel1が’ColA’のデータを抽出

MultiIndexの操作

MultiIndexは、データの集計や再整形など、様々な操作において柔軟性を提供します。

sort_index()

インデックスをソートすることで、データの検索やスライスを効率化できます。特に、locやilocで範囲指定を行う場合に重要です。

df_sorted = df.sort_index()
print(df_sorted)

unstack()とstack()

unstack()メソッドは、DataFrameのインデックスレベルの1つを列に移動させ、DataFrameの形状を変更します。stack()は逆に、列レベルをインデックスレベルに移動させます。これらは、階層構造を平坦化したり、逆に階層化したりする際に非常に強力です。

# dfからunstack
df_unstacked = df.unstack(level=’Level2′)
print(df_unstacked)

# df_unstackedからstack
df_stacked = df_unstacked.stack(level=’Level2′)
print(df_stacked)

reset_index()とset_index()

reset_index()は、DataFrameのインデックスを通常の列に変換します。MultiIndexの場合は、各レベルが別々の列になります。set_index()は、DataFrameの列をインデックスに設定しますが、MultiIndexを作成することも可能です。

# DataFrameをリセット
df_reset = df.reset_index()
print(df_reset)

# 列からMultiIndexを設定
df_new = pd.DataFrame({‘Level1’: [‘A’, ‘A’, ‘B’, ‘B’], ‘Level2’: [‘X’, ‘Y’, ‘X’, ‘Y’], ‘Value’: [10, 20, 30, 40]})
df_indexed = df_new.set_index([‘Level1’, ‘Level2’])
print(df_indexed)

MultiIndexの利点

MultiIndexを使用することの主な利点は以下の通りです。

  • 階層構造の自然な表現: 複雑な関係性を持つデータを直感的に表現できます。
  • 効率的なデータアクセス: 階層構造を利用したインデックス指定により、目的のデータを素早く特定できます。
  • 柔軟なデータ操作: unstack, stack, reset_index, set_indexなどのメソッドと組み合わせることで、データの形状を柔軟に変更し、分析に適した形に変換できます。
  • 可読性の向上: 適切な名前をインデックスレベルに付けることで、データの意味が明確になり、コードの可読性が向上します。

まとめ

PandasのMultiIndexは、階層的なデータ構造を扱うための必須の機能です。その作成方法、データへのアクセス方法、そして様々な操作メソッドを理解することで、より複雑で大規模なデータセットを効率的かつ効果的に分析することが可能になります。特に、時系列データ、地理空間データ、実験データなど、複数の分類軸を持つデータセットにおいては、MultiIndexの活用が不可欠と言えるでしょう。