pandasのMultiindexの指定・追加・解除・ソート・レベル変更

Posted: | Tags: Python, pandas

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()

引数appendTrueとすると追加される。デフォルトは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()の引数inplaceTrueとすると、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

マルチインデックスから解除してデータ列からも削除したい場合は引数dropTrueとする。

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()でも引数inplaceTrueとすると、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

関連カテゴリー

関連記事