pythonでの階層インデックス&階層カラムの扱い方

pythonでの階層インデックス&階層カラムの扱い方
 df.groupbyやunstackなどの処理を行うと、マルチインデックスで返ってくることが多いのでまとめてみました。
In [1]:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

#マルチインデックスのデータ抽出に便利な関数
idx = pd.IndexSlice
In [2]:
#ダミーデータの作成

index = pd.MultiIndex.from_product((range(1, 5), ['brand_A','brand_b','brand_C']), names=['id', 'brand'])
data = np.random.normal(size=(len(index), 2))
df = pd.DataFrame(data, index=index, columns=['x', 'y'])
df
Out[2]:
x y
id brand
1 brand_A 0.301830 -0.806435
brand_b -0.892886 0.251640
brand_C 2.110377 0.193161
2 brand_A -0.415665 1.755490
brand_b 0.169821 -0.246861
brand_C 0.303027 0.187336
3 brand_A 1.144092 -1.375392
brand_b 1.026717 -0.462429
brand_C 0.376289 -0.668439
4 brand_A -0.962556 -0.430512
brand_b 0.143557 -0.782270
brand_C -0.287031 -0.226092

IDとブランドが階層インデックスとなったデータフレームができました。イメージとしては、5人のブランドイメージスコアなどを想定してもらえればと思います。

外側の階層を抽出する

外側のインデックスでデータ抽出をする場合は、とてもシンプルです。

In [3]:
df.loc[1,:]
Out[3]:
x y
brand
brand_A 0.301830 -0.806435
brand_b -0.892886 0.251640
brand_C 2.110377 0.193161

内側の階層で抽出

内側の階層で抽出する場合、IndexSlice関数を使います。先頭から順番に外側のインデックス指定していきます。brandは2層目なので2番めのリストで指定します。

In [4]:
df.loc[idx[:,'brand_A'],:]
Out[4]:
x y
id brand
1 brand_A 0.301830 -0.806435
2 brand_A -0.415665 1.755490
3 brand_A 1.144092 -1.375392
4 brand_A -0.962556 -0.430512

外側と内側を組合せて抽出

順番にそれぞれの階層を指定すれば、組合せて抽出することも可能です。

In [5]:
df.loc[idx[[1,3],['brand_A','brand_C']],:]
Out[5]:
x y
id brand
1 brand_A 0.301830 -0.806435
brand_C 2.110377 0.193161
3 brand_A 1.144092 -1.375392
brand_C 0.376289 -0.668439

条件式での抽出

カラムの値の条件で抽出することも可能です。

In [6]:
df[df['x']>1]
Out[6]:
x y
id brand
1 brand_C 2.110377 0.193161
3 brand_A 1.144092 -1.375392
brand_b 1.026717 -0.462429

seabornでプロット

seabornは軸を1つ指定する形なので、一旦はreset_indexなどで階層を解除しないと使えない。

In [7]:
sns.boxplot('brand', 'x', data=df.reset_index('brand'))
plt.show()

マルチカラムの扱い

先程のデータをマルチカラムの形にしてみる。

In [8]:
dfa = df.unstack('brand')
dfa
Out[8]:
x y
brand brand_A brand_C brand_b brand_A brand_C brand_b
id
1 0.301830 2.110377 -0.892886 -0.806435 0.193161 0.251640
2 -0.415665 0.303027 0.169821 1.755490 0.187336 -0.246861
3 1.144092 0.376289 1.026717 -1.375392 -0.668439 -0.462429
4 -0.962556 -0.287031 0.143557 -0.430512 -0.226092 -0.782270

カラムの抽出

こちらもIndexSliceで抽出することが可能。

In [9]:
#外側抽出
dfa.loc[:,idx['x']]
Out[9]:
brand brand_A brand_C brand_b
id
1 0.301830 2.110377 -0.892886
2 -0.415665 0.303027 0.169821
3 1.144092 0.376289 1.026717
4 -0.962556 -0.287031 0.143557
In [18]:
#内側抽出
dfa.loc[:,idx[:,'brand_A']]
Out[18]:
x y
brand brand_A brand_A
id
1 0.301830 -0.806435
2 -0.415665 1.755490
3 1.144092 -1.375392
4 -0.962556 -0.430512
In [16]:
#組合せて抽出
dfa.loc[:,idx['x',['brand_A','brand_C']]]
Out[16]:
x
brand brand_A brand_C
id
1 0.301830 2.110377
2 -0.415665 0.303027
3 1.144092 0.376289
4 -0.962556 -0.287031
In [14]:
#条件抽出
dfa[dfa.loc[:,idx['x','brand_A']] > 1] 
Out[14]:
x y
brand brand_A brand_C brand_b brand_A brand_C brand_b
id
3 1.144092 0.376289 1.026717 -1.375392 -0.668439 -0.462429

カラム名称の付け替え

カラム名称が階層型の時は、seabornなどでプロットすることができない。その場合は、一旦、カラム名称を非階層にします。

In [21]:
#カラムの付け替え

levels = dfa.columns.levels
labels = dfa.columns.labels

col_level_1 = levels[0][labels[0]]
col_level_2 = levels[1][labels[1]]

recolnames = [x + "_" + y for x, y in zip(col_level_1, col_level_2)]

#リネームdfを作成
dfa_re = dfa.copy()
dfa_re.columns = recolnames
dfa_re.head()
Out[21]:
x_brand_A x_brand_C x_brand_b y_brand_A y_brand_C y_brand_b
id
1 0.301830 2.110377 -0.892886 -0.806435 0.193161 0.251640
2 -0.415665 0.303027 0.169821 1.755490 0.187336 -0.246861
3 1.144092 0.376289 1.026717 -1.375392 -0.668439 -0.462429
4 -0.962556 -0.287031 0.143557 -0.430512 -0.226092 -0.782270

これで階層が解除されるので、seabornで作図も可能になります。

In [24]:
sns.regplot(data=dfa_re,x='x_brand_A',y='y_brand_A',)
plt.show()

df.groupbyやunstackなどの処理を行うと、マルチインデックスで返ってくることが多いのでまとめてみました。下にpandasの参考書籍などを紹介しておくので、ご参考までに。

Pythonカテゴリの最新記事