よっしーの私的空間

機械学習を中心に興味のあることについて更新します

縦持ちデータを横持ちデータに変換する方法(Pandas)

データを縦持ちから横持ちに変換する方法について解説します。 横持ちデータを縦持ちデータに変換する方法についてはこちらでまとめています。

1.そもそも縦持ちと横持ちとは

縦持ちとは縦に長いデータで以下のようなデータのことです。

氏名 科目 点数
A君 数学 100
A君 国語 70
A君 英語 60
A君 ドイツ語 60
B君 数学 60
B君 国語 50
B君 英語 50
B君 アラビア語 60

一方、横持ちとは横に長いデータで以下のようなデータです。

氏名 数学 国語 英語 ドイツ語 アラビア語
A君 100 70 60 60 NaN
B君 60 50 50 NaN 60

上記の例ですと、横持ちの方がすっきりしていて、良いように感じますが、必ずしもそうではありません。どのようなデータの場合、縦持ちの方が良いか後述します。まずは、Pandasで縦持ちデータを横持ちに変換する方法について記載します。

2.縦持ちを横持ちに変換する方法

以下の通りです。まずは縦持ちのサンプルデータを作成します。

df_score_vertical = pd.DataFrame([['A君','数学',100],
                                  ['A君','国語',70],
                                  ['A君','英語',60],
                                  ['A君','ドイツ語',60],
                                  ['B君','数学',60],
                                  ['B君','国語',50],
                                  ['B君','英語',50],
                                  ['B君','アラビア語',60]],
                                 columns=['氏名','科目','点数'])

以下のコードで横持ちに変換できます。

df_score_horizontal = pd.pivot_table(df_score_vertical,
                                     index=['氏名'],
                                     columns=['科目'],
                                     values='点数',
                                     fill_value=0)

上記のコードを実行すると以下のようなDataFrameが作成されます。
f:id:t-yoshi-book:20210609230701p:plain

カラム名が2段になっていますし、「氏名」がIndexになってしまっています。こうならないようにするために以下のようなコードを実行します。多少強引ですが、カラムの貼り直しをしています。

df_score_horizontal = pd.pivot_table(df_score_vertical,
                                     index=['氏名'],
                                     columns=['科目'],
                                     values='点数',
                                     fill_value=0).reset_index()
df_score_horizontal.columns = df_score_horizontal.columns.to_list()

上記を実行することで以下のようなDataFrameができます。たぶん、多くの人が欲しい結果ではないでしょうか。
f:id:t-yoshi-book:20210609231546p:plain

3.縦持ちデータの方が良い例

極端な例ですが、以下のようなデータの場合は横持ちにしてしまうと無駄に表が大きくなってしまいます。

<横持ちの場合>

氏名 フランス語 ドイツ語 アラビア語 ベトナム語
A君 100 NaN NaN NaN
B君 NaN 50 NaN NaN
C君 NaN NaN NaN 80
B君 NaN NaN 50 NaN

欠損値だらけで無駄が多いです。上記のようなデータを疎行列(スパースマトリックス)といいます。以下のように縦持ちにすることですっきりして、データサイズも削減できます。

縦持ちで表現するとスマートです。

氏名 科目 点数
A君 フランス語 100
B君 ドイツ語 50
C君 ベトナム語 80
D君 アラビア語 50
関連記事

SQLで縦持ちデータを横持ちデータに変換する方法についてもまとめたので、良ければ参考にしてください。
book-read-yoshi.hatenablog.com