pandasには階層型インデックスという概念がある。
あるデータセットに対して、複数のインデックスを階層として持たせることができるのだ。
階層型インデックスは、ピボットテーブルの作成やデータの変形など、グループによるデータ操作をする場合に重要な機能となる。
コンテンツ
階層型インデックスを用いたデータセット
簡単な例を見てみよう。
import pandas as pd
import numpy as np
data = pd.Series(np.random.randn(9),
index=[
['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c'],
[1, 2, 3, 1, 2, 3,1, 2, 3]
])
# a 1 -0.596496
# 2 0.526021
# 3 -2.395249
# b 1 0.382245
# 2 -1.460518
# 3 1.013924
# c 1 -0.154135
# 2 -0.994512
# 3 -0.694720
# dtype: float64
出力結果を見ると、1列目に空値が複数見られるが、これは直前の行のラベルをインデックスとして使うことを意味する。
別途indexプロパティを使えば詳しいインデックス情報を確認することができる。
MultiIndex(levels=[['a', 'b', 'c'], [1, 2, 3]],
labels=[[0, 0, 0, 1, 1, 1, 2, 2, 2], [0, 1, 2, 0, 1, 2, 0, 1, 2]])
部分インデックス参照
階層型インデックスのメリットとして、部分集合を簡単に抽出できることが挙げられる。
様々な抽出例を紹介する。
import pandas as pd
import numpy as np
data = pd.Series(np.random.randn(9),
index=[
['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c'],
[1, 2, 3, 1, 2, 3,1, 2, 3]
])
data['b']
# 1 -0.642686
# 2 -0.665147
# 3 -0.212816
# dtype: float64
data['a':'b']
# a 1 -1.001568
# 2 -1.201770
# 3 -0.500852
# b 1 -0.642686
# 2 -0.665147
# 3 -0.212816
# dtype: float64
data.iloc[2:3]
# a 3 -0.500852
# dtype: float64
data.loc[['a', 'c']]
# a 1 -1.001568
# 2 -1.201770
# 3 -0.500852
# c 1 0.855579
# 2 0.103584
# 3 -0.300320
# dtype: float64
内側のインデックスを指定して抽出することも可能だ。
data.loc[:, 2]
# a 1.209921
# b 0.229654
# c 1.858592
# dtype: float64
階層型データをデータフレームに変換する
unstack関数を使うことで、先程の例で使用したデータをデータフレームに変換することができる。
df = data.unstack()
# 1 2 3
# a 0.713211 -1.829338 0.001228
# b -1.479334 1.631776 1.436027
# c -0.310134 -0.661608 1.958301
また、逆にデータフレームを階層型インデックスを持つオブジェクトに戻す場合はstack関数を使う。
df.stack()
# a 1 1.443906
# 2 0.090950
# 3 1.545684
# b 1 1.202481
# 2 -1.680269
# 3 0.379805
# c 1 1.250931
# 2 1.960360
# 3 0.390611
# dtype: float64
データフレームのインデックスに階層を持たせる
ここまでは、シリーズをベースに例を紹介してきたが、データフレームのインデックスにも階層を持たせることができる。
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(4, 3),
index=[
['a', 'a', 'b', 'b'],
[1, 2, 1, 2]
],
columns=[
['Tokyo', 'Osaka', 'Osaka'],
['Shinagawa', 'Umeda', 'Namba']
])
# Tokyo Osaka
# Shinagawa Umeda Namba
# a 1 0 1 2
# 2 3 4 5
# b 1 6 7 8
# 2 9 10 11
参照方法についてはシリーズ同様、様々な方法がある。
df['Tokyo']
# Shinagawa
# a 1 0
# 2 3
# b 1 6
# 2 9
df['Osaka', 'Umeda']
# a 1 1
# 2 4
# b 1 7
# 2 10
df.loc['a',1]['Tokyo']
# Shinagawa
# a 1 0
# 2 3
df.loc['a']['Tokyo']
# Shinagawa
# 1 0
# 2 3