【Pandasデータ整形】stack(), unstack(), pivot()で縦横無尽にデータを変換!


 

データ分析において、データの形式は分析の目的や使用するツールによって最適な形が異なります。例えば、同じデータでも、ある時は「地域が行、商品が列」の形式が欲しく、別の時には「地域と商品が縦に並んだ形式」が必要になることがあります。Pandasは、このようなデータの「形」を自在に変換するための強力なメソッドを提供しています。それが、stack(), unstack(), そして**pivot()**です。

これらのメソッドを使いこなすことで、複雑なデータも分析しやすい形に整形し、集計や可視化を効率的に進めることができます。この記事では、stack(), unstack(), pivot()の基本的な使い方から、それぞれの違い、そして知っておくと便利な応用例まで、短いサンプルコードと丁寧な解説を交えてご紹介します。


 

データ整形(リシェイプ)とは?なぜ必要なのか?

 

データ整形(またはリシェイプ、再構築)とは、DataFrameの行と列の配置を変更し、データの構造を変換するプロセスです。

なぜデータ整形が必要なのでしょうか?

  • 分析要件への適合: 統計モデルやグラフ描画ツールは、特定のデータ形式を要求することがあります。

  • 可読性の向上: データを理解しやすく、人間が見やすい形式に変換します。

  • 集計の準備: groupby()などの集計操作を行う前に、データを適切な粒度に変換します。

  • データベースとの連携: 正規化されたデータ形式や、特定のデータベーススキーマに合わせた形に変換します。


 

stack():列から行へデータを「積み上げる」

 

stack()メソッドは、DataFrameの**列(カラム)をインデックスレベル(行)に「積み上げる」**操作を行います。これにより、ワイド形式(横に広い形式)のデータをロング形式(縦に長い形式)に変換できます。主にMultiIndex(複数階層のインデックス)を持つSeriesが結果として生成されます。

 

基本的な使い方

 

Python
 
import pandas as pd
import numpy as np

# サンプルDataFrameの作成
df_wide = pd.DataFrame({
    '地域': ['東京', '大阪'],
    '商品A売上': [100, 150],
    '商品B売上': [200, 180]
})
print("元のワイド形式DataFrame:\n", df_wide)

# '商品A売上'と'商品B売上'の列をインデックスに積み上げる
df_stacked = df_wide.set_index('地域').stack()
print("\n`stack()`で積み上げたデータ:\n", df_stacked)

解説:

  1. df_wide.set_index('地域'): まず、'地域'列をインデックスに設定します。これはstack()を適用する準備として一般的です。

  2. .stack(): 設定されたインデックス(この場合は'地域')以外の列('商品A売上', '商品B売上')を、新しいインデックスレベルとして行に積み上げます。

  3. 結果はMultiIndexを持つSeriesになります。新しいインデックスレベルの名前は自動的に0が割り当てられますが、.rename_axis()で後から変更可能です。

 

MultiIndexの列を持つDataFrameをstackする

 

列がMultiIndexの場合、level引数でどのレベルを積み上げるか指定できます。

Python
 
# MultiIndexの列を持つDataFrame
idx_cols = pd.MultiIndex.from_product([['売上', '費用'], ['1月', '2月']], names=['項目', '月'])
df_multi_cols = pd.DataFrame(
    np.random.randint(50, 200, (2, 4)),
    index=['A店', 'B店'],
    columns=idx_cols
)
print("\nMultiIndex列を持つDataFrame:\n", df_multi_cols)

# 最下層のレベル ('月') を積み上げる
df_stacked_level = df_multi_cols.stack(level='月')
print("\nMultiIndex列を`stack()`で積み上げ後:\n", df_stacked_level)

 

unstack():インデックスから列へデータを「広げる」

 

unstack()メソッドは、stack()の逆の操作で、DataFrameまたはSeriesの**インデックスレベル(行)を列に「広げる」**操作を行います。これにより、ロング形式のデータをワイド形式に変換できます。

 

基本的な使い方

 

Python
 
# 先ほどstackしたSeriesを使用
print("元のstackされたSeries:\n", df_stacked)

# 最下層のインデックスレベル(商品種別)を列に広げる
df_unstacked = df_stacked.unstack()
print("\n`unstack()`で広げたデータ:\n", df_unstacked)

