pandasのMultiindexの指定・追加・解除・ソート・レベル変更
pandasでMultiindex(マルチインデックス、階層型インデックス)を設定すると、print()
表示が見やすくなったり、各階層の項目ごとの統計量を簡単に算出できたりして便利。
ここでは、マルチインデックスの設定に関して以下の内容を説明する。
- ファイルの読み込み時に設定:
read_csv()
- データ列をマルチインデックスに指定・追加:
set_index()
- マルチインデックスを解除:
reset_index()
- マルチインデックスをソート:
sort_index()
- マルチインデックスのレベルを変更:
swaplevel()
例として以下のデータを使用する。
import pandas as pd
df = pd.read_csv('data/src/sample_multi.csv')
print(df)
# level_1 level_2 level_3 val_1 val_2
# 0 A0 B0 C0 98 90
# 1 A0 B0 C1 44 9
# 2 A0 B1 C2 39 17
# 3 A0 B1 C3 75 71
# 4 A1 B2 C0 1 89
# 5 A1 B2 C1 54 60
# 6 A1 B3 C2 47 6
# 7 A1 B3 C3 16 5
# 8 A2 B0 C0 75 22
# 9 A2 B0 C1 19 4
# 10 A2 B1 C2 25 52
# 11 A2 B1 C3 57 40
# 12 A3 B2 C0 64 54
# 13 A3 B2 C1 27 96
# 14 A3 B3 C2 100 77
# 15 A3 B3 C3 22 50
csvファイルはコチラ。
ファイルの読み込み時に設定: read_csv()
ファイルからデータを読み込むのであれば、読み込み時にマルチインデックスを設定できる。
read_csv()
メソッドでは、引数index_col
に列名か列番号をリストで指定するとマルチインデックスになる。
df_m_csv = pd.read_csv('data/src/sample_multi.csv', index_col=['level_1', 'level_2', 'level_3'])
print(df_m_csv)
# val_1 val_2
# level_1 level_2 level_3
# A0 B0 C0 98 90
# C1 44 9
# B1 C2 39 17
# C3 75 71
# A1 B2 C0 1 89
# C1 54 60
# B3 C2 47 6
# C3 16 5
# A2 B0 C0 75 22
# C1 19 4
# B1 C2 25 52
# C3 57 40
# A3 B2 C0 64 54
# C1 27 96
# B3 C2 100 77
# C3 22 50
read_csv()
メソッドについての詳細は以下の記事を参照。
データ列をマルチインデックスを指定・追加: set_index()
既存のpandas.DataFrame
オブジェクトの複数のデータ列をマルチインデックスとして指定するにはset_index()
メソッドを使う。
第一引数keys
に列名のリストを指定する。
df_m = df.set_index(['level_1', 'level_2', 'level_3'])
print(df_m)
# val_1 val_2
# level_1 level_2 level_3
# A0 B0 C0 98 90
# C1 44 9
# B1 C2 39 17
# C3 75 71
# A1 B2 C0 1 89
# C1 54 60
# B3 C2 47 6
# C3 16 5
# A2 B0 C0 75 22
# C1 19 4
# B1 C2 25 52
# C3 57 40
# A3 B2 C0 64 54
# C1 27 96
# B3 C2 100 77
# C3 22 50
既にインデックスが指定されているpandas.DataFrame
オブジェクトにデータ列をマルチインデックスとして追加する場合もset_index()
。
引数append
をTrue
とすると追加される。デフォルトはappend=False
で新しいインデックスで上書きされてしまうので注意。
df_m_1 = df.set_index('level_1')
print(df_m_1)
# level_2 level_3 val_1 val_2
# level_1
# A0 B0 C0 98 90
# A0 B0 C1 44 9
# A0 B1 C2 39 17
# A0 B1 C3 75 71
# A1 B2 C0 1 89
# A1 B2 C1 54 60
# A1 B3 C2 47 6
# A1 B3 C3 16 5
# A2 B0 C0 75 22
# A2 B0 C1 19 4
# A2 B1 C2 25 52
# A2 B1 C3 57 40
# A3 B2 C0 64 54
# A3 B2 C1 27 96
# A3 B3 C2 100 77
# A3 B3 C3 22 50
df_m_2 = df_m_1.set_index('level_2', append=True)
print(df_m_2)
# level_3 val_1 val_2
# level_1 level_2
# A0 B0 C0 98 90
# B0 C1 44 9
# B1 C2 39 17
# B1 C3 75 71
# A1 B2 C0 1 89
# B2 C1 54 60
# B3 C2 47 6
# B3 C3 16 5
# A2 B0 C0 75 22
# B0 C1 19 4
# B1 C2 25 52
# B1 C3 57 40
# A3 B2 C0 64 54
# B2 C1 27 96
# B3 C2 100 77
# B3 C3 22 50
例では新たなオブジェクトが返されているが、set_index()
の引数inplace
をTrue
とすると、set_index()
を呼び出したオブジェクト自体が変更される。
set_index()
については以下の記事も参照。
マルチインデックスを解除: reset_index()
マルチインデックスを解除するにはreset_index()
メソッドを使う。
引数をなにも指定しないとすべてのインデックス列が解除され、データ列に追加される。
df_r_all = df_m.reset_index()
print(df_r_all)
# level_1 level_2 level_3 val_1 val_2
# 0 A0 B0 C0 98 90
# 1 A0 B0 C1 44 9
# 2 A0 B1 C2 39 17
# 3 A0 B1 C3 75 71
# 4 A1 B2 C0 1 89
# 5 A1 B2 C1 54 60
# 6 A1 B3 C2 47 6
# 7 A1 B3 C3 16 5
# 8 A2 B0 C0 75 22
# 9 A2 B0 C1 19 4
# 10 A2 B1 C2 25 52
# 11 A2 B1 C3 57 40
# 12 A3 B2 C0 64 54
# 13 A3 B2 C1 27 96
# 14 A3 B3 C2 100 77
# 15 A3 B3 C3 22 50
特定のインデックス列のみをマルチインデックスから解除したい場合は、引数level
に列名を文字列で指定するかレベル(階層)を整数値で指定する。レベル(階層)は外側(大項目)が0
。
列名またはレベル値のリストで指定すると複数のインデックス列が解除される。
df_r_1 = df_m.reset_index(level='level_1')
print(df_r_1)
# level_1 val_1 val_2
# level_2 level_3
# B0 C0 A0 98 90
# C1 A0 44 9
# B1 C2 A0 39 17
# C3 A0 75 71
# B2 C0 A1 1 89
# C1 A1 54 60
# B3 C2 A1 47 6
# C3 A1 16 5
# B0 C0 A2 75 22
# C1 A2 19 4
# B1 C2 A2 25 52
# C3 A2 57 40
# B2 C0 A3 64 54
# C1 A3 27 96
# B3 C2 A3 100 77
# C3 A3 22 50
df_r_1 = df_m.reset_index(level=0)
print(df_r_1)
# level_1 val_1 val_2
# level_2 level_3
# B0 C0 A0 98 90
# C1 A0 44 9
# B1 C2 A0 39 17
# C3 A0 75 71
# B2 C0 A1 1 89
# C1 A1 54 60
# B3 C2 A1 47 6
# C3 A1 16 5
# B0 C0 A2 75 22
# C1 A2 19 4
# B1 C2 A2 25 52
# C3 A2 57 40
# B2 C0 A3 64 54
# C1 A3 27 96
# B3 C2 A3 100 77
# C3 A3 22 50
df_r_2 = df_m.reset_index(level=['level_1', 'level_2'])
print(df_r_2)
# level_1 level_2 val_1 val_2
# level_3
# C0 A0 B0 98 90
# C1 A0 B0 44 9
# C2 A0 B1 39 17
# C3 A0 B1 75 71
# C0 A1 B2 1 89
# C1 A1 B2 54 60
# C2 A1 B3 47 6
# C3 A1 B3 16 5
# C0 A2 B0 75 22
# C1 A2 B0 19 4
# C2 A2 B1 25 52
# C3 A2 B1 57 40
# C0 A3 B2 64 54
# C1 A3 B2 27 96
# C2 A3 B3 100 77
# C3 A3 B3 22 50
マルチインデックスから解除してデータ列からも削除したい場合は引数drop
をTrue
とする。
df_r_drop = df_m.reset_index(level='level_1', drop=True)
print(df_r_drop)
# val_1 val_2
# level_2 level_3
# B0 C0 98 90
# C1 44 9
# B1 C2 39 17
# C3 75 71
# B2 C0 1 89
# C1 54 60
# B3 C2 47 6
# C3 16 5
# B0 C0 75 22
# C1 19 4
# B1 C2 25 52
# C3 57 40
# B2 C0 64 54
# C1 27 96
# B3 C2 100 77
# C3 22 50
例では新たなオブジェクトが返されているが、reset_index()
でも引数inplace
をTrue
とすると、reset_index()
を呼び出したオブジェクト自体が変更される。
reset_index()
については以下の記事も参照。
マルチインデックスをソート: sort_index()
マルチインデックスのインデックス列をソートするにはsort_index()
を使う。
上の例のようにインデックス列を解除した場合はソートし直したほうが見やすい。
引数をなにも指定しないとレベル順にソートされる。
df_r_drop_sort = df_r_drop.sort_index()
print(df_r_drop_sort)
# val_1 val_2
# level_2 level_3
# B0 C0 98 90
# C0 75 22
# C1 44 9
# C1 19 4
# B1 C2 39 17
# C2 25 52
# C3 75 71
# C3 57 40
# B2 C0 1 89
# C0 64 54
# C1 54 60
# C1 27 96
# B3 C2 47 6
# C2 100 77
# C3 16 5
# C3 22 50
特定のインデックス列を基準にソートしたい場合は、引数level
に列名かレベル値またはそれらのリストを指定する。
df_r_drop_sort_2 = df_r_drop.sort_index(level='level_3')
print(df_r_drop_sort_2)
# val_1 val_2
# level_2 level_3
# B0 C0 98 90
# C0 75 22
# B2 C0 1 89
# C0 64 54
# B0 C1 44 9
# C1 19 4
# B2 C1 54 60
# C1 27 96
# B1 C2 39 17
# C2 25 52
# B3 C2 47 6
# C2 100 77
# B1 C3 75 71
# C3 57 40
# B3 C3 16 5
# C3 22 50
sort_index()
については以下の記事も参照。
マルチインデックスのレベルを変更: swaplevel()
マルチインデックスのレベル(階層)の順番を変更するにはswaplevel()
メソッドを使う。
第一引数と第二引数に列名またはレベル値を指定すると、ふたつのレベル(階層)が交換される。
print(df_m)
# val_1 val_2
# level_1 level_2 level_3
# A0 B0 C0 98 90
# C1 44 9
# B1 C2 39 17
# C3 75 71
# A1 B2 C0 1 89
# C1 54 60
# B3 C2 47 6
# C3 16 5
# A2 B0 C0 75 22
# C1 19 4
# B1 C2 25 52
# C3 57 40
# A3 B2 C0 64 54
# C1 27 96
# B3 C2 100 77
# C3 22 50
df_m_swap = df_m.swaplevel('level_1', 'level_3')
print(df_m_swap)
# val_1 val_2
# level_3 level_2 level_1
# C0 B0 A0 98 90
# C1 B0 A0 44 9
# C2 B1 A0 39 17
# C3 B1 A0 75 71
# C0 B2 A1 1 89
# C1 B2 A1 54 60
# C2 B3 A1 47 6
# C3 B3 A1 16 5
# C0 B0 A2 75 22
# C1 B0 A2 19 4
# C2 B1 A2 25 52
# C3 B1 A2 57 40
# C0 B2 A3 64 54
# C1 B2 A3 27 96
# C2 B3 A3 100 77
# C3 B3 A3 22 50
df_m_swap = df_m.swaplevel(0, 2)
print(df_m_swap)
# val_1 val_2
# level_3 level_2 level_1
# C0 B0 A0 98 90
# C1 B0 A0 44 9
# C2 B1 A0 39 17
# C3 B1 A0 75 71
# C0 B2 A1 1 89
# C1 B2 A1 54 60
# C2 B3 A1 47 6
# C3 B3 A1 16 5
# C0 B0 A2 75 22
# C1 B0 A2 19 4
# C2 B1 A2 25 52
# C3 B1 A2 57 40
# C0 B2 A3 64 54
# C1 B2 A3 27 96
# C2 B3 A3 100 77
# C3 B3 A3 22 50
sore_index()
でソートすると見やすい。
df_m_swap_sort = df_m.swaplevel('level_1', 'level_3').sort_index()
print(df_m_swap_sort)
# val_1 val_2
# level_3 level_2 level_1
# C0 B0 A0 98 90
# A2 75 22
# B2 A1 1 89
# A3 64 54
# C1 B0 A0 44 9
# A2 19 4
# B2 A1 54 60
# A3 27 96
# C2 B1 A0 39 17
# A2 25 52
# B3 A1 47 6
# A3 100 77
# C3 B1 A0 75 71
# A2 57 40
# B3 A1 16 5
# A3 22 50
ふたつのレベルの交換ではなく任意の順番にレベルを変更したい場合は、reset_index()
で解除してから再度set_index()
で設定すればOK。
df_m_change = df_m.reset_index().set_index(['level_2', 'level_3', 'level_1']).sort_index()
print(df_m_change)
# val_1 val_2
# level_2 level_3 level_1
# B0 C0 A0 98 90
# A2 75 22
# C1 A0 44 9
# A2 19 4
# B1 C2 A0 39 17
# A2 25 52
# C3 A0 75 71
# A2 57 40
# B2 C0 A1 1 89
# A3 64 54
# C1 A1 54 60
# A3 27 96
# B3 C2 A1 47 6
# A3 100 77
# C3 A1 16 5
# A3 22 50