🎯 学习目标

  • 掌握Pandas的groupby分组聚合操作
  • 学会使用数据透视表进行多维度分析
  • 掌握各种聚合函数的应用场景
  • 了解金融数据分析中的典型聚合操作
数据透视与聚合

数据透视与聚合

数据聚合是将原始数据转换为更高层次汇总数据的过程,是量化分析中的核心技能。 通过分组、透视和聚合,我们可以从不同维度深入分析市场特征。

📊 GroupBy分组聚合

基本分组操作

import pandas as pd
import numpy as np

# 创建示例数据
data = {
    'symbol': ['AAPL', 'MSFT', 'GOOG', 'AAPL', 'MSFT', 'GOOG'] * 100,
    'date': pd.date_range('2024-01-01', periods=600),
    'price': np.random.randn(600) * 10 + 100,
    'volume': np.random.randint(1000000, 10000000, 600)
}
df = pd.DataFrame(data)

# 单列分组
symbol_groups = df.groupby('symbol')
print(symbol_groups.size())

# 多列分组
date_symbol_groups = df.groupby(['symbol', df['date'].dt.month])
print(date_symbol_groups.size())

# 计算分组统计
print(symbol_groups['price'].mean())
print(symbol_groups['volume'].sum())

聚合函数

# 内置聚合函数
agg_result = df.groupby('symbol').agg({
    'price': ['mean', 'std', 'min', 'max'],
    'volume': ['sum', 'mean']
})

# 自定义聚合函数
def range_func(x):
    return x.max() - x.min()

symbol_groups['price'].agg(range_func)

# 多种聚合方式
result = df.groupby('symbol').agg({
    'price': {
        'avg_price': 'mean',
        'price_volatility': 'std',
        'max_price': 'max'
    }
})

分组操作

# 分组后过滤
filtered = df.groupby('symbol').filter(
    lambda x: len(x) > 100
)

# 分组后转换
df['price_zscore'] = df.groupby('symbol')['price'].transform(
    lambda x: (x - x.mean()) / x.std()
)

# 分组后应用
result = df.groupby('symbol').apply(
    lambda x: x.sort_values('date', ascending=False).head(10)
)

# 分组迭代
for symbol, group in symbol_groups:
    print(f"Symbol: {symbol}, Shape: {group.shape}")

🔄 数据透视表

基本透视表

# 创建透视表
pivot = pd.pivot_table(
    df,
    values='price',
    index='symbol',
    columns=df['date'].dt.month,
    aggfunc='mean'
)

# 多值透视表
pivot_multi = pd.pivot_table(
    df,
    values=['price', 'volume'],
    index='symbol',
    columns=df['date'].dt.month,
    aggfunc={'price': 'mean', 'volume': 'sum'}
)

# 添加汇总
pivot_with_totals = pd.pivot_table(
    df,
    values='price',
    index='symbol',
    columns=df['date'].dt.month,
    aggfunc='mean',
    margins=True,
    margins_name='总计'
)

交叉表

# 创建交叉表
df['price_range'] = pd.cut(df['price'], bins=5, labels=['极低', '低', '中', '高', '极高'])

crosstab = pd.crosstab(
    index=df['symbol'],
    columns=df['price_range'],
    margins=True
)

# 百分比交叉表
crosstab_pct = pd.crosstab(
    index=df['symbol'],
    columns=df['price_range'],
    normalize='index'
)

📈 金融数据分析应用

股票收益率聚合

# 计算日收益率
df['returns'] = df.groupby('symbol')['price'].pct_change()

# 按股票汇总收益率
stock_returns = df.groupby('symbol')['returns'].agg({
    'annual_return': lambda x: (1 + x).prod() - 1,
    'daily_mean': 'mean',
    'daily_std': 'std',
    'sharpe_ratio': lambda x: x.mean() / x.std() * np.sqrt(252)
})

# 按时间段聚合
monthly_returns = df.set_index('date').groupby([
    pd.Grouper(freq='M'),  # 按月
    'symbol'
])['returns'].agg(['mean', 'std'])

技术指标聚合

# 移动平均
df['ma5'] = df.groupby('symbol')['price'].transform(
    lambda x: x.rolling(5).mean()
)

df['ma20'] = df.groupby('symbol')['price'].transform(
    lambda x: x.rolling(20).mean()
)

# 波动率
df['volatility'] = df.groupby('symbol')['returns'].transform(
    lambda x: x.rolling(20).std()
)

# 相对强弱指标
def calculate_rsi(returns, periods=14):
    delta = returns.diff()
    gain = delta.where(delta > 0, 0)
    loss = -delta.where(delta < 0, 0)
    avg_gain = gain.rolling(periods).mean()
    avg_loss = loss.rolling(periods).mean()
    rs = avg_gain / avg_loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

df['rsi'] = df.groupby('symbol')['price'].apply(calculate_rsi)

行业分析聚合

# 按行业分组
df['industry'] = df['symbol'].map({
    'AAPL': 'Technology',
    'MSFT': 'Technology',
    'GOOG': 'Technology'
})

industry_stats = df.groupby('industry').agg({
    'price': ['mean', 'std', 'count'],
    'volume': ['sum', 'mean'],
    'returns': ['mean', 'std']
})

# 行业间比较
industry_comparison = pd.pivot_table(
    df,
    values='returns',
    index=df['date'].dt.month,
    columns='industry',
    aggfunc='mean'
)

🔧 高级聚合技巧

时间窗口聚合

# 重采样(降采样)
daily = df.set_index('date')
weekly = daily.groupby('symbol').resample('W').agg({
    'price': ['first', 'last', 'mean'],
    'volume': 'sum'
})

# 升采样
hourly = daily.groupby('symbol').resample('H').asfreq()

# 滚动窗口聚合
df['rolling_mean'] = df.groupby('symbol')['price'].transform(
    lambda x: x.rolling(window=20).mean()
)

df['rolling_std'] = df.groupby('symbol')['price'].transform(
    lambda x: x.rolling(window=20).std()
)

多级索引聚合

# 创建多级索引
multi_index_df = df.set_index(['symbol', 'date'])

# 在多级索引上聚合
symbol_monthly = multi_index_df.groupby([
    pd.Grouper(level='symbol'),
    pd.Grouper(level='date', freq='M')
]).agg({
    'price': 'mean',
    'volume': 'sum'
})

# 多级聚合
result = df.groupby([
    'symbol',
    pd.Grouper(key='date', freq='M'),
    'industry'
]).agg({
    'price': ['mean', 'std'],
    'volume': 'sum'
})
💡
最佳实践

1. 合理选择分组粒度,避免过度细分
2. 使用命名聚合提高代码可读性
3. 注意聚合后的数据结构变化
4. 大数据集使用agg而非apply提高性能
5. 理解不同聚合函数的金融含义

📝 本节小结

  • • 掌握了GroupBy分组聚合操作
  • • 学会了数据透视表的使用方法
  • • 理解了各种聚合函数的应用
  • • 掌握了金融数据分析中的聚合技巧