note.nkmk.me

pandasのMultiIndexから任意の行・列を選択、抽出

Date: 2018-02-01 / tags: Python, pandas
このエントリーをはてなブックマークに追加

pandas.DataFramepandas.Seriesのインデックスを階層的に構成できるマルチインデックスを使うと、階層ごとに合計や平均などの統計量を算出できて便利。

ただ、マルチインデックスの行・列の選択(抽出)方法に若干クセがあるので注意が必要。

公式ドキュメントでは以下の節で説明されている。

例として、以下のcsvデータを使用する。

import pandas as pd

df = pd.read_csv('data/src/sample_multi.csv', index_col=[0, 1, 2])
print(df)
#                          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

print(df.sum(level='level_2'))
#          val_1  val_2
# level_2              
# B0         236    125
# B1         196    180
# B2         146    299
# B3         185    138

print(df.sum(level=['level_2', 'level_3']))
#                  val_1  val_2
# level_2 level_3              
# B0      C0         173    112
#         C1          63     13
# B1      C2          64     69
#         C3         132    111
# B2      C0          65    143
#         C1          81    156
# B3      C2         147     83
#         C3          38     55

locで任意の行・列を選択、抽出

通常のインデックスと同様、loc[]を使って任意の行・列を選択、抽出することができる。

以下の場合は列全体を指定するスライス:を省略できるが、あとで説明するslice(None)pd.IndexSliceを使う場合などは省略できない(エラーになる)ので、明示的に指定しておいたほうが無難。

print(df.loc['A0', 'val_1'])
# level_2  level_3
# B0       C0         98
#          C1         44
# B1       C2         39
#          C3         75
# Name: val_1, dtype: int64

print(df.loc['A0', :])
#                  val_1  val_2
# level_2 level_3              
# B0      C0          98     90
#         C1          44      9
# B1      C2          39     17
#         C3          75     71

print(df.loc['A0'])
#                  val_1  val_2
# level_2 level_3              
# B0      C0          98     90
#         C1          44      9
# B1      C2          39     17
#         C3          75     71

スライスやリストで範囲を選択することが可能。

print(df.loc['A0':'A2', :])
#                          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

print(df.loc[['A0', 'A2'], :])
#                          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
# A2      B0      C0          75     22
#                 C1          19      4
#         B1      C2          25     52
#                 C3          57     40

上の階層から順に値を指定して絞り込んでいくこともできる。

print(df.loc[('A0', 'B1'), :])
#          val_1  val_2
# level_3              
# C2          39     17
# C3          75     71

print(df.loc[('A0', 'B1', 'C2'), :])
# val_1    39
# val_2    17
# Name: (A0, B1, C2), dtype: int64

slice(None), pd.IndexSlice

マルチインデックスに対して、全体を表すスライス:をそのまま使うとエラーとなる。

slice(None)に置き換えるかpd.IndexSliceを使う必要がある。

# print(df.loc[(:, 'B1'), :]) => SyntaxError
print(df.loc[(slice(None), 'B1'), :])
#                          val_1  val_2
# level_1 level_2 level_3              
# A0      B1      C2          39     17
#                 C3          75     71
# A2      B1      C2          25     52
#                 C3          57     40

print(df.loc[pd.IndexSlice[:, 'B1'], :])
#                          val_1  val_2
# level_1 level_2 level_3              
# A0      B1      C2          39     17
#                 C3          75     71
# A2      B1      C2          25     52
#                 C3          57     40

xsメソッド

xs()メソッドで、インデックス名とその値を指定して選択、抽出することもできる。

print(df.xs('B1', level='level_2'))
#                  val_1  val_2
# level_1 level_3              
# A0      C2          39     17
#         C3          75     71
# A2      C2          25     52
#         C3          57     40

複数のインデックスに対する値をリストで指定することも可能。

print(df.xs(['B1', 'C2'], level=['level_2', 'level_3']))
#          val_1  val_2
# level_1              
# A0          39     17
# A2          25     52

ただし、xs()メソッドでは一つのインデックス列に対してスライスやリストで複数の値を指定することができない。そのような場合はloc[]を使う。

# print(df.xs(['B1', 'B2'], level='level_2')) => KeyError
print(df.loc[pd.IndexSlice[:, ['B1', 'B2']], :])
#                          val_1  val_2
# level_1 level_2 level_3              
# A0      B1      C2          39     17
#                 C3          75     71
# A1      B2      C0           1     89
#                 C1          54     60
# A2      B1      C2          25     52
#                 C3          57     40
# A3      B2      C0          64     54
#                 C1          27     96
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事