10、归因结果可视化:瀑布图、热力图、堆积面积图、雷达图
归因分析做完了,数据摆在那,然后呢?
说实话,我见过太多团队把归因结果扔进Excel表格里,然后开会时对着密密麻麻的数字发呆。这太可惜了。你想想看,归因分析的本质是「找问题」,而可视化就是让问题自己「跳出来」。
我个人习惯把归因可视化分成四类:拆解贡献、暴露风险、追踪时序、综合对比。正好对应四种图:瀑布图、热力图、堆积面积图、雷达图。咱们一个一个聊。
10.1 瀑布图:拆解收益的「流水账」
瀑布图是我最常用的图,没有之一。它能把总收益一步步拆开,告诉你每一层贡献了多少、拖累了多少。
我在项目中遇到过一件事:一个策略回测年化20%,但实盘只有8%。用瀑布图一画,发现「交易成本」这一项比回测时预估的高了3倍,直接把收益吃掉了大半。嗯,从那以后,我每次归因必画瀑布图。
核心逻辑: 从总收益出发,依次加上/减去各因子的贡献,最终落到残差或特定因子。
举个例子,假设我们有一个多因子策略,归因结果如下:
| 归因项 | 贡献(bp) |
|---|---|
| 市场择时 | +15 |
| 行业配置 | +8 |
| 选股Alpha | +22 |
| 交易成本 | -5 |
| 其他残差 | +2 |
| 总超额收益 | +42 |
用Python画瀑布图其实不复杂,我习惯用waterfallcharts库或者自己用matplotlib拼一个:
import matplotlib.pyplot as plt
import numpy as np
# 数据准备
labels = ['总收益', '市场择时', '行业配置', '选股Alpha', '交易成本', '残差']
values = [42, 15, 8, 22, -5, 2] # 注意:总收益是最终结果
# 计算累积值
cumulative = np.cumsum([0] + values[:-1])
# 画图
fig, ax = plt.subplots(figsize=(10, 6))
for i in range(len(labels)):
if values[i] >= 0:
ax.bar(i, values[i], bottom=cumulative[i], color='#2ecc71', edgecolor='white')
else:
ax.bar(i, abs(values[i]), bottom=cumulative[i] + values[i], color='#e74c3c', edgecolor='white')
ax.set_xticks(range(len(labels)))
ax.set_xticklabels(labels, rotation=45)
ax.set_ylabel('累计贡献 (bp)')
ax.set_title('策略收益归因瀑布图')
plt.tight_layout()
plt.show()
我的小技巧: 瀑布图的颜色要区分正负贡献。绿色代表正贡献,红色代表负贡献。一眼就能看出「谁在赚钱,谁在亏钱」。
10.2 热力图:暴露风险的「X光片」
热力图适合展示因子暴露的分布情况。说白了,就是看你的策略在哪些风格因子上下注了,下注了多少。
我记得有一次帮朋友诊断一个量化策略,回测曲线漂亮得不像话。我画了一张热力图,发现它在「小市值」因子上的暴露高达3.5个标准差。这哪是Alpha策略?这分明是押注小盘股。后来小盘股崩了,策略也跟着崩了。
热力图的横轴通常是时间(月份/季度),纵轴是因子名称,颜色深浅代表暴露度:
import seaborn as sns
import pandas as pd
import numpy as np
# 模拟数据:12个月 × 6个因子
np.random.seed(42)
data = np.random.randn(12, 6)
df = pd.DataFrame(data,
columns=['动量', '价值', '质量', '成长', '低波', '规模'],
index=[f'2024-{m:02d}' for m in range(1, 13)])
# 画热力图
plt.figure(figsize=(12, 6))
sns.heatmap(df, cmap='RdBu_r', center=0, annot=True, fmt='.2f',
linewidths=0.5, cbar_kws={'label': '因子暴露 (Z-score)'})
plt.title('策略因子暴露热力图(月度)')
plt.tight_layout()
plt.show()
避坑指南: 我曾经犯过一个错——直接用原始暴露值画热力图,结果不同因子的量纲不同,颜色深浅完全没意义。一定要先做标准化(Z-score),让每个因子的均值为0、标准差为1,这样颜色才有可比性。
10.3 堆积面积图:追踪收益的「时间机器」
瀑布图看的是「某个时间点」的拆解,但策略是动态的。堆积面积图能展示收益来源随时间的变化趋势。
我习惯用堆积面积图来回答一个问题:「这个策略的Alpha来源稳定吗?」如果某个因子的贡献面积忽大忽小,说明策略可能过度依赖某个不稳定的信号。
# 模拟数据:24个月的累积收益拆解
months = pd.date_range('2023-01', periods=24, freq='M')
np.random.seed(42)
factor1 = np.cumsum(np.random.randn(24) * 0.5 + 0.3) # 动量
factor2 = np.cumsum(np.random.randn(24) * 0.3 + 0.2) # 价值
factor3 = np.cumsum(np.random.randn(24) * 0.2 + 0.1) # 质量
residual = np.cumsum(np.random.randn(24) * 0.1) # 残差
plt.figure(figsize=(12, 6))
plt.stackplot(months, factor1, factor2, factor3, residual,
labels=['动量因子', '价值因子', '质量因子', '残差'],
colors=['#3498db', '#2ecc71', '#f39c12', '#95a5a6'],
alpha=0.8)
plt.legend(loc='upper left')
plt.title('策略累积收益来源分解(堆积面积图)')
plt.ylabel('累积收益 (bp)')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
注意: 堆积面积图一定要用「累积值」,而不是每期的增量。否则看起来会像一堆杂乱无章的波浪线,根本看不出趋势。
10.4 雷达图:综合对比的「体检报告」
雷达图适合做横向对比。比如,比较两个策略在「收益、风险、夏普、回撤、胜率」五个维度上的表现。
我个人习惯在季度复盘时用雷达图。把当前策略和基准、以及历史最优策略放在一起,一眼就能看出「短板在哪」。
import numpy as np
import matplotlib.pyplot as plt
# 定义指标
categories = ['年化收益', '夏普比率', '最大回撤', '胜率', '信息比率']
N = len(categories)
# 两个策略的数据(注意:最大回撤是负向指标,需要取倒数或正向化)
strategy_a = [0.18, 1.5, -0.12, 0.55, 0.8]
strategy_b = [0.22, 1.8, -0.18, 0.52, 1.2]
# 正向化处理:最大回撤取绝对值后取倒数,再归一化
# 这里简化处理,直接使用原始值(假设已处理好)
values_a = strategy_a
values_b = strategy_b
# 闭合数据
values_a += values_a[:1]
values_b += values_b[:1]
angles = [n / float(N) * 2 * np.pi for n in range(N)]
angles += angles[:1]
# 画图
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))
ax.plot(angles, values_a, 'o-', linewidth=2, label='策略A', color='#3498db')
ax.fill(angles, values_a, alpha=0.25, color='#3498db')
ax.plot(angles, values_b, 'o-', linewidth=2, label='策略B', color='#e74c3c')
ax.fill(angles, values_b, alpha=0.25, color='#e74c3c')
ax.set_xticks(angles[:-1])
ax.set_xticklabels(categories)
ax.set_title('策略综合对比雷达图')
ax.legend(loc='upper right')
plt.tight_layout()
plt.show()
避坑指南: 雷达图最怕「量纲不统一」。比如年化收益是0.18,最大回撤是-0.12,放在一起画,回撤那条线几乎看不见。我的做法是:把所有指标映射到0-1之间,或者用百分位数。这样雷达图才公平。
10.5 四种图的选型指南
你可能会问:这么多图,我到底该用哪个?
嗯,我总结了一个简单的判断逻辑:
- 想拆解「谁贡献了多少」 → 瀑布图
- 想看「因子暴露是否集中」 → 热力图
- 想看「收益来源是否稳定」 → 堆积面积图
- 想对比「多个策略的综合能力」 → 雷达图
当然,实际工作中我经常把几种图组合使用。比如先画瀑布图看整体拆解,再用热力图深挖某个因子的暴露细节。你想想看,这样是不是比看一堆数字直观多了?
核心要点: 可视化不是为了好看,是为了「发现问题」。如果一张图画完,你没有任何新的发现,那这张图就是废的。