Pandas df.stack() 関数

Pandas 常用函数Pandas よく使う関数


df.stack()DataFrame のメンバーメソッドであり、列インデックスを行インデックスに変換するために使用されます。これはワイド形式データの列を「スタック」して行にし、階層化インデックスを持つ Series または DataFrame を生成します。

これはデータ再形成における重要な操作であり、通常はunstack()と組み合わせて使用することで、データの相互変換を実現します。

単語の説明: stackは「スタック、積み重ね」を意味し、ここでは列データを「スタック」して行にし、ワイドテーブルをロングテーブルに変換することを指します。


基本構文とパラメータ

df.stack()DataFrame のインスタンスメソッドであり、ドット演算子によって呼び出されます。

構文形式

DataFrame.stack(level=-1, dropna=True)

パラメータの説明

  • パラメータ: level
    • 型: int、str、int リスト、または str リスト。
    • 説明: スタックするレベルを指定します。複数層インデックスの場合、具体的なレベル番号(0から始まる)またはレベル名を指定できます。デフォルトは -1 で、最内層を表します。
  • パラメータ: dropna
    • 型: ブール値。
    • 説明: 結果内のすべてが NaN の行を削除するかどうか。デフォルトは True で、すべての値が NaN の行を削除します。

関数の説明

  • 戻り値: Series または DataFrame を返します。元の DataFrame でスタックされる列が1つだけの場合は Series を返し、それ以外の場合は DataFrame を返します。
  • 効果: 列インデックスを行インデックスに変換し、より長いデータ形式を生成します。スタック後のデータは「ロング形式」であり、統計分析や可視化に適しています。

例

単純なものから複雑なものまでの一連の例を通して、df.stack()の使い方を徹底的に習得しましょう。

例1:基本的な使い方 - 列を行に変換

例

import pandas as pd
import numpy as np

# 1. ワイド形式のデータを作成(四半期ごとに1列)
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'Q1': [100, 150, 200],
    'Q2': [120, 160, 210],
    'Q3': [130, 170, 220]
})

print("=== 元のワイド形式データ ===")
print(df)
print(f"列名: {df.columns.tolist()}")

# 2. df.stack() を使用して列を行に変換
stacked = df.stack()
print("n=== df.stack() 結果 ===")
print(stacked)
print(f"n型: {type(stacked)}")

# 3. 結果をDataFrameに変換して確認
print("n=== DataFrameに変換 ===")
stacked_df = stacked.reset_index()
stacked_df.columns = ['name', 'quarter', 'sales']
print(stacked_df)

実行結果の予想:

=== 原始宽格式数据 ===
      name  Q1   Q2   Q3
0    Alice  100  120  130
1      Bob  150  160  170
2  Charlie  'Q2', 'Q3'], columns=['name', 'quarter', 'sales']
...

コードの解説:

  1. 元のデータはワイド形式で、Q1、Q2、Q3 は3つの四半期データの列です。
  2. stack()Q1、Q2、Q3 の3列を「スタック」して行にします。
  3. 結果は Series 型で、2層のインデックスを含みます:外側は元の行インデックス、内側は元の列名(四半期)です。
  4. スタック後、データは「ロング形式」になり、各行には1つの四半期の値だけが含まれます。

例2:複数層の列インデックスのスタック

DataFrame に複数層の列インデックスがある場合、スタックするレベルを指定できます。

例

import pandas as pd
import numpy as np

# 1. 複数層の列インデックスを持つデータを作成
# 外側:製品タイプ(Electronics、Furniture)
# 内側:四半期(Q1、Q2)
df = pd.DataFrame(
    [[100, 110, 200, 210], [150, 160, 180, 190]],
    index=['Store_A', 'Store_B'],
    columns=pd.MultiIndex.from_tuples([
        ('Electronics', 'Q1'), ('Electronics', 'Q2'),
        ('Furniture', 'Q1'), ('Furniture', 'Q2')
    ], names=['Product', 'Quarter'])
)

print("=== 元のデータ(複数層の列インデックス)===")
print(df)
print(f"列インデックスのレベル: {df.columns.names}")

# 2. 内側の列をスタック(デフォルト、level=-1)
print("n=== 内側の列をスタック (level=-1) ===")
stacked_inner = df.stack()
print(stacked_inner)

# 3. 外側の列をスタック
print("n=== 外側の列をスタック (level=0) ===")
stacked_outer = df.stack(level=0)
print(stacked_outer)

# 4. すべての列をスタック(より長い形式を生成)
print("n=== すべての列をスタック ===")
stacked_all = df.stack(level=[0, 1])
print(stacked_all)

実行結果の予想:

=== 原始数据(多层列索引)===
Product      Electronics   Furniture
Quarter              Q1   Q2      Q1   Q
...

