Pandas stack 徹底解説: ワイド形式から多重インデックスのロング形式へデータを再構築!
データ分析において、データの形状を適切に整えることは非常に重要です。特に、レポートや特定の分析に適したワイド形式のデータ(列数が多く、各列が異なる変数に対応している形式)を、統計モデルへの入力や特定の可視化ツールが求めるロング形式(行数が多く、カテゴリ変数の値が列として並び、その値が別の列に集約されている形式、しばしば多重インデックスを持つ)に変換したい場面は多々あります。そんな時に役立つのが、Pandasの強力なメソッド**stack
**です。
この記事では、Pandas stack
の基本的な使い方から、データを効率的に多重インデックスのロング形式へ再構築するための応用テクニックまで、徹底的に解説します。
Pandas stack
ってどんなもの?
Pandasのstack
メソッドは、DataFrameの**列(カラム)のレベルを、新しい行インデックスとして「積み重ねる(stack)」**ための機能です。これは、unstack
メソッドの逆の操作であり、ワイド形式のデータを多重インデックスを持つロング形式へと変換します。
stack
でできること
列の行インデックス化: DataFrameの列の一部または全体を新しい行インデックスレベルとして追加し、データをロング形式に変換します。
データの再整形: 統計分析や特定の可視化ツールが求める多重インデックス形式のデータに変換します。
データ集約の準備: 複数の測定値をまとめて集約する前段階として利用します。
なぜstack
を選ぶべきか?
データ整形の手法は他にもありますが、stack
を使うことには以下のようなメリットがあります。
MultiIndexとの親和性: 多重インデックスを持つデータへの変換に特化しており、直感的かつ効率的にデータの形状を変更できます。
コードの簡潔性: 複雑なループや条件分岐なしに、数行のコードでデータの再構築が可能です。
高速性: Pandasの内部最適化により、大量のデータでも効率的に処理できます。
データの可視化や分析準備: ロング形式にすることで、より多くの可視化ライブラリの要件を満たし、複雑な統計モデルへの入力データとして適した形にできます。
stack
を始めるための準備
1. ライブラリのインポートとデータの準備
stack
を使うためには、Pandasライブラリをインポートし、操作したいデータがDataFrame形式で用意されている必要があります。
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
を引数なしで呼び出すと、これらのカラム名が新しい行インデックスレベルとして追加されます。
# カラムを新しいインデックスレベルに積み重ねる
df_stacked_basic = df_wide.stack()
print("--- カラムをインデックスに展開した結果 (Sales_2022などがインデックスになる) ---")
print(df_stacked_basic)
print("\n")
この結果、Region
の下に元のカラム名が新しいインデックスレベルとして追加された、MultiIndexを持つSeriesが生成されます。
例2: 多階層カラムを持つデータで特定のレベルを展開
より実践的な例として、年と測定値が多階層カラムになっているデータを考えます。
# 多階層カラムを持つデータフレーム
# 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
のある行も保持されます。
# 欠損値を含むデータフレーム
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
は特定の条件(index
とcolumns
の組み合わせが一意であること)を満たさないとエラーになりますが、groupby().stack().unstack()
という組み合わせを使うことで、より柔軟なデータ再構築が可能です。また、stack
はpivot
とmelt
が苦手な「多重カラムの展開」に非常に強いです。
stack
とunstack
、pivot
、melt
の使い分け
Pandasにはデータの形状を変換する複数の強力な関数があり、それぞれ最適な利用シーンがあります。
stack()
:列(カラム)のレベルを、新しい行インデックスとして追加したい場合に特化。
特に多階層カラムを持つワイド形式のデータをロング形式に変換するのに非常に強力です。
unstack
の逆操作。
unstack()
:多重行インデックスのレベルを、新しい列として展開したい場合に特化。
stack
の逆操作。
pivot()
:特定の列を
index
、別の列をcolumns
に、さらに別の列をvalues
にしてデータをワイド形式に再構築したい場合。index
とcolumns
の組み合わせが一意である必要がある(重複するとエラー)。集計機能はない。
pivot_table()
:pivot
と同様にデータをワイド形式に再構築するが、同時に集計機能を持つ。index
とcolumns
の組み合わせが重複しても集計してくれるためエラーにならない。最も柔軟なクロス集計ツール。
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爆速講座