Pandas 樞紐分析表

樞紐分析表(Pivot Table)是一種強大的資料摘要工具,可以將資料重新組織成易於分析的格式。類似 Excel 中的樞紐分析表功能。

基本概念

樞紐分析表將資料從「長格式」轉換成「寬格式」,並進行聚合計算。

pivot_table()

基本用法

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'city': ['Taipei', 'Tokyo', 'Taipei', 'Tokyo', 'Taipei', 'Tokyo'],
    'year': [2023, 2023, 2024, 2024, 2023, 2024],
    'sales': [100, 200, 150, 250, 120, 280]
})

# 建立樞紐分析表
pivot = pd.pivot_table(df, values='sales', index='city', columns='year')
print(pivot)
year      2023   2024
city                 
Taipei   110.0  150.0
Tokyo    200.0  265.0

預設會使用 mean 作為聚合函數。

指定聚合函數

# 使用總和
pivot = pd.pivot_table(df, values='sales', index='city', columns='year', aggfunc='sum')
print(pivot)
year    2023  2024
city              
Taipei   220   150
Tokyo    200   530

多種聚合函數

pivot = pd.pivot_table(df, values='sales', index='city', columns='year', 
                       aggfunc=['sum', 'mean', 'count'])
print(pivot)

多個值欄位

df = pd.DataFrame({
    'city': ['Taipei', 'Tokyo', 'Taipei', 'Tokyo'],
    'year': [2023, 2023, 2024, 2024],
    'sales': [100, 200, 150, 250],
    'profit': [10, 20, 15, 25]
})

pivot = pd.pivot_table(df, values=['sales', 'profit'], index='city', columns='year')
print(pivot)

多層索引和欄位

df = pd.DataFrame({
    'city': ['Taipei', 'Taipei', 'Tokyo', 'Tokyo'] * 2,
    'category': ['A', 'B', 'A', 'B'] * 2,
    'year': [2023] * 4 + [2024] * 4,
    'sales': [100, 150, 200, 180, 120, 160, 220, 190]
})

pivot = pd.pivot_table(df, values='sales', 
                       index=['city', 'category'], 
                       columns='year')
print(pivot)

處理缺失值

# 用 0 填補缺失值
pivot = pd.pivot_table(df, values='sales', index='city', columns='year', fill_value=0)

加上邊際總計

pivot = pd.pivot_table(df, values='sales', index='city', columns='year', 
                       aggfunc='sum', margins=True, margins_name='Total')
print(pivot)
year     2023  2024  Total
city                      
Taipei    220   150    370
Tokyo     200   530    730
Total     420   680   1100

pivot()

pivot()pivot_table() 的簡化版,不進行聚合:

df = pd.DataFrame({
    'city': ['Taipei', 'Tokyo', 'Seoul'],
    'year': [2023, 2023, 2023],
    'sales': [100, 200, 150]
})

# 每個 city-year 組合只能有一個值
pivot = df.pivot(index='city', columns='year', values='sales')

如果有重複的組合,pivot() 會報錯,此時應使用 pivot_table()

反向操作:melt()

將「寬格式」轉回「長格式」:

# 原始寬格式
df_wide = pd.DataFrame({
    'city': ['Taipei', 'Tokyo'],
    '2023': [100, 200],
    '2024': [150, 250]
})

# 轉成長格式
df_long = df_wide.melt(id_vars='city', var_name='year', value_name='sales')
print(df_long)
     city  year  sales
0  Taipei  2023    100
1   Tokyo  2023    200
2  Taipei  2024    150
3   Tokyo  2024    250

crosstab():交叉表

crosstab() 專門用於計算交叉頻率表:

df = pd.DataFrame({
    'gender': ['M', 'F', 'M', 'F', 'M'],
    'city': ['Taipei', 'Tokyo', 'Taipei', 'Taipei', 'Tokyo']
})

# 計算頻率
ct = pd.crosstab(df['gender'], df['city'])
print(ct)
city    Taipei  Tokyo
gender               
F            1      1
M            2      1
# 顯示百分比
ct = pd.crosstab(df['gender'], df['city'], normalize='all')

# 按列百分比
ct = pd.crosstab(df['gender'], df['city'], normalize='columns')

# 按行百分比
ct = pd.crosstab(df['gender'], df['city'], normalize='index')

# 加上邊際總計
ct = pd.crosstab(df['gender'], df['city'], margins=True)

實際應用

銷售報表

df = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=12, freq='M'),
    'product': ['A', 'B', 'A', 'B'] * 3,
    'region': ['North', 'North', 'South', 'South'] * 3,
    'sales': [100, 150, 120, 180, 130, 160, 140, 190, 150, 170, 160, 200]
})

# 按產品和區域的月銷售報表
df['month'] = df['date'].dt.month
pivot = pd.pivot_table(df, values='sales', 
                       index=['product', 'region'], 
                       columns='month',
                       aggfunc='sum',
                       fill_value=0)

學生成績表

df = pd.DataFrame({
    'student': ['Alice', 'Bob', 'Alice', 'Bob', 'Alice', 'Bob'],
    'subject': ['Math', 'Math', 'English', 'English', 'Science', 'Science'],
    'score': [90, 85, 88, 92, 95, 78]
})

# 轉成成績表格式
pivot = df.pivot(index='student', columns='subject', values='score')
print(pivot)
subject  English  Math  Science
student                        
Alice         88    90       95
Bob           92    85       78

計算轉換率

df = pd.DataFrame({
    'source': ['Google', 'Facebook', 'Google', 'Facebook'] * 2,
    'action': ['view', 'view', 'click', 'click', 'view', 'click', 'view', 'click'],
    'count': [1000, 800, 100, 50, 1200, 120, 900, 60]
})

pivot = pd.pivot_table(df, values='count', index='source', columns='action', aggfunc='sum')
pivot['conversion_rate'] = pivot['click'] / pivot['view']
print(pivot)