Pandas stack 徹底解説: ワイド形式から多重インデックスのロング形式へデータを再構築!


 

データ分析において、データの形状を適切に整えることは非常に重要です。特に、レポートや特定の分析に適したワイド形式のデータ(列数が多く、各列が異なる変数に対応している形式)を、統計モデルへの入力や特定の可視化ツールが求めるロング形式(行数が多く、カテゴリ変数の値が列として並び、その値が別の列に集約されている形式、しばしば多重インデックスを持つ)に変換したい場面は多々あります。そんな時に役立つのが、Pandasの強力なメソッド**stack**です。

この記事では、Pandas stackの基本的な使い方から、データを効率的に多重インデックスのロング形式へ再構築するための応用テクニックまで、徹底的に解説します。


 

Pandas stackってどんなもの?

 

Pandasのstackメソッドは、DataFrameの**列(カラム)のレベルを、新しい行インデックスとして「積み重ねる(stack)」**ための機能です。これは、unstackメソッドの逆の操作であり、ワイド形式のデータを多重インデックスを持つロング形式へと変換します。

 

stackでできること

 

  • 列の行インデックス化: DataFrameの列の一部または全体を新しい行インデックスレベルとして追加し、データをロング形式に変換します。

  • データの再整形: 統計分析や特定の可視化ツールが求める多重インデックス形式のデータに変換します。

  • データ集約の準備: 複数の測定値をまとめて集約する前段階として利用します。


 

なぜstackを選ぶべきか?

 

データ整形の手法は他にもありますが、stackを使うことには以下のようなメリットがあります。

  • MultiIndexとの親和性: 多重インデックスを持つデータへの変換に特化しており、直感的かつ効率的にデータの形状を変更できます。

  • コードの簡潔性: 複雑なループや条件分岐なしに、数行のコードでデータの再構築が可能です。

  • 高速性: Pandasの内部最適化により、大量のデータでも効率的に処理できます。

  • データの可視化や分析準備: ロング形式にすることで、より多くの可視化ライブラリの要件を満たし、複雑な統計モデルへの入力データとして適した形にできます。


 

stackを始めるための準備

 

 

1. ライブラリのインポートとデータの準備

 

stackを使うためには、Pandasライブラリをインポートし、操作したいデータがDataFrame形式で用意されている必要があります。

Python
 
import pandas as pd
import numpy as np

# サンプルデータフレームの作成 (ワイド形式)
# 各地域、各年の売上データと顧客数が列に並んでいる想定
data = {
    'Region': ['East', 'West', 'North', 'South'],
    'Sales_2022': [100, 150, 120, 90],
    'Sales_2023': [110, 160, 130, 95],
    'Customers_2022': [20, 30, 25, 15],
    'Customers_2023': [22, 32, 28, 18]
}
df_wide = pd.DataFrame(data).set_index('Region') # Regionをインデックスに設定

print("--- 元のデータフレーム (ワイド形式) ---")
print(df_wide)
print("\n")

 

stackの基本的な使い方

 

stackメソッドは、どのカラムレベルを行インデックスとして展開するかをlevel引数で指定します。デフォルトでは、最も内側のカラムレベルが展開されます。

 

最小限のサンプルプログラム

 

 

例1: 最も内側のカラムレベルを新しいインデックスに展開 (単一のカラムレベルの場合)

 

df_wideは単一のカラムレベル(Sales_2022など)を持っています。stackを引数なしで呼び出すと、これらのカラム名が新しい行インデックスレベルとして追加されます。

Python
 
# カラムを新しいインデックスレベルに積み重ねる
df_stacked_basic = df_wide.stack()

print("--- カラムをインデックスに展開した結果 (Sales_2022などがインデックスになる) ---")
print(df_stacked_basic)
print("\n")

この結果、Regionの下に元のカラム名が新しいインデックスレベルとして追加された、MultiIndexを持つSeriesが生成されます。

 

例2: 多階層カラムを持つデータで特定のレベルを展開

 

より実践的な例として、年と測定値が多階層カラムになっているデータを考えます。

Python
 
# 多階層カラムを持つデータフレーム
# Regionごと、年ごと、SalesとCustomersのデータ
multi_col_data = {
    ('Sales', 2022): [100, 150, 120, 90],
    ('Sales', 2023): [110, 160, 130, 95],
    ('Customers', 2022): [20, 30, 25, 15],
    ('Customers', 2023): [22, 32, 28, 18]
}
df_multi_col = pd.DataFrame(multi_col_data, index=['East', 'West', 'North', 'South'])

print("--- 多階層カラムを持つデータフレーム ---")
print(df_multi_col)
print("\n")