コードの解説:

  • 複数層の列インデックスを持つ DataFrame では、列名はタプル形式です:(Product, Quarter)。
  • level=-1(デフォルト)最内層、つまり Quarter 層をスタックし、結果は Product を列として保持します。
  • level=0外側の層、つまり Product 層をスタックし、結果は Quarter を列として保持します。
  • この柔軟性により、分析のニーズに応じてスタックするレベルを選択できます。

例3:欠損値の処理

使用dropnaパラメータで欠損値の処理方法を制御します。

例

import pandas as pd
import numpy as np

# 1. 欠損値を含むデータを作成
df = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'Math': [100, np.nan],
    'English': [90, 85],
    'Science': [np.nan, 95]
})

print("=== 元のデータ(欠損値を含む)===")
print(df)

# 2. dropna=True(デフォルト)、すべてがNaNの行を削除
print("n=== dropna=True(デフォルト)===")
stacked_drop = df.stack(dropna=True)
print(stacked_drop)

# 3. dropna=False、NaN値を保持
print("n=== dropna=False ===")
stacked_keep = df.stack(dropna=False)
print(stacked_keep)

# 4. 実際の応用:スタック結果を分析可能なロング形式に整理
print("n=== ロング形式のDataFrameに整理 ===")
result = df.set_index('name').stack().reset_index()
result.columns = ['name', 'subject', 'score']
print(result)

# 5. 欠損値を削除
result_clean = result.dropna()
print("n=== 欠損値の削除後 ===")
print(result_clean)

実行結果の予想:

=== 原始数据(包含缺失值)===
   name  Math  English  Science
0  Alice  100.0     90.0      NaN
1    Bob    NaN    85.0     95.0
2=== 堆叠内层列 (level=-1) ===
Store_A  Electronics  Q1    100
                  Q2    110
         Furniture   Q1    200
                  Q2    210
Store_B  Electronics  Q1    150
 ...

コードの解説:

  • dropna=True(デフォルト)すべての値が NaN の行を削除します。
  • データ分析では、通常は元のデータを保持し、必要に応じて欠損値を削除します。
  • スタック後に使用reset_index()すると、階層インデックスを通常の列に変換でき、後続の処理が容易になります。

例4:stack と unstack の組み合わせ使用

stack()とunstack()は互いに逆の操作であり、組み合わせて使用することで、データの柔軟な再形成を実現できます。

例

import pandas as pd

# 1. 初期データを作成
df = pd.DataFrame({
    'product': ['A', 'B', 'C'],
    'North': [100, 150, 200],
    'South': [180, 170, 160],
    'East': [190, 200, 210]
})

print("=== 元のデータ ===")
print(df)

# 2. unstack を使用して地区を列に変換(先に複数層インデックスに変換)
df_indexed = df.set_index('product')
print("n=== インデックス設定後 ===")
print(df_indexed)

# 3. stack を使用して列を行に変換(stackはunstackの逆操作)
print("n=== unstack + stack 往復 ===")
# 最初に unstack
unstacked = df_indexed.unstack()
print("unstack 結果:")
print(unstacked)
# 次に stack で戻す
restacked = unstacked.stack()
print("nstack で元に戻す:")
print(restacked)

# 4. 完全な例:複数層インデックスを作成してから変換
print("n=== 複数層インデックスの変換 ===")
# 複数層インデックスのDataFrameを作成
multi_df = pd.DataFrame(
    [[100, 110], [150, 160]],
    index=pd.MultiIndex.from_tuples([('A', '2023'), ('B', '2023')], names=['product', 'year']),
    columns=['North', 'South']
)
print("元の複数層インデックスデータ:")
print(multi_df)

# unstack year
print("nunstack year:")
print(multi_df.unstack(level='year'))

# unstack columns
print("nunstack columns (列に変換):")
print(multi_df.unstack(level='columns'))

実行結果の予想:

=== unstack + stack 往返 ===
unstack 结果:
       product
North  A          100
       B          150
       C          200
South  A          180
       B          170
...

コードの解説:

  • stack()列インデックスを行インデックスに変換し、ワイドテーブルをロングテーブルに変換します。
  • unstack()行インデックスを列インデックスに変換し、ロングテーブルをワイドテーブルに変換します。
  • 両者を組み合わせて使用することで、データを任意の形状に変換できます。
  • データ分析において、これら2つの操作の互いに逆の関係を理解することは非常に重要です。

ヒント: stack()とunstack()はデータ再形成の中核的なツールです。stack()列を「スタック」して行にします(ワイドからロングへ)、unstack()行を「展開」して列にします(ロングからワイドへ)。

Pandas 常用函数Pandas よく使う関数

その他の拡張