概要
MultiIndexを使用したデータフレームでpandas.DataFrame.joinを実行する際に気をつけるべきことを記します。
準備
# 必要なモジュールをインポート
import pandas as pd
# データフレームの作成
df = pd.DataFrame()
df["name"] = ["hoge"] * 6 + ["fuga"] * 6
df["year"] = (["2017"] * 2 + ["2018"] * 2 + ["2019"] * 2) * 2
df["season"] = ["summer", "winter"] * 6
df["height"] = [160, 161, 163, 166, 168, 169, 180, 180, 181, 181, 182, 183]
df["weight"] = [50, 52, 52, 55, 54, 56, 70, 72, 73, 75, 75, 78]
df
| name | year | season | height | weight | |
|---|---|---|---|---|---|
| 0 | hoge | 2017 | summer | 160 | 50 |
| 1 | hoge | 2017 | winter | 161 | 52 |
| 2 | hoge | 2018 | summer | 163 | 52 |
| 3 | hoge | 2018 | winter | 166 | 55 |
| 4 | hoge | 2019 | summer | 168 | 54 |
| 5 | hoge | 2019 | winter | 169 | 56 |
| 6 | fuga | 2017 | summer | 180 | 70 |
| 7 | fuga | 2017 | winter | 180 | 72 |
| 8 | fuga | 2018 | summer | 181 | 73 |
| 9 | fuga | 2018 | winter | 181 | 75 |
| 10 | fuga | 2019 | summer | 182 | 75 |
| 11 | fuga | 2019 | winter | 183 | 78 |
MultiIndexを設定
"name", "year", "season"をMultiIndexに持ち、"height"をカラムに持つデータフレームを作成します。
df1 = df.set_index(["name", "year", "season"])[['height']]
df1
| height | |||
|---|---|---|---|
| name | year | season | |
| hoge | 2017 | summer | 160 |
| winter | 161 | ||
| 2018 | summer | 163 | |
| winter | 166 | ||
| 2019 | summer | 168 | |
| winter | 169 | ||
| fuga | 2017 | summer | 180 |
| winter | 180 | ||
| 2018 | summer | 181 | |
| winter | 181 | ||
| 2019 | summer | 182 | |
| winter | 183 |
次に、MultiIndexの順番を"name"->"season"->"year"に変え、"weight"をカラムに持つデータフレームを作成します。
df2 = df.set_index(["name", "season", "year"])[['weight']]
df2
| weight | |||
|---|---|---|---|
| name | season | year | |
| hoge | summer | 2017 | 50 |
| winter | 2017 | 52 | |
| summer | 2018 | 52 | |
| winter | 2018 | 55 | |
| summer | 2019 | 54 | |
| winter | 2019 | 56 | |
| fuga | summer | 2017 | 70 |
| winter | 2017 | 72 | |
| summer | 2018 | 73 | |
| winter | 2018 | 75 | |
| summer | 2019 | 75 | |
| winter | 2019 | 78 |
データフレームの結合
上記で作成した二つのデータフレームをインデックスをkeyとして結合します。
df1.join(df2)
# NotImplementedError: merging with more than one level overlap on a multi-index is not implemented
すると上記のようなエラー文が発生します。原因はそう、インデックスの順番が異なっているからです。
インデックスの順番を揃えて結合
インデックスの順番を揃え直し、再び結合してみます。
df2.index = df2.index.swaplevel("season", "year")
df1.join(df2)
| height | weight | |||
|---|---|---|---|---|
| name | year | season | ||
| hoge | 2017 | summer | 160 | 50 |
| winter | 161 | 52 | ||
| 2018 | summer | 163 | 52 | |
| winter | 166 | 55 | ||
| 2019 | summer | 168 | 54 | |
| winter | 169 | 56 | ||
| fuga | 2017 | summer | 180 | 70 |
| winter | 180 | 72 | ||
| 2018 | summer | 181 | 73 | |
| winter | 181 | 75 | ||
| 2019 | summer | 182 | 75 | |
| winter | 183 | 78 |
うまくいきました。
まとめ
今回は簡単な例で説明したため、こんなことが本当に起こるのかと思われますが、実際に大量のデータセットで複雑な結合などをしているとこのような状態になることがあります(少なくとも僕はありました)。MultiIndexを使わずとも処理する方法はありますが、もし使う際には注意する必要があります。