解説:

  1. df_stacked.unstack(): MultiIndexの最も内側のレベル(この場合は'商品A売上', '商品B売上'といった列名だった部分)を列に広げます。

  2. 結果は元のDataFrameと似た形に戻ります。

 

特定のインデックスレベルをunstackする

 

MultiIndexのDataFrameやSeriesで、level引数を使ってどのインデックスレベルを列に広げるか指定できます。

Python
 
# '月'レベルをunstackする
df_unstacked_level = df_stacked_level.unstack(level='月')
print("\n'月'レベルを`unstack()`で広げたデータ:\n", df_unstacked_level)

# '項目'レベルをunstackする
df_unstacked_item = df_stacked_level.unstack(level='項目')
print("\n'項目'レベルを`unstack()`で広げたデータ:\n", df_unstacked_item)

 

pivot():特定の列を軸にデータを「回転」

 

pivot()メソッドは、DataFrameの特定の列の値を新しい列名として使用し、データを再整形します。pivot_table()と似ていますが、pivot()集計機能を持たず、重複するインデックス/カラムの組み合わせが存在しない場合にのみ使用できます。つまり、同じ行と列の組み合わせに複数の値が存在しない「ユニーク」なデータセットに適しています。

 

基本的な使い方

 

Python
 
# pivot用のDataFrame (重複なし)
df_pivot_data = pd.DataFrame({
    '日付': ['2023-01-01', '2023-01-01', '2023-01-02', '2023-01-02'],
    '地域': ['東京', '大阪', '東京', '大阪'],
    '売上': [100, 150, 120, 180]
})
print("\n元のDataFrame (pivot用):\n", df_pivot_data)

# '日付'を行、'地域'を列、'売上'を値にするピボット
df_pivoted = df_pivot_data.pivot(index='日付', columns='地域', values='売上')
print("\n`pivot()`で整形したデータ:\n", df_pivoted)

解説:

  1. index='日付': '日付'列のユニークな値が行インデックスになります。

  2. columns='地域': '地域'列のユニークな値が列ヘッダーになります。

  3. values='売上': '売上'列の値が新しい表のセルに配置されます。

重要: pivot()は、指定したindexcolumnsの組み合わせが重複する場合(例: 2023-01-01の東京の売上が2つある場合)はエラーになります。その場合は、pivot_table()を使います。


 

stack(), unstack(), pivot()の使い分けとpivot_table()との比較

 

これら3つのメソッドはデータの整形に非常に役立ちますが、それぞれに得意なシチュエーションがあります。また、pivot_table()もデータ整形によく使われるため、その違いも理解しておきましょう。

  • stack():

    • ワイド→ロング変換。列名をインデックスレベルに変換したい場合に最適。

    • 結果はMultiIndexのSeriesになることが多い。

  • unstack():

    • ロング→ワイド変換。インデックスレベルを列名に変換したい場合に最適。

    • stack()の逆の操作。

  • pivot():

    • 特定の列を新しいインデックス、新しいカラム、新しい値としてDataFrameを再構築。

    • 集計機能なしindexcolumnsの組み合わせに重複がない(一意である)必要がある。

    • シンプルで高速なデータ回転に適している。

  • pivot_table():

    • pivot()強化版

    • indexcolumnsの組み合わせが重複しても、aggfunc(集計関数)で集計して処理できる

    • データクレンジングや欠損値処理(fill_value)、小計(margins)など、より多くのオプションがある。

    • 集計が伴うデータ整形にはこちらを使うのが一般的。

使い分けのヒント:

  • 集計が必要なく、ユニークな組み合わせのデータを整形したい: pivot()

  • ワイド形式をロング形式に、あるいはその逆: stack() / unstack()

  • 集計しながらデータを整形したい、または重複する組み合わせがある: pivot_table()


 

まとめ

 

Pandasのstack(), unstack(), pivot()メソッドは、DataFrameの構造を柔軟に変換し、様々な分析や可視化の要件に合わせたデータ整形を可能にする強力なツールです。stack()でデータを縦に積み上げ、unstack()で横に広げ、pivot()で特定の列を軸にデータを回転させることで、あなたのデータを自在に操ることができます。これらのメソッドと、さらに集計も可能なpivot_table()を適切に使い分けることで、複雑なデータも効率的に分析し、より深い洞察を得ることができるでしょう。