前回の記事で「階層型インデックス」に関する概要を説明した。

pandas 階層型インデックス

今回は、階層型インデックスで構成されたデータセットに対するあらゆる操作方法について紹介していく。

階層のソート

インデックス階層の順序を変更する場合、swaplevelメソッドを使う。

まずはサンプルとなるデータフレームを用意しよう。

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']
                 ])

df.index.names = ['key1', 'key2']
df.columns.names = ['pref', 'station']
# pref          Tokyo Osaka      
# station   Shinagawa Umeda Namba
# key1 key2                      
# a    1            0     1     2
#      2            3     4     5
# b    1            6     7     8
#      2            9    10    11

用意したデータフレームのインデックス階層の順序を変更してみよう。

swaplevelメソッドの引数に渡したキーの順序が入れ替わり、key2をベースに昇順された結果が得られる。

なお、順序を変更したデータのコピーを返すので、元のデータは変更されない。

df2 = df.swaplevel('key1', 'key2')
# pref          Tokyo Osaka      
# station   Shinagawa Umeda Namba
# key2 key1                      
# 1    a            0     1     2
#      a            3     4     5
# 2    b            6     7     8
#      b            9    10    11

また、sort_indexというメソッドも用意されている。

こちらは特定の一つの階層の値のみを使ってソートをおこなう。

df3 = df.sort_index(level=1)
# pref          Tokyo Osaka      
# station   Shinagawa Umeda Namba
# key1 key2                      
# a    1            0     1     2
# b    1            6     7     8
# a    2            3     4     5
# b    2            9    10    11

以下のようにswaplevelとsort_indexを組み合わせ、階層を入れ替えた後にソートする方法はよく使われる。

df4 = df.swaplevel(0, 1).sort_index(level=0)
# pref          Tokyo Osaka      
# station   Shinagawa Umeda Namba
# key2 key1                      
# 1    a            0     1     2
#      b            6     7     8
# 2    a            3     4     5
#      b            9    10    11

階層ごとの要約統計量

データセットの要約統計量にlevelオプションを与えると、集計対象としたい階層を指定することができる。

先程用意したデータフレームを使って例を見ていこう。

df
# pref          Tokyo Osaka      
# station   Shinagawa Umeda Namba
# key1 key2                      
# a    1            0     1     2
#      2            3     4     5
# b    1            6     7     8
#      2            9    10    11

df.sum(level='key2')
# pref        Tokyo Osaka      
# station Shinagawa Umeda Namba
# key2                         
# 1               6     8    10
# 2              12    14    16

df.sum(level='pref', axis=1)
# pref       Tokyo  Osaka
# key1 key2              
# a    1         0      3
#      2         3      9
# b    1         6     15
#      2         9     21

上記例のようにaxisオプションで軸を指定すると、より幅広い集計をおこなうことが可能だ。

データフレームの列をインデックスとして使う

データフレームの列の値を行インデックスとして、逆に行インデックスを列に変換する事もできる。

別のデータフレームを用意して例を見てみよう。

import pandas as pd

df = pd.DataFrame(
    {'a': range(7),
     'b': range(7, 0, -1),
     'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'],
     'd': [0, 1, 2, 0, 1, 2, 3]
    })

#    a  b    c  d
# 0  0  7  one  0
# 1  1  6  one  1
# 2  2  5  one  2
# 3  3  4  two  0
# 4  4  3  two  1
# 5  5  2  two  2
# 6  6  1  two  3

set_indexメソッドを使うと、指定した列を行インデックスとして持つ新たなデータフレームを作ることができる。

df2 = df.set_index(['c', 'd'])
#        a  b
# c   d      
# one 0  0  7
#     1  1  6
#     2  2  5
# two 0  3  4
#     1  4  3
#     2  5  2
#     3  6  1

行インデックスに変換した列はデフォルトでは削除されてしまうが、残しておきたい場合はdropオプションにFalseを指定する。

df2 = df.set_index(['c', 'd'], drop=False)
#        a  b    c  d
# c   d              
# one 0  0  7  one  0
#     1  1  6  one  1
#     2  2  5  one  2
# two 0  3  4  two  0
#     1  4  3  two  1
#     2  5  2  two  2
#     3  6  1  two  3

行インデックスを列に変換する場合、reset_indexメソッドを使う。
これはset_indexメソッドと全く逆の動作をおこなう。

df2 = df.set_index(['c', 'd'])
#        a  b    c  d
# c   d              
# one 0  0  7  one  0
#     1  1  6  one  1
#     2  2  5  one  2
# two 0  3  4  two  0
#     1  4  3  two  1
#     2  5  2  two  2
#     3  6  1  two  3

df3 = df2.reset_index()
#      c  d  a  b
# 0  one  0  0  7
# 1  one  1  1  6
# 2  one  2  2  5
# 3  two  0  3  4
# 4  two  1  4  3
# 5  two  2  5  2
# 6  two  3  6  1