この間、Pandasを使った教材を流し読みしていると、DataFrameクラスのmeltというメソッドが出てきて、pivotの逆だと説明されていた。それを読んで、meltされたものをpivotして元に戻してみよう思って、すきま時間を集めてのべ1時間くらいがんばったが、できなかった。
ついでに、meltとstackの違いがわからなかった。
今月、1時間くらい連続してがんばったら成功して、meltとstackの違いも理解できたので、ここに控えておく。
以下、コード例はJupyter Notebookで書いたインタラクティブシェル向けの形式のものをそのまま貼り付けており、出力例はJupyter Notebookの出力を加工して作成している。
In [1]:
import pandas as pd
df = pd.DataFrame({'月': ['1月', '2月', '3月'],
'京都': [110, 115, 144],
'大阪': [263, 283, 309],
'奈良': [12, 13, 21],
})
df
Out [1]:
月 | 京都 | 大阪 | 奈良 | |
---|---|---|---|---|
0 | 1月 | 110 | 263 | 12 |
1 | 2月 | 115 | 283 | 13 |
2 | 3月 | 144 | 309 | 21 |
このようなDataFrameがあるとして、これをmeltして、pivotで元に戻してみる。
In [2]:
df_melted = df.melt(id_vars='月', var_name='地域', value_name='人数')
df_melted
Out [2]:
月 | 地域 | 人数 | |
---|---|---|---|
0 | 1月 | 京都 | 110 |
1 | 2月 | 京都 | 115 |
2 | 3月 | 京都 | 144 |
3 | 1月 | 大阪 | 263 |
4 | 2月 | 大阪 | 283 |
5 | 3月 | 大阪 | 309 |
6 | 1月 | 奈良 | 12 |
7 | 2月 | 奈良 | 13 |
8 | 3月 | 奈良 | 21 |
df_pivoted = df_melted.pivot(index='月', columns='地域', values='人数')
df_pivoted
Out [3]:
地域 | 京都 | 大阪 | 奈良 |
---|---|---|---|
月 | |||
1月 | 110 | 263 | 12 |
2月 | 115 | 283 | 13 |
3月 | 144 | 309 | 21 |
meltしたものをpivotすると大体戻ったが、「月」がindexになっているのと、meltで加えた「地域」が残っているのが異なるので、修正する。
(ちなみに、reset_indexしただけでは「月」が「地域」に入っておかしなことになる)
df_pivoted = df_pivoted.reset_index()
df_pivoted.columns.name = None
df_pivoted
Out [4]:
月 | 京都 | 大阪 | 奈良 | |
---|---|---|---|---|
0 | 1月 | 110 | 263 | 12 |
1 | 2月 | 115 | 283 | 13 |
2 | 3月 | 144 | 309 | 21 |
次に、meltとstackの違いを見てみる。
上のdfをstackすると「月」と地域名が同列に処理されてしまうので、まず「月」をインデックスにしてからstackする。
df2 = df.set_index('月')
df2
Out [5]:
京都 | 大阪 | 奈良 | |
---|---|---|---|
月 | |||
1月 | 110 | 263 | 12 |
2月 | 115 | 283 | 13 |
3月 | 144 | 309 | 21 |
この場合はstackすると結果が1列なのでDataFrameでなくSeriesになるので、変数名の先頭をdf_でなくsr_にしている。
In [6]:
sr_stacked = df2.stack()
sr_stacked
Out [6]:
月 | ||
---|---|---|
1月 | 京都 | 110 |
大阪 | 263 | |
奈良 | 12 | |
2月 | 京都 | 115 |
大阪 | 283 | |
奈良 | 13 | |
3月 | 京都 | 144 |
大阪 | 309 | |
奈良 | 21 |
当然ながら、stackしたものをunstackすると元に戻る。
In [7]:
sr_stacked.unstack()
Out [7]:
京都 | 大阪 | 奈良 | |
---|---|---|---|
月 | |||
1月 | 110 | 263 | 12 |
2月 | 115 | 283 | 13 |
3月 | 144 | 309 | 21 |
meltでは元々column名だった列(「地域」列)がindexにならなかったが、stackではindexになっている。つまり、meltはcolumn名を新たに加えた通常の列に展開することによって表を変形し、stackはcolumn名をindexの新たな階層に展開することによって表を変形する。このことがmeltとstackの主な違いのようだ。
次のようにして、stackしたもののindexを通常の列に戻すと、meltした結果(Out [2])と同じになる。
df_stacked = sr_stacked.sort_index(level=1).reset_index()
df_stacked.columns = ['月', '地域', '人数']
df_stacked
Out [8]:
月 | 地域 | 人数 | |
---|---|---|---|
0 | 1月 | 京都 | 110 |
1 | 2月 | 京都 | 115 |
2 | 3月 | 京都 | 144 |
3 | 1月 | 大阪 | 263 |
4 | 2月 | 大阪 | 283 |
5 | 3月 | 大阪 | 309 |
6 | 1月 | 奈良 | 12 |
7 | 2月 | 奈良 | 13 |
8 | 3月 | 奈良 | 21 |
なお、pivotは単にset_indexとunstackを使って階層的なインデックスを作る為のショートカットだ、というようなことが、O'REILLYの「Pythonによるデータ分析入門」に書かれている。
次のようにset_indexとunstackを使うと、pivotの結果(Out [3])と一致する。
df_melted.set_index(['月', '地域']).unstack()['人数']
Out [9]:
地域 | 京都 | 大阪 | 奈良 |
---|---|---|---|
月 | |||
1月 | 110 | 263 | 12 |
2月 | 115 | 283 | 13 |
3月 | 144 | 309 | 21 |
やっぱり、理解するという行為は集中してないとできず、すきま時間にやるのは無謀だと思い知った。
コメント