Python: PandasのDataFrameを横持ち・縦持ちに変換する
PandasのDataFrameを縦持ちから横持ちにする方法とその逆(横持ちから縦持ちにする方法)についての備忘録です。
縦持ちと横持ち
縦持ちは、以下のように、カラム固定で1行に1つの値を持たせている表です。カラムをおいそれと変更できないDBのテーブルなどはこういった形かと思います。
customer_id | product_id | count |
---|---|---|
C1 | P1 | 1 |
C1 | P2 | 2 |
C2 | P2 | 2 |
C2 | P2 | 1 |
C3 | P3 | 3 |
一方で、横持ちは、カラム数が可変で1行に複数の値をもたせている表です。行列はこういう形になるでしょう。
P1 | P2 | P3 | |
---|---|---|---|
C1 | 1 | 2 | 0 |
C2 | 0 | 3 | 0 |
C3 | 0 | 0 | 3 |
縦持ちから横持ちへ変換する
それでは縦持ちとなっている以下のデータを横持ちへ変換します。
import pandas as pd import numpy as np orders_df = pd.DataFrame({'customer_id': ['C1', 'C1', 'C2', 'C2', 'C3'], 'product_id': ['P1', 'P2', 'P2', 'P2', 'P3'], 'count': [1, 2, 2, 1, 3]})
横持ちにするときは、Pandasのpivot_tableメソッドを使います。 インデックスにcustomer_id、カラムにはproduct_idを指定することで、customer_id×product_idの横持ちテーブルとなります。
pivot_orders_df = orders_df.pivot_table(values=['count'], index=['customer_id'], columns=['product_id'], aggfunc='sum')
いくつかオプション引数があります。
aggfunc
には、同じcustomer_idとproduct_idの値を集約するためのnumpyの関数を指定します- 例えば、customer_id='C2'とprodct_id='P2'の組み合わせが2つありますが、合計値3で埋められてます
- デフォルトでは"mean"ですが、"sum"、"count"、"max"、"min"などが使えます
fill_value
で、欠測値を指定します (デフォルトではNaN)
横持ちから縦持ちへ変換する
上で横持ちにしたテーブルを縦持ちに戻します。
縦持ちにするときは、stackメソッドが使えます。
orders_df = pivot_orders_df.stack()
dropna=Falseとすると、NaNの行となります。
orders_df = pivot_orders_df.stack(dropna=False)
元のテーブルの通り、インデックスではなくカラムにする場合は、reset_indexメソッドでカラム化します。
orders_df = pivot_orders_df.stack().reset_index()