DataFrameのMultiIndexでつまづく人のために

MultiIndexは便利だけど、ちょっとした処理でしょっちゅうつまづくので、忘れないようにやり方をメモしておく。

データセット

```python
df = pd.DataFrame({'地方':['北海道','北海道','東北','東北','関東'],
                  '都道府県':['北海道','北海道','青森','岩手','千葉'],
                  '振興局':['オホーツク','根室','','',''],
                  'いわし':[20,8,15,5,46],
                  'さば':[1,2,20,10,29]}).set_index(['地方','都道府県','振興局'])
```
| 地方  | 都道府県 | 振興局  | いわし<br>　 <br>　 |さば<br>　<br>　 |
|:-----:|:-----:|:-----:|:-----:|:-----:|
| 北海道 |北海道|オホーツク|20|1|
| 北海道 |北海道|釧路     |8|2|
| 東北 |青森    |        |15|20|
| 東北 |岩手    |        |5|10|
| 関東 |千葉    |        |46|29|


# 特定のレベルのラベル一覧を取得
## 単独のレベル
都道府県の一覧を取得。ソートが必要なら`.sort_values()`を後ろに付ける。

```python
# ！version 0.23.0.以降
df.index.unique('都道府県') 
# Index(['北海道', '青森', '岩手', '千葉'], dtype='object', name='都道府県')

# ！version 0.23.0.より前
df.index.get_level_values('都道府県').unique() 
# Index(['北海道', '青森', '岩手', '千葉'], dtype='object', name='都道府県')
```

## 複数のレベル
地方、都道府県の組み合わせの一覧を取得。欲しくない振興局をインデックスレベルから外す。

```python:要らないレベルを指定
df.index.droplevel(['振興局']).drop_duplicates()
# MultiIndex(levels=[['北海道', '東北', '関東'], ['北海道', '千葉', '岩手', '青森']],
#            codes=[[0, 1, 1, 2], [0, 3, 2, 1]],
#            names=['地方', '都道府県'])
```

```python:必要なレベルを指定
selected_levels = ['地方', '都道府県']
dropped_levels = list(set(df.index.names) - set(selected_levels))
df.index.droplevel(dropped_levels).drop_duplicates()
# MultiIndex(levels=[['北海道', '東北', '関東'], ['北海道', '千葉', '岩手', '青森']],
#            codes=[[0, 1, 1, 2], [0, 3, 2, 1]],
#            names=['地方', '都道府県'])
```

# レベル順序の変更
## スワップ
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.MultiIndex.swaplevel.html#pandas.MultiIndex.swaplevel
都道府県と振興局を入れ替え。

```python
df.index = df.index.swaplevel('都道府県','振興局')
df
```

| 地方  | 振興局| 都道府県   | いわし<br>　 <br>　 |さば<br>　<br>　 |
|:-----:|:-----:|:-----:|:-----:|:-----:|
| 北海道 |オホーツク|北海道|20|1|
| 北海道 |釧路|北海道     |8|2|
| 東北 ||青森            |15|20|
| 東北 ||岩手            |5|10|
| 関東 ||千葉            |46|29|


## 任意の順序
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.MultiIndex.reorder_levels.html#pandas.MultiIndex.reorder_levels
振興局、都道府県、地方の順に入れ替え。

```python
df.index = df.index.reorder_levels(['振興局','都道府県','地方'])
df
```
|振興局  | 都道府県 |  地方  | いわし<br>　 <br>　 |さば<br>　<br>　 |
|:-----:|:-----:|:-----:|:-----:|:-----:|
|オホーツク|北海道| 北海道 |20|1|
|釧路|北海道| 北海道      |8|2|
||青森    |         東北 |15|20|
||岩手    | 東北 |        5|10|
||千葉    | 関東 |       46|29|

# インデックスの置換
```python
df.rename(index={'青森':'秋田'},level='都道府県')
```
| 地方  | 都道府県 | 振興局  | いわし<br>　 <br>　 |さば<br>　<br>　 |
|:-----:|:-----:|:-----:|:-----:|:-----:|
| 北海道 |北海道|オホーツク|20|1|
| 北海道 |北海道|釧路     |8|2|
| 東北 |秋田    |        |15|20|
| 東北 |岩手    |        |5|10|
| 関東 |千葉    |        |46|29|

# 最上位レベルの追加
ややテクニカルな方法。

```python
pd.concat([df],keys=['日本'],names=['国'])
```

| 国 | 地方  | 都道府県 | 振興局  | いわし<br>　 <br>　 |さば<br>　<br>　 |
|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|
| 日本 | 北海道 |北海道|オホーツク|20|1|
| 日本 | 北海道 |北海道|釧路     |8|2|
| 日本 | 東北 |秋田    |        |15|20|
| 日本 | 東北 |岩手    |        |5|10|
| 日本 | 関東 |千葉    |        |46|29|



# 列のマルチインデックスの解除
https://code.i-harness.com/ja-jp/q/d8847f#0
https://stackoverflow.com/questions/14189695/reset-a-columns-multiindex-levels