数学基础(下):线性代数核心、微积分基础与时间序列分析
说实话,很多刚入行的朋友问我:「量化研究到底要学多深的数学?」我的回答一直是——你不需要成为数学家,但你必须理解数学在说什么。这一章我们接着聊数学基础的下半部分。线性代数、微积分、时间序列,这三样东西在量化里几乎天天见。
本章核心脉络:矩阵运算 → 特征值分解 → 奇异值分解 → 梯度与优化 → 平稳性与自相关。每一步都是下一环的铺垫。
3.1 线性代数核心:从矩阵到分解
线性代数在量化里到底干嘛用?我个人的理解是——它帮我们把一堆乱七八糟的数据整理成结构化的东西。你想想看,几百只股票的日收益率,不就是一个大矩阵吗?
3.1.1 矩阵运算——量化里的基本操作
矩阵乘法、转置、求逆,这些是基本功。但我要说的是,别小看这些操作。我在做多因子模型时,每天都要算协方差矩阵。一个 N×N 的协方差矩阵,如果 N=500,那就是 25 万个元素。手算?不可能。但用 NumPy 一行代码搞定。
import numpy as np
# 假设 returns 是 (T, N) 的收益率矩阵
cov_matrix = np.cov(returns, rowvar=False)
# 投资组合方差:w^T * Σ * w
portfolio_var = w.T @ cov_matrix @ w
我的习惯:写代码时尽量用 @ 运算符代替 np.dot,可读性更好。另外,求逆矩阵尽量用 np.linalg.solve 而不是 np.linalg.inv,数值稳定性更高。
3.1.2 特征值分解——看懂数据的「骨架」
特征值分解,说白了就是找到一个矩阵的「主方向」。一个方阵 A,如果存在 A·v = λ·v,那么 v 就是特征向量,λ 就是特征值。
在量化里,特征值分解最常见的应用就是主成分分析(PCA)。我记得有一次做风格因子分析,50 多个候选因子,相关性高得吓人。用 PCA 一跑,前 5 个主成分就解释了 80% 的方差。剩下的?全是噪音。
from numpy.linalg import eig
# 计算协方差矩阵的特征值和特征向量
eigenvalues, eigenvectors = eig(cov_matrix)
# 按特征值降序排列
idx = np.argsort(eigenvalues)[::-1]
eigenvalues = eigenvalues[idx]
eigenvectors = eigenvectors[:, idx]
# 前 k 个主成分的方差解释率
explained_ratio = eigenvalues[:k] / eigenvalues.sum()
我曾经踩过的坑:特征值分解只适用于方阵。如果你手里的数据矩阵是 m×n 且 m≠n,别硬上特征值分解。这时候该用 SVD。
3.1.3 奇异值分解(SVD)——更通用的分解利器
SVD 是特征值分解的「升级版」。任何矩阵都能做 SVD,不要求方阵。公式是 A = U·Σ·V^T。其中 U 和 V 是正交矩阵,Σ 是对角矩阵,对角线上的值叫奇异值。
SVD 在量化里的用处太多了。降维、去噪、推荐系统(想想看,这不就是找相似股票吗?)。我个人最喜欢用它来做矩阵补全——比如有些股票某几天停牌,收益率缺失,SVD 可以帮你把缺失值补上。
from numpy.linalg import svd
U, S, Vt = svd(returns_matrix, full_matrices=False)
# 只保留前 k 个奇异值,实现降维去噪
k = 10
S_k = np.diag(S[:k])
U_k = U[:, :k]
Vt_k = Vt[:k, :]
# 重构去噪后的矩阵
returns_denoised = U_k @ S_k @ Vt_k
| 分解方法 | 适用矩阵 | 量化应用 |
|---|---|---|
| 特征值分解 | 方阵(对称矩阵更佳) | PCA、协方差矩阵分析 |
| 奇异值分解 | 任意矩阵 | 降维、去噪、矩阵补全 |
3.2 微积分基础:梯度与优化
微积分在量化里最核心的应用就是优化。说白了,我们做的大部分事情都可以归结为:找一个目标函数,然后让它最小化或最大化。
3.2.1 梯度——函数变化的「指南针」
梯度是一个向量,指向函数增长最快的方向。在优化里,我们沿着梯度的反方向走,就能找到函数的极小值。这就是梯度下降法的核心思想。
你想想看,我们做因子权重优化时,目标函数是夏普比率。梯度告诉我们应该往哪个方向调整权重,夏普比率才能提升。嗯,就是这么回事。
def gradient_descent(grad_func, init_w, lr=0.01, n_iter=100):
w = init_w.copy()
for i in range(n_iter):
grad = grad_func(w)
w = w - lr * grad # 沿梯度反方向更新
return w
我的经验:学习率 lr 别设太大,否则会震荡。我一般从 0.001 开始试,不行再调。另外,用 Adam 或 RMSProp 这类自适应学习率的方法,效果通常比纯 SGD 好。
3.2.2 优化——找到最好的那个参数
量化里的优化问题,大部分是凸优化。凸优化有个好性质:局部最优就是全局最优。你不用担心掉进坑里出不来。
但现实往往不完美。我记得有一次做期权隐含波动率曲面拟合,目标函数非凸,梯度下降跑了好几次,每次结果都不一样。后来换了模拟退火,才找到比较稳定的解。
常用的优化方法对比:
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 梯度下降 | 凸优化、大规模 | 简单、可扩展 | 可能陷入鞍点 |
| 牛顿法 | 小规模、二阶可导 | 收敛快 | 计算 Hessian 矩阵代价高 |
| 拟牛顿法(BFGS) | 中等规模 | 兼顾速度和稳定性 | 内存占用随维度增长 |
3.3 时间序列分析基础:平稳性与自相关
时间序列是量化研究的命根子。股票价格、收益率、波动率,全是时间序列。如果你不懂时间序列,量化研究基本做不了。
3.3.1 平稳性——时间序列的「定海神针」
平稳性是什么意思?简单说,就是一个时间序列的统计性质不随时间变化。均值不变、方差不变、自相关结构不变。
为什么要平稳?因为大多数时间序列模型(ARIMA、GARCH 等)都假设数据是平稳的。如果你拿非平稳数据直接建模,结果就是伪回归——看起来相关,其实全是假的。
我记得有一次帮同事看一个策略,回测曲线漂亮得不行。我一看,用的是价格序列直接回归。我说:「兄弟,价格是非平稳的,你这 R² 再高也是假的。」后来改成收益率序列,策略直接失效了。
避坑指南:千万不要用价格序列做回归或相关性分析。先用 ADF 检验(Augmented Dickey-Fuller test)检查平稳性。p 值大于 0.05 就是不平稳,需要差分或取对数。
from statsmodels.tsa.stattools import adfuller
# ADF 检验
result = adfuller(price_series)
print(f'ADF Statistic: {result[0]}')
print(f'p-value: {result[1]}')
# p-value > 0.05 表示非平稳,需要差分
if result[1] > 0.05:
returns_series = price_series.pct_change().dropna()
3.3.2 自相关——过去和现在的「悄悄话」
自相关衡量的是时间序列和它自己滞后版本的相关性。说白了,就是今天的收益率和昨天的收益率有没有关系。
在量化里,自相关函数(ACF)和偏自相关函数(PACF)是两大神器。ACF 看的是总相关性,PACF 看的是剔除中间变量后的「净」相关性。
我一般用 ACF 和 PACF 图来判断 ARIMA 模型的阶数。ACF 拖尾、PACF 截尾 → AR 模型;ACF 截尾、PACF 拖尾 → MA 模型;都拖尾 → ARMA 模型。
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import matplotlib.pyplot as plt
# 画 ACF 和 PACF 图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6))
plot_acf(returns_series, lags=20, ax=ax1)
plot_pacf(returns_series, lags=20, ax=ax2)
plt.show()
我的习惯:看 ACF 图时,重点关注前几个滞后的值是否超出置信区间(蓝色区域)。如果第 1 阶自相关显著,说明有短期动量或反转效应。这在高频策略里很常见。