# 最も内側のカラムレベル(年)をインデックスに積み重ねる
df_stacked_year = df_multi_col.stack(level=1) # level=1はカラムの2番目のレベル(年)

print("--- 年をインデックスに展開した結果 ---")
print(df_stacked_year)
print("\n")

# 次に、Sales/Customersレベルをインデックスに積み重ねる
df_stacked_all = df_stacked_year.stack(level=0) # level=0はカラムの最初のレベル(Sales/Customers)

print("--- Sales/Customersもインデックスに展開した結果 ---")
print(df_stacked_all)
print("\n")

このように、stackを複数回適用することで、多階層カラムのすべてのレベルを行インデックスに変換できます。


 

stackの応用テクニック

 

 

1. dropna引数でNaNを処理

 

デフォルトでは、stackは欠損値(NaN)のある行を削除します。dropna=Falseを設定すると、NaNのある行も保持されます。

Python
 
# 欠損値を含むデータフレーム
df_with_nan = pd.DataFrame({
    'A': [1, np.nan, 3],
    'B': [4, 5, np.nan]
})

print("--- 欠損値を含む元データ ---")
print(df_with_nan)
print("\n")

# dropna=True (デフォルト)
stacked_dropna_true = df_with_nan.stack()
print("--- stack (dropna=True) ---")
print(stacked_dropna_true)
print("\n")

# dropna=False
stacked_dropna_false = df_with_nan.stack(dropna=False)
print("--- stack (dropna=False) ---")
print(stacked_dropna_false)
print("\n")

 

2. unstackとの組み合わせ (pivotの代替として)

 

pivotは特定の条件(indexcolumnsの組み合わせが一意であること)を満たさないとエラーになりますが、groupby().stack().unstack()という組み合わせを使うことで、より柔軟なデータ再構築が可能です。また、stackpivotmeltが苦手な「多重カラムの展開」に非常に強いです。


 

stackunstackpivotmeltの使い分け

 

Pandasにはデータの形状を変換する複数の強力な関数があり、それぞれ最適な利用シーンがあります。

  • stack():

    • 列(カラム)のレベルを、新しい行インデックスとして追加したい場合に特化。

    • 特に多階層カラムを持つワイド形式のデータをロング形式に変換するのに非常に強力です。

    • unstackの逆操作。

  • unstack():

    • 多重行インデックスのレベルを、新しい列として展開したい場合に特化。

    • stackの逆操作。

  • pivot():

    • 特定の列をindex、別の列をcolumnsに、さらに別の列をvaluesにしてデータをワイド形式に再構築したい場合。

    • indexcolumnsの組み合わせが一意である必要がある(重複するとエラー)。集計機能はない。

  • pivot_table():

    • pivotと同様にデータをワイド形式に再構築するが、同時に集計機能を持つ

    • indexcolumnsの組み合わせが重複しても集計してくれるためエラーにならない。

    • 最も柔軟なクロス集計ツール。

  • melt():

    • ワイド形式のデータをロング形式に変換する(stackと似ているが、meltは多重インデックスを生成しない)。

    • 複数の「測定値の列」を「変数名」と「値」の2つの列に「溶解」する。主にシンプルなワイド→ロング変換で使う。

簡単な使い分けの例:

  • stack:

    • df_multi_colのような「測定値がカラム(Sales, Customers)で、その下に年がある」多重カラムのデータを、Region、年、測定値、値のロング形式にしたい。

    • df_wideのような「Sales_2022, Sales_2023, Customers_2022, Customers_2023」といった列を、Region、タイプ(Sales/Customers)、年、値のロング形式にしたい。

  • unstack: df.groupby(['A', 'B'])['Value'].sum().unstack('B') のように、groupby結果のMultiIndexを列にしたい。

  • pivot: 「日付」「商品」「売上」のロング形式から、「日付」を行、「商品」を列、売上を値とする表にしたい(日付・商品の組み合わせはユニーク)。

  • melt: 「年ごとの売上列(Year_2022, Year_2023…)」が並んだ単純なワイド形式のデータから、「年」「売上」というロング形式に変換したい。


 

まとめ

 

この記事では、Pandasでワイド形式のデータを多重インデックスを持つロング形式に効率的に変換する**stack**メソッドについて、その特徴、基本的な使い方、そして他のデータ整形メソッドとの違いや使い分けを徹底的に解説しました。

stackを適切に活用することで、多階層カラムを持つデータの分析や可視化の準備を、簡潔かつ効率的に行えるようになります。特に、分析や機械学習モデルへの入力として、より構造化されたロング形式のデータが必要な場合に、stackはあなたの強力な味方となるでしょう。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座