1. 这节究竟解决什么实际问题?¶
1.6 统计学基础与假设检验 的具体任务是:用假设检验、置信区间和效应量区分随机波动与可复核的证据。 本节将明确输入数据、计算过程、输出及其在后续研究中的用途。
2. 前置知识¶
会使用百分比和基础代数;建议先完成环境配置。 对公式的理解应包括变量定义、单位、时间索引和适用条件。
3. 数据说明¶
示例优先使用仓库固定的日频复权收盘价;它不是实时行情,也不代表完整市场。 运行前先检查 shape、日期范围、列名与缺失值。数据看起来能画图,不代表它适合回答研究问题。
4. 学习目标与完成标准¶
完成本节后,你应能用自己的话解释 1.6 统计学基础与假设检验 的输入、计算步骤、输出和局限;尤其能说明:用假设检验、置信区间和效应量区分随机波动与可复核的证据。 你还应能独立改动一个参数并解释结果为什么变化,指出至少一个会让结论失真的假设。
5. 核心概念与公式¶
价格表示资产在特定时点的水平,收益率表示两个时点之间的相对变化。多数跨资产比较使用收益率。
所有公式都先说明分子、分母、单位与时间尺度;年化前必须确认数据频率。 看到公式时依次确认:每个符号的单位是什么?它属于哪个时点?分母会不会为零?它是描述性统计量、预测量,还是交易规则?
6. 从零实现¶
原始代码按照“准备输入 → 计算中间量 → 得到结果 → 解释输出”的顺序组织。每个单元应检查变量类型、索引、维度和代表性数值。中间变量用于核对公式实现和定位计算错误。
7. 成熟库实现¶
NumPy/Pandas 帮你算数和对齐索引;统计库帮你估计参数,但不替你解释经济含义。 使用库函数前先阅读参数含义、默认值和返回对象;库输出一个数字,并不说明这个数字适合你的交易假设。
8. 两种实现的差异¶
从零实现便于核对公式、调试和识别隐含假设;成熟库适合在计算逻辑已验证后复用。两种实现依赖相同的数据口径与时点假设,使用库函数不会改变输入数据的质量。
9. 预期结果与检查范围¶
你应看到维度正确的 Series/DataFrame、日期单调递增的索引,以及能支持“用假设检验、置信区间和效应量区分随机波动与可复核的证据。”这一任务的表格或图形。金融日收益率均值通常接近 0;若出现极大的连续收益、空表、全 NaN 或索引错位,应先排查数据和对齐逻辑,而不是立即相信结果。
10. 常见错误与诊断¶
把百分比和小数混用、忘记 dropna、把日频波动率直接叫作年化波动率、把相关性当因果。
诊断顺序:先打印类型与 shape,再看 head()/tail(),接着检查日期和 NaN,最后才比较数值。这样能避免在错误的对象上反复改参数。
11. 研究偏差检查¶
概念演示也要避免事后选择样本或只展示支持结论的时间段。 结果至少应与一个简单基线比较,并明确哪些部分只是教学演示。
12. 三层练习与答案¶
- 基础练习:验证一个中间变量、补全一段小计算,并用一句话解释输出。
- 研究练习:改变窗口、样本区间、约束或标的,记录哪些结论仍成立。
- 开放项目:把本节方法嵌入模块项目,报告基线、失败结果和限制。
题目在 ../exercises/01_financial_concepts/06_statistics_fundamentals_exercises.ipynb;完整推导、可运行参考实现与结果检查在 ../solutions/01_financial_concepts/06_statistics_fundamentals_solutions.ipynb。请先独立作答,再打开答案。
13. 延伸阅读¶
延伸材料:Investments(Bodie, Kane, Marcus)。阅读记录应包括研究假设、数据频率、样本范围和结论适用条件。
14. 下一节¶
下一节是 07_time_series_analysis。本节的概念会成为理解它的输入,而不是孤立的名词。
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
# 生成正态分布数据
mu, sigma = 0, 0.01 # 假设日均收益率为0,日波动率为1%
# 设置随机种子保证可重复性
np.random.seed(42)
s = np.random.normal(mu, sigma, 1000)
# 绘制直方图和概率密度分布图
count, bins, ignored = plt.hist(s, 30, density=True, alpha=0.6, color='g')
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * np.exp( - (bins - mu)**2 / (2 * sigma**2) ), linewidth=2, color='r')
plt.title('Normal Distribution of Returns')
plt.xlabel('Returns')
plt.ylabel('Frequency')
plt.show()
import matplotlib.pyplot as plt
# 1. 设置系统自带的中文字体(这里使用黑体 SimHei)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 如果你想用微软雅黑,可以改成 ['Microsoft YaHei']
# 2. 解决更换字体后,负号(-)显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
肥尾效应 (Fat Tails / Leptokurtic)¶
现实中的金融市场数据并不严格服从正态分布。 它们通常呈现出“尖峰肥尾”的特征。这意味着极端事件(极端收益或极端亏损,即“黑天鹅”事件)发生的概率比正态分布预测的要高得多。
- 偏度 (Skewness): 衡量分布的非对称性。负偏度意味着大概率有小收益,但有小概率发生大额亏损。
- 峰度 (Kurtosis): 衡量分布尾部的厚度。正态分布的峰度是 3(超额峰度为 0)。真实的股票收益率通常具有正的超额峰度(肥尾)。
在量化建模时,忽视肥尾效应会导致对尾部风险(Tail Risk)的严重低估。
# 我们可以用 scipy.stats 来计算偏度和峰度
print(f'偏度 (Skewness): {stats.skew(s):.4f}')
print(f'峰度 (Kurtosis): {stats.kurtosis(s):.4f}')
偏度 (Skewness): 0.1168 峰度 (Kurtosis): 0.0662
2. 假设检验 (Hypothesis Testing) 与 P值 (P-Value)¶
当我们回测一个策略并得到正的历史收益时,我们如何知道这是否只是运气好?这就需要假设检验。
- 原假设 (Null Hypothesis, $H_0$): 通常是我们试图反驳的假设。例如:“这个策略的期望超额收益为0”(策略无效)。
- 备择假设 (Alternative Hypothesis, $H_1$): 我们试图证明的假设。例如:“这个策略的期望超额收益大于0”(策略有效)。
P值 (P-Value)¶
P值是在原假设 ($H_0$) 成立的前提下,观察到当前数据(或更极端数据)的概率。
- P值越小,反驳原假设的证据就越强。
- 通常使用的显著性水平(Significance Level, $\alpha$)是 5% (0.05) 或 1% (0.01)。
- 如果 P值 < $\alpha$,我们拒绝原假设,认为策略“在统计上显著”地赚钱。
注意: P值 < 0.05 并不意味着策略有 95% 的概率赚钱。它只意味着,如果策略实际上不赚钱,你能在回测中看到这么好(或更好)结果的概率不到 5%。这是量化研究中常见的误区。
# T检验示例:检验平均收益率是否显著不为0
# 假设我们有一组策略回测的每日收益率
strategy_returns = np.random.normal(0.0005, 0.01, 252) # 均值为正
t_stat, p_val = stats.ttest_1samp(strategy_returns, 0.0)
print(f'T-statistic: {t_stat:.4f}')
print(f'P-value: {p_val:.4f}')
if p_val < 0.05:
print('拒绝原假设:策略日均收益显著不为0')
else:
print('不能拒绝原假设:无法说明策略赚钱')
T-statistic: 2.5611 P-value: 0.0110 拒绝原假设:策略日均收益显著不为0
3. 多重比较偏差 (Multiple Testing Bias)¶
在量化研究中,我们经常测试成百上千个参数或因子。如果我们使用 5% 的显著性水平,即使所有策略都是随机的(无效的),也有大约 5% 的策略会因为运气而显得“显著有效”。
这就是多重比较偏差,也称为数据挖掘偏差 (Data Mining Bias) 或 P-hacking。为了避免将随机噪音误认为是真实信号,我们需要对显著性水平进行调整,例如使用 Bonferroni 校正或 FDR (False Discovery Rate) 控制。
在后续的机器学习章节中,我们将介绍Purged K-Fold Cross-Validation 作为应对过拟合的重要手段。
4. 相关性:Pearson vs Spearman (Correlation)¶
在上面提到了相关性,量化中最常提到两种相关系数:
- Pearson 相关系数 (皮尔逊): 衡量两个连续变量之间的线性关系强度。它对极值(Outliers)非常敏感。
- Spearman 秩相关系数 (斯皮尔曼): 衡量两个变量的单调关系。它不是直接基于具体数值算,而是先把数值转为排名(Rank),再计算排名的相关性。这使得它对极值非常鲁棒,并且能捕捉非线性的单调关系。
**重要应用:**由于金融收益率具有严重的肥尾且常常有异常极值,在用前文提到的 Alphalens 计算信息系数(IC)时,我们几乎总是使用 Spearman Rank Correlation,而不是普通的 Pearson。
import scipy.stats as stats
import numpy as np
# 模拟包含极端异常值的数据
np.random.seed(42)
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
y = np.array([1.2, 2.1, 2.9, 4.2, 5.1, 5.8, 7.2, 8.1, 9.5, 100.0]) # 最后一个是极值
pearson_corr, _ = stats.pearsonr(x, y)
spearman_corr, _ = stats.spearmanr(x, y)
print(f"Pearson 相关 (受极值影响): {pearson_corr:.4f}")
print(f"Spearman 秩相关 (鲁棒): {spearman_corr:.4f}")
Pearson 相关 (受极值影响): 0.5950 Spearman 秩相关 (鲁棒): 1.0000
5. 线性回归与 Beta ($\beta$) 的估计 (Linear Regression)¶
线性回归是最基础也是运用最广的统计模型,比如计算一只股票相对于大盘的 Beta(即著名的 CAPM 模型中的市场风险暴露)。
公式:$Y = \alpha + \beta X + \epsilon$
- $Y$ 是一只股票的日收益率。
- $X$ 是大盘指数的日收益率。
- $\alpha$ (Alpha) 是截距,代表股票超额(独立于大盘)的收益表现。
- $\beta$ (Beta) 是斜率,代表这只股票相对于大盘变动的敏感度。
普通最小二乘法 (OLS) 是最常用的求解方式。
import statsmodels.api as sm
import matplotlib.pyplot as plt
# 假设 X 是市场收益率,Y 是某只股票收益率
np.random.seed(42)
market_returns = np.random.normal(0.0002, 0.01, 252)
# 假设该股票的真实 Beta 是 1.2,真实 Alpha 是 0.0005
stock_returns = 0.0005 + 1.2 * market_returns + np.random.normal(0, 0.005, 252)
# 使用 statsmodels 进行 OLS 回归
# 注意需要手动加上一列常数项 (1) 以便拟合截距 alpha
X_with_constant = sm.add_constant(market_returns)
model = sm.OLS(stock_returns, X_with_constant)
results = model.fit()
print("回归结果摘要:")
print(f"Alpha (截距): {results.params[0]:.6f} | P-Value: {results.pvalues[0]:.4f}")
print(f"Beta (市场斜率): {results.params[1]:.6f} | P-Value: {results.pvalues[1]:.4f}")
print(f"R-Squared (解释率): {results.rsquared:.4f}")
# 画出拟合散点图和回归线
plt.figure(figsize=(8, 5))
plt.scatter(market_returns, stock_returns, alpha=0.5, label='Daily Returns')
plt.plot(market_returns, results.predict(X_with_constant), color='red', label='OLS Regression Line')
plt.xlabel('Market Returns')
plt.ylabel('Stock Returns')
plt.title('CAPM Beta Estimation')
plt.legend()
plt.show()
回归结果摘要: Alpha (截距): 0.000624 | P-Value: 0.0495 Beta (市场斜率): 1.211484 | P-Value: 0.0000 R-Squared (解释率): 0.8454
练习¶
- 将代码中的
strategy_returns换成真实 AAPL 的日收益率,对其平均收益进行 t 检验,看是否显著大于 0。 - 查阅 Bonferroni 校正,对 100 个随机策略同时进行假设检验,多少个会因为多重比较偏差误判为显著?
- 比较
stats.pearsonr和stats.spearmanr在有异常值时的鲁棒性差异(用 SPY 真实数据)。
下一节 → 07_time_series_analysis.ipynb