06 线性模型选择与正则化

核心问题:普通最小二乘法够用吗?

在前几章我们学习了线性回归模型,使用最小二乘法 (OLS) 来拟合:

\[ Y = \beta_0 + \beta_1 X_1 + \cdots + \beta_p X_p + \epsilon \]

OLS 有两个痛点

  • 预测精度:当 \(p\) 接近或超过 \(n\) 时,OLS 方差爆炸,过拟合严重
  • 模型可解释性:当预测变量很多时,哪些才是真正重要的?

本章介绍三类替代方法来解决这些问题。

OLS 在高维数据上到底会怎样崩溃?

让我们用一个非常具体的场景来理解 OLS 的问题。

假设你有 200 家 A 股上市公司的季度财务数据,要预测下季度 ROE,候选解释变量有 50 个财务比率。

  • 维度灾难\(p = 50\) 时,OLS 已经开始挣扎;如果再加入交互项和滞后项,\(p\) 轻松超过 \(n\)
  • 系数爆炸:当 \(p \geq n\)\(\mathbf{X}^T \mathbf{X}\) 不可逆,OLS 根本无法计算
  • 虚假完美拟合:当 \(p = n\),OLS 可以完美通过每个样本点(\(R^2 = 1\)),但对新数据的预测毫无价值
  • 共线性放大噪声:资产负债率、权益乘数、杠杆率等高度相关的变量让系数估计变得极度不稳定

这不是理论上的担忧——在 A 股量化研究中,研究者经常面对\(p \approx n\) 甚至 \(p > n\) 的局面。

为什么模型选择在经济金融里格外重要?

在经济金融任务中,’变量太多、样本不够、变量彼此高度相关’几乎是常态。

  • 财务报表里同时有盈利、周转、杠杆、现金流等几十类指标,它们往往互相纠缠
  • 宏观预测常常只有几十期季度数据,却想利用上百个先行指标
  • 风控和投研不仅要预测准,还要解释’为什么是这些变量’而不是另外一些
  • 变量选错的代价很真实:错误授信、错误选股、错误政策判断

因此,模型选择不是’美化回归’的小技巧,而是经济决策质量的一部分。

一个来自量化投资的真实教训

2018-2019 年,A 股量化界流行一种做法:堆因子

研究者把上百个技术指标和财务因子全部放进线性模型,样本内回测表现惊人——但一旦用到实盘,收益迅速衰减。

这个现象的统计学解释正是本章的核心问题:

  • 因子之间高度相关(如市值、流通市值、总资产),模型挑不出谁真正重要
  • OLS 的系数在不同回测区间剧烈波动,缺乏稳定性
  • 变量太多导致过拟合:模型记住了噪声而非信号

本章介绍的方法——子集选择、正则化、降维——正是量化界后来用来解决这一问题的三条主线。

本章学习路线图

为了系统地解决 OLS 的问题,本章按照从简单到复杂的逻辑展开:

  1. 子集选择(最直接):从 \(p\) 个变量中选出最好的 \(k\)
  2. 收缩方法(最核心):保留所有变量但把系数’压小’,包括岭回归与 Lasso
  3. 降维方法(另一条路):把 \(p\) 个变量投影到少数几个方向

每类方法我们都会讲清楚三件事:

  • 数学原理:它在优化什么目标函数?
  • 算法实现:用 Python/sklearn 怎么做?
  • 金融应用:在哪些实际问题里最有用?

最后我们会给出一个方法选择决策框架,帮助你面对具体问题时快速判断该用哪种方法。

三类替代方法的全景图

线性模型改进方法全景图 展示子集选择、收缩方法、降维三大类方法的关系 改进 OLS 的三条技术路线 OLS 的局限性 子集选择 最优子集选择 前向/后向逐步选择 保留变量的子集 收缩方法 岭回归 (Ridge) 套索回归 (Lasso) 系数向零收缩 降维方法 主成分回归 (PCR) 偏最小二乘 (PLS) 投影到低维空间 共同目标:降低方差、提升泛化能力

最优子集选择:它其实是在做一场’全模型搜索’

最优子集选择的直觉非常朴素:既然不知道哪几个变量最好,那就把所有候选组合都拿来比赛。

  • 先按模型大小分组:1 个变量一组,2 个变量一组,直到 \(p\) 个变量一组
  • 在每个组里选出表现最好的’组冠军’
  • 再让这些’组冠军’用 BIC、调整 \(R^2\)\(C_p\) 或交叉验证做总决赛
  • 最终问题不再是’哪个变量最好’,而是’哪个复杂度水平下的最佳模型最好’

这种思路的优点是彻底、透明、容易解释,特别适合课堂上讲清楚’模型选择到底在选什么’。

最优子集选择的算法细节:每一步都在比较什么?

我们可以把算法拆成四个非常具体的动作:

  1. \(M_0\) 为零模型,只保留截距项,作为比较基准
  2. 对每个 \(k = 1, 2, \ldots, p\),枚举全部 \(\binom{p}{k}\) 个候选模型
  3. 在固定的 \(k\) 下,只比较’同样复杂度’的模型,选出 RSS 最小的那个 \(M_k\)
  4. 最后再在 \(M_0, M_1, \ldots, M_p\) 之间引入复杂度惩罚,选最终模型

最容易误解的地方:如果只看训练 RSS 或训练 \(R^2\),答案几乎一定是’变量越多越好’;真正的模型选择必须显式惩罚复杂度。

最优子集选择的计算瓶颈:\(2^p\) 的诅咒

最优子集选择虽然在理论上’完美’,但有一个致命的实际问题——计算量随变量数呈指数增长

变量数 \(p\) 候选模型数 \(2^p\) 比较规模
10 1,024 几秒钟
20 ~100万 几分钟到几小时
30 ~10亿 数天
50 ~\(10^{15}\) 不可能

\(p > 30\) 时,穷举搜索在任何现有计算机上都不现实。

这就是为什么需要逐步选择作为替代——它把计算复杂度从 \(2^p\) 降到了 \(O(p^2)\),虽然不保证找到全局最优,但在工程上可行。

现代替代方案:混合整数优化 (Mixed-Integer Optimization, MIO) 近年来让最优子集选择能够处理 \(p \approx 1000\) 的问题,但仍需专门的优化器(如 Gurobi),不是 sklearn 开箱即用的。

最优子集选择最适合哪类任务?

最优子集选择最适合’变量数量不算太大,但解释要求很高’的任务。

  • 候选变量数量中等,例如 10 到 20 个核心财务指标
  • 每个变量都有明确业务含义,老师、管理层或监管者希望逐个解释
  • 采集变量本身有成本,希望留下最少但最有用的一组指标
  • 样本量不算巨大,希望避免把模型做得太花哨

在经济金融里,它常见于授信评分卡、企业财务诊断、少量因子的选股模型,以及地方产业风险监测等需要’讲得明白’的场景。

案例:杜邦分析法预测 ROE

我们使用 A 股上市公司财务数据,用杜邦分析核心因子预测 ROE(净资产收益率)。

杜邦恒等式将 ROE 分解为三大驱动力:

\[ \text{ROE} = \underbrace{\text{净利率}}_{\text{盈利能力}} \times \underbrace{\text{资产周转率}}_{\text{运营效率}} \times \underbrace{\text{权益乘数}}_{\text{财务杠杆}} \]

我们构造 6 个候选财务指标,用最优子集选择来找出哪些因子组合对 ROE 的解释力最强。

为什么杜邦分析特别适合讲模型选择?

杜邦分析非常适合做教学案例,因为它兼具’经济学含义清晰’和’统计上存在竞争关系’这两个特征。

  • 净利率、周转率、杠杆率都能解释 ROE,但解释角度不同
  • 某些指标彼此相关,例如高杠杆企业往往也伴随不同的资产结构
  • 管理层真正关心的是:控制其他指标后,哪个因素还有独立贡献?
  • 这正对应模型选择的核心问题:哪些变量提供了不可替代的信息?

所以,这个案例不是单纯为了跑代码,而是为了把’统计筛选’和’财务解释’放在同一个框架里理解。

数据准备:加载 A 股财务数据

import numpy as np  # 数值计算库
import pandas as pd  # 数据分析库
import os  # 操作系统接口,用于跨平台路径
import matplotlib.pyplot as plt  # 绑图库

# 设置中文字体,确保图表中文正常显示
plt.rcParams['font.sans-serif'] = ['Source Han Serif SC']  # 思源宋体
plt.rcParams['axes.unicode_minus'] = False  # 负号正常显示

# 根据操作系统自动选择本地数据路径
LOCAL_DATA_DIR = 'C:/qiufei/data' if os.name == 'nt' else '/home/ubuntu/r2_data_mount/qiufei/data'  # 跨平台路径
financial_data_path = os.path.join(LOCAL_DATA_DIR, 'stock/financial_statement.h5')  # 拼接财务数据路径
financial_data = pd.read_hdf(financial_data_path)  # 读取A股上市公司财务报表数据

构造杜邦分析特征

# 筛选2022年年报数据(最完整的年度数据)
financial_data = financial_data[financial_data['quarter'] == '2022q4'].copy()  # 使用年报数据

# 构造杜邦分析核心指标
financial_data['total_equity'] = financial_data['equity_parent_company']  # 归母权益作为净资产
financial_data = financial_data[financial_data['total_equity'] > 1e8]  # 过滤净资产过低的公司(<1亿元)
financial_data['ROE'] = financial_data['net_profit_parent_company'] / financial_data['total_equity']  # 计算净资产收益率
financial_data = financial_data[(financial_data['ROE'] > -1) & (financial_data['ROE'] < 1)]  # 过滤极端ROE值

# 6个候选财务特征
financial_data['Net_Margin'] = financial_data['net_profit_parent_company'] / financial_data['operating_revenue']  # 净利润率
financial_data['Asset_Turnover'] = financial_data['operating_revenue'] / financial_data['total_assets']  # 资产周转率
financial_data['Leverage'] = financial_data['total_assets'] / financial_data['total_equity']  # 权益乘数
financial_data['Debt_Ratio'] = financial_data['total_liabilities'] / financial_data['total_assets']  # 资产负债率
financial_data['Log_Assets'] = np.log(financial_data['total_assets'])  # 对数总资产(规模代理变量)
financial_data['Cash_Ratio'] = financial_data['cash_equivalent'] / financial_data['total_assets']  # 现金比率

最优子集选择:穷举 6 个因子的所有组合

from itertools import combinations  # 排列组合工具
from sklearn.linear_model import LinearRegression  # 普通最小二乘线性回归
from sklearn.metrics import mean_squared_error, r2_score  # 模型评估指标

# 定义候选特征列表
financial_predictors = ['Net_Margin', 'Asset_Turnover', 'Leverage', 'Debt_Ratio', 'Log_Assets', 'Cash_Ratio']  # 6个杜邦因子

# 清洗数据:移除含有无穷大或缺失值的行
analysis_subset = financial_data[['ROE'] + financial_predictors].replace([np.inf, -np.inf], np.nan).dropna()  # 清洗异常值

max_feature_count = len(financial_predictors)  # 最大特征数量(6)

# 存储每个k(变量个数)下的最佳模型信息
best_models = []  # 最佳特征组合
mse_list = []  # 对应的MSE
r2_list = []  # 对应的R²

穷举搜索并记录最优模型

for k in range(1, max_feature_count + 1):  # 从1个变量到6个变量逐一尝试
    best_mse_at_k = np.inf  # 初始化当前k下的最佳MSE为正无穷
    best_r2_at_k = -np.inf  # 初始化当前k下的最佳R²为负无穷
    best_combo_at_k = None  # 初始化最佳特征组合为空

    for combo in combinations(financial_predictors, k):  # 遍历所有k个变量的组合
        feature_matrix = analysis_subset[list(combo)].values  # 提取当前组合的特征矩阵
        target_vector = analysis_subset['ROE'].values  # 目标变量
        ols_model = LinearRegression().fit(feature_matrix, target_vector)  # 拟合OLS模型
        predictions = ols_model.predict(feature_matrix)  # 计算预测值
        current_mse = mean_squared_error(target_vector, predictions)  # 计算MSE
        current_r2 = r2_score(target_vector, predictions)  # 计算R²

        if current_mse < best_mse_at_k:  # 如果当前组合的MSE更低
            best_mse_at_k = current_mse  # 更新最佳MSE
            best_r2_at_k = current_r2  # 更新最佳R²
            best_combo_at_k = combo  # 更新最佳组合

    best_models.append(best_combo_at_k)  # 记录该k下的最佳组合
    mse_list.append(best_mse_at_k)  # 记录最佳MSE
    r2_list.append(best_r2_at_k)  # 记录最佳R²

可视化:最优子集选择结果

Code
fig, axes = plt.subplots(1, 2, figsize=(14, 5))  # 创建1行2列子图

# 左图:MSE随变量数量下降(模型越复杂,训练误差越低)
axes[0].plot(range(1, max_feature_count + 1), mse_list, marker='o', linewidth=2.5,
            markersize=8, color='#E3120B')  # 红色折线标记每个k下的最小MSE
axes[0].set_xlabel('预测变量数量', fontsize=13)  # 横轴标签
axes[0].set_ylabel('MSE', fontsize=13)  # 纵轴标签
axes[0].set_title('最优子集选择: MSE vs. 模型大小', fontsize=14)  # 左图标题
axes[0].grid(True, alpha=0.3)  # 添加网格线

# 右图:R²随变量数量上升(4个变量之后边际改善趋于平缓)
axes[1].plot(range(1, max_feature_count + 1), r2_list, marker='o', linewidth=2.5,
            markersize=8, color='#008080')  # 蓝绿色折线标记每个k下的最大R²
axes[1].set_xlabel('预测变量数量', fontsize=13)  # 横轴标签
axes[1].set_ylabel('$R^2$', fontsize=13)  # 纵轴标签
axes[1].set_title('最优子集选择: $R^2$ vs. 模型大小', fontsize=14)  # 右图标题
axes[1].grid(True, alpha=0.3)  # 添加网格线

plt.tight_layout()  # 自动调整间距
plt.show()  # 显示图形
Figure 1: 最优子集选择结果:MSE和R²随模型大小的变化

如何正确解读子集选择结果?

这两张图很好看,但解读时一定要有一个统计学上的’刹车’。

  • 训练 MSE 下降是正常现象,因为变量越多,模型越有能力记住样本
  • 训练 \(R^2\) 上升也几乎是必然现象,它不等于泛化能力提升
  • 真正关键的问题是:多加一个变量,是否能在新样本上继续带来收益?
  • 因此课堂上看到’曲线继续变好’,不能立刻下结论说’变量越多越好’

这也是为什么经济金融建模里,BIC 和交叉验证常常比单纯的训练拟合优度更重要。

子集选择的现代进展:穷举不等于蛮力

虽然最优子集选择听起来很’暴力’,但现代算法已经让它比教科书时代高效得多。

  • Branch-and-Bound:利用上下界剪枝,避免把所有组合都真正算完
  • Mixed-Integer Optimization:把’是否选入变量’写成 0-1 决策变量,用现代优化器求解
  • Stability Selection:反复重抽样,看哪些变量被稳定选中,而不是只看一次结果
  • Post-Selection Inference:在模型选择完成后,重新评估显著性和不确定性

这说明最优子集选择并没有过时,而是在’可解释建模’回潮的背景下重新获得重视。

前向逐步选择:用’贪心法’近似最优搜索

当前向逐步选择出场时,问题已经从’我能不能算完’变成了’我能不能快速找到一个不错的答案’。

  1. 从零模型 \(M_0\) 开始,什么变量都不放
  2. 在剩余变量中逐个试探,问’谁的加入带来最大改进?’
  3. 选出当前最优变量加入模型,进入下一轮
  4. 重复这个过程,直到达到停止规则或变量耗尽

它的核心思想是局部最优、逐步扩展,很像投资研究中的滚动筛选:先找第一重要因子,再问第二个还能补充什么信息。

前向、后向与双向逐步:怎么选?

三种逐步策略的差别,本质上在于’起点’和’是否允许回头’。

  • 前向逐步:从空模型出发,适合变量多、样本有限的场景
  • 后向逐步:从全模型出发,逐步删除最不重要变量,但要求能先拟合全模型,因此通常需要 \(n > p\)
  • 双向逐步:允许边加边删,像一场’动态谈判’,灵活但也更容易受随机波动影响
  • 经验法则:如果变量很多,先用前向;如果候选变量较少且全模型可估,后向也常见

在金融研究里,逐步法最大的价值是快,但最大的风险是’早期错误会沿着路径累积’。

逐步选择的真正瓶颈:怎么决定在哪一步停下来?

逐步选择只回答了’按什么顺序加变量’,但没有直接回答最终保留多少个变量

  • 训练 RSS 一定随模型变大而下降——不能用它做停止规则
  • 训练 \(R^2\) 也一样,变量越多总是越大
  • 我们需要某种显式惩罚复杂度的指标,来平衡拟合与过拟合

这就引出了模型选择理论中最重要的一组工具:信息准则

四大信息准则:\(C_p\)、AIC、BIC 与调整 \(R^2\)

当我们有一组候选模型时,以下四个准则各自从不同角度衡量’模型质量’。

Mallow’s \(C_p\)

\[ C_p = \frac{1}{n} (\text{RSS} + 2 d \hat{\sigma}^2) \]

AIC (Akaike Information Criterion)

\[ \text{AIC} = -2 \ln L + 2d \]

BIC (Bayesian Information Criterion)

\[ \text{BIC} = -2 \ln L + d \ln n \]

调整 \(R^2\)

\[ \text{Adjusted } R^2 = 1 - \frac{\text{RSS}/(n - d - 1)}{\text{TSS}/(n - 1)} \]

其中 \(d\) 是模型中参数个数,\(n\) 是样本量,\(\hat{\sigma}^2\) 是误差方差的估计,\(L\) 是似然函数值。

信息准则的直觉:为什么要’惩罚复杂度’?

四个准则的共同逻辑可以用一句话概括:

好模型 = 拟合得好 \(-\) 变量太多的代价

  • \(C_p\) 和 AIC 对每个额外参数施加固定惩罚 \(2\hat{\sigma}^2\)\(2\)
  • BIC 的惩罚力度随样本量 \(n\) 增长:当 \(n > 7\) 时,\(\ln n > 2\),BIC 惩罚更重
  • 因此 BIC 倾向于选择更小的模型,AIC 则相对宽容
  • 调整 \(R^2\) 的思路类似,但用的是’每自由度残差’而非似然函数
准则 惩罚力度 倾向 适用场景
\(C_p\) / AIC \(2d\) 宽容 关心预测精度
BIC \(d \ln n\) 严格 关心真模型识别
调整 \(R^2\) 自由度调整 中等 快速比较嵌套模型

AIC 与 BIC 在金融中的应用:选择 VAR 模型的滞后阶数

信息准则在金融计量经济学中最经典的应用之一是选择 VAR 模型的滞后阶数

  • 向量自回归 (VAR) 模型需要决定用多少期历史数据来预测
  • 滞后太少:遗漏重要的动态关系,预测偏差大
  • 滞后太多:参数爆炸式增长,过拟合噪声
  • AIC/BIC 帮助在这两个极端之间找到平衡点

例如,在预测沪深 300 指数收益率时:

  • AIC 可能选择 3 阶滞后(保留更多动态信息)
  • BIC 可能选择 1 阶滞后(偏好简约模型)
  • 实际中常常参考两者的结果,如果一致性很高,结论更可信

交叉验证 vs 信息准则:各有什么优缺点?

模型选择有两条主线:基于公式的信息准则,和基于重采样的交叉验证。

维度 信息准则 (AIC/BIC) 交叉验证 (CV)
计算成本 低(一次拟合) 高(需要 \(k\) 次拟合)
理论假设 假设模型形式正确 不需要
适用范围 参数模型 几乎任何模型
样本效率 略低(数据被分割)
在金融中的典型用途 VAR 滞后选择、ARIMA 定阶 正则化调参、机器学习

实践建议:对于经典线性模型,两者往往给出相似答案。对于复杂的非线性模型或正则化方法,交叉验证更通用、更可靠。

收缩方法:将系数向零压缩

子集选择是’要么选、要么不选’的硬决策

收缩方法则是一种软策略:先不急着删变量,而是通过惩罚项给系数’上刹车’。

  • 如果某个变量只是提供了一点点噪声信息,它的系数会被压小
  • 如果变量彼此高度相关,收缩能降低系数在不同样本间剧烈摆动的风险
  • 目标不是让训练集拟合到极致,而是让模型在新数据上更稳、更耐用

两大经典方法分别对应两种不同的’压缩哲学’:

  • 岭回归 (Ridge Regression)\(\ell_2\) 惩罚 → 所有变量都保留,但一起被压缩
  • 套索回归 (Lasso)\(\ell_1\) 惩罚 → 一部分变量会被压到零,从而自动筛选

子集选择 vs. 收缩方法:一个统一的视角

其实子集选择和收缩方法解决的是同一个问题,只是’手段’不同。

维度 子集选择 收缩方法
变量处理 硬决策:进或出,非零即一 软决策:系数连续缩小
优化问题 \(\min \text{RSS}\) subject to \(\|\beta\|_0 \leq k\) \(\min \text{RSS} + \lambda \|\beta\|\)
系数路径 不连续跳变 连续平滑变化
对小扰动的稳定性 较差(一个样本的变化可能改变入选名单) 较好(系数变化平滑)
计算复杂度 指数级 \(2^p\)(最优)或多项式 \(p^2\)(逐步) 多项式(通常与 OLS 同阶)

从数学角度看,Lasso 可以被理解为一种’连续化的子集选择’——它用 \(\ell_1\) 范数作为 \(\ell_0\) 范数(非零个数)的凸松弛

为什么金融数据特别需要收缩?

金融数据往往是收缩方法的’天然主场’。

  • 很多特征高度相关,例如规模、营收、总资产、负债通常同时变化
  • 样本期数常常不长,但大家又想塞进很多先行指标、财务比率和市场变量
  • 市场会发生制度变化、风格切换、行业冲击,导致历史关系并不稳定
  • 在风控、资产配置、盈利预测中,’系数太极端’往往比’略有偏差’更危险

所以正则化并不是承认自己’拟合不好’,而是在主动追求更稳健的决策规则。

岭回归:保留所有变量,但限制’押注过重’

OLS 目标\(\min_\beta \text{RSS} = \sum_{i=1}^n (y_i - \beta_0 - \sum_{j=1}^p \beta_j x_{ij})^2\)

岭回归目标:在 RSS 的基础上加入 \(\ell_2\) 惩罚

\[ \min_\beta \left\{ \text{RSS} + \lambda \sum_{j=1}^{p} \beta_j^2 \right\} \]

  • \(\lambda = 0\) 时,岭回归退化为 OLS
  • \(\lambda\) 逐渐增大时,模型会越来越’保守’
  • \(\ell_2\) 惩罚的直觉是:允许很多变量都有一点作用,但不允许任何单个变量权重过大
  • 这非常适合’每个指标都可能有点信息,但谁也不该独占全部解释权’的金融场景

因此,岭回归的关键不是删变量,而是把极端系数重新拉回合理区间。

岭回归最适合哪些金融任务?

岭回归尤其适合’变量之间高度相关,但我们又不想武断删除其中任何一个’的任务。

  • 收益预测:价值、质量、成长、波动率因子之间往往彼此相关
  • 利率预测:不同期限的收益率曲线节点天然共线
  • 企业风险监测:资产、营收、杠杆、现金流等指标往往同步变动
  • 行业研究:长三角制造业企业如上汽集团、恒瑞医药、海康威视,财务比率既有关联又各有含义

在这些场景里,岭回归的优点是’共享信息而不轻易丢信息’。

为什么岭回归有时比 OLS 更准?

岭回归能改善预测,靠的不是’训练集拟合更好’,而是’样本外更稳定’。

  • OLS 的一个优点是无偏,但在高相关或高维场景下,方差可能非常大
  • 一点点样本扰动,就可能让 OLS 系数发生剧烈摆动
  • 岭回归愿意引入少量偏差,去换取显著的方差下降
  • 因而真正可能出现 U 型的,通常是测试 MSE,而不是训练 MSE

这句话非常关键:正则化通常会让训练误差变差,但让样本外误差变好。

偏差-方差权衡:测试 MSE 应该是 U 型

偏差方差权衡 展示随着惩罚强度lambda增大,方差下降、偏差平方上升,而测试MSE呈U型的关系 惩罚强度 λ(左小右大) 误差 模型灵活度:左高,右低 方差 偏差² 测试 MSE 最优 λ 注意:U 型的是测试误差,不是训练误差

偏差-方差权衡的金融直觉:过拟合 vs 过度简化

偏差-方差权衡在金融中有非常直接的实际含义:

过拟合(低偏差、高方差,\(\lambda\) 太小)

  • 模型学到了’2023 年 Q3 那个月的特殊市场环境’
  • 样本内回测看起来很棒,但换一个季度就失效
  • 典型症状:系数在不同回测窗口之间剧烈跳动

过度简化(高偏差、低方差,\(\lambda\) 太大)

  • 模型把所有系数都压到接近零,几乎等于用均值做预测
  • 丢掉了真正有用的信息,比如’高杠杆企业确实风险更大’
  • 典型症状:预测值几乎不随输入变化

最优 \(\lambda\) 位于两个极端之间——模型既保留了关键信号,又不会对噪声过度反应。

实际上,金融从业者经常说的’模型太敏感’(高方差)和’模型太迟钝’(高偏差)就是在描述这个权衡。

案例:高维财务数据的岭回归系数路径

from sklearn.linear_model import Ridge  # 岭回归模型
from sklearn.preprocessing import StandardScaler  # 标准化工具

# 自动筛选所有数值型列作为候选特征
numeric_columns = financial_data.select_dtypes(include=[np.number]).columns  # 获取所有数值型列名
excluded_columns = ['ROE', 'net_profit_parent_company', 'equity_parent_company',
                    'total_equity', 'net_profit', 'undistributed_profit',
                    'minority_profit', 'basic_earnings_per_share']  # 排除与ROE直接相关的变量

# 只保留缺失率低于30%的列
valid_columns = [c for c in numeric_columns if c not in excluded_columns
                 and financial_data[c].isnull().mean() < 0.3]  # 过滤高缺失率列

# 缺失值用0填充,构造高维特征
data_filled = financial_data[valid_columns].fillna(0)  # 0填充缺失值
data_filled['_target_ROE'] = financial_data['ROE'].values  # 带入目标变量

特征工程:构造高维比率指标

# 将所有绝对金额除以总资产,消除规模效应
selected_features = []  # 存储最终特征名
if 'total_assets' in data_filled.columns:  # 确认总资产列存在
    for c in data_filled.columns:  # 遍历所有列
        if c in ['total_assets', '_target_ROE']:  # 跳过特殊列
            if c == 'total_assets':  # 总资产取对数
                data_filled['Log_Assets'] = np.log(data_filled['total_assets'])  # 对数变换
                selected_features.append('Log_Assets')  # 加入特征集
        else:  # 其他科目统一除以总资产
            data_filled[c + '_Ratio'] = data_filled[c] / (data_filled['total_assets'] + 1)  # +1防除零
            selected_features.append(c + '_Ratio')  # 加入特征集

# 清洗无穷值并抽样
modeling_data = data_filled.replace([np.inf, -np.inf], np.nan).dropna()  # 替换inf后删除
if len(modeling_data) > 500:  # 抽样减少计算量
    modeling_data = modeling_data.sample(n=500, random_state=42)  # 固定种子确保可复现

拟合不同惩罚强度下的岭回归

# 从所有特征中选取方差最大的50个
high_dim_features = modeling_data[selected_features].values  # 提取特征矩阵
feature_variances = np.var(high_dim_features, axis=0)  # 计算每个特征的方差
top_variance_indices = np.argsort(feature_variances)[-50:]  # 取方差排名前50的索引
high_dim_features = high_dim_features[:, top_variance_indices]  # 只保留Top50特征
financial_feature_names = np.array(selected_features)[top_variance_indices]  # 对应特征名
high_dim_target_roe = modeling_data['_target_ROE'].values  # 目标变量

# 标准化特征(岭回归要求统一量纲)
feature_scaler = StandardScaler()  # 实例化标准化器
scaled_features = feature_scaler.fit_transform(high_dim_features)  # 拟合并变换

# 创建λ的对数网格(从0.01到1,000,000)
ridge_lambdas = np.logspace(-2, 6, 100)  # 100个对数等距的λ值

记录系数路径并计算 L₂ 范数

# 逐一拟合岭回归,记录每个λ下的系数
ridge_coefficient_paths = []  # 存储系数路径
for current_lambda in ridge_lambdas:  # 遍历每个候选λ
    ridge_model = Ridge(alpha=current_lambda, fit_intercept=True)  # 创建岭回归实例
    ridge_model.fit(scaled_features, high_dim_target_roe)  # 拟合模型
    ridge_coefficient_paths.append(ridge_model.coef_)  # 追加系数向量
ridge_coefficient_paths = np.array(ridge_coefficient_paths)  # 转为矩阵

# 计算相对L₂范数(以极小λ的解近似OLS)
ols_proxy_model = Ridge(alpha=1e-5).fit(scaled_features, high_dim_target_roe).coef_  # 近似OLS系数
ols_l2_norm = np.linalg.norm(ols_proxy_model, 2)  # OLS系数的L₂范数作为基准
coefficient_l2_norms = [np.linalg.norm(coef, 2) / ols_l2_norm for coef in ridge_coefficient_paths]  # 收缩比例

可视化:岭回归系数路径

Code
fig, axes = plt.subplots(1, 2, figsize=(14, 5))  # 创建1行2列子图

# 随机选取10个特征高亮显示
highlighted_indices = np.random.RandomState(42).choice(range(high_dim_features.shape[1]), 10, replace=False)  # 抽取10个特征索引
for i in range(high_dim_features.shape[1]):  # 遍历所有特征
    alpha_val = 1.0 if i in highlighted_indices else 0.1  # 高亮特征不透明
    axes[0].plot(ridge_lambdas, ridge_coefficient_paths[:, i], alpha=alpha_val, linewidth=1.2)  # 绘制系数路径

axes[0].set_xscale('log')  # λ轴取对数
axes[0].set_xlabel('$\\lambda$(惩罚强度)', fontsize=13)  # 横轴标签
axes[0].set_ylabel('标准化系数', fontsize=13)  # 纵轴标签
axes[0].set_title('岭回归系数路径', fontsize=14)  # 标题
axes[0].axhline(y=0, color='black', linestyle='-', linewidth=0.5)  # 零线
axes[0].grid(True, alpha=0.3)  # 网格

# 右图:以L₂范数比为横轴
axes[1].plot(coefficient_l2_norms, ridge_coefficient_paths[:, highlighted_indices], linewidth=1.5)  # 绘制收缩路径
axes[1].set_xlabel('$||\\hat{\\beta}^R_\\lambda||_2 / ||\\hat{\\beta}||_2$', fontsize=13)  # 横轴:相对L₂范数比
axes[1].set_ylabel('标准化系数', fontsize=13)  # 纵轴标签
axes[1].set_title('岭回归系数收缩路径', fontsize=14)  # 标题
axes[1].grid(True, alpha=0.3)  # 网格

plt.tight_layout()  # 调整间距
plt.show()  # 显示
Figure 2: 岭回归系数路径。左图:系数随λ的变化。右图:系数随L₂范数比的变化。

怎样解读岭回归的系数路径?

系数路径图不是’好看而已’,它提供了很多关于数据结构的线索。

  • 如果几条路径一起收缩,往往说明这些变量携带相近信息
  • 如果某个系数一开始很大、随后快速缩小,可能意味着它原本受噪声放大
  • 岭回归几乎不会把系数精确压成零,因此它更像’重新分配权重’而不是’淘汰选手’
  • 在风险管理和收益预测里,这种平滑收缩常常比变量忽进忽出更稳健

所以,读岭回归路径图,本质上是在读’信息如何在变量之间重新分配’。

岭回归结果的金融解读:系数收缩揭示了什么?

让我们用投资分析的语言来解读刚才的系数路径图,把统计结论翻译成商业洞察。

被大幅收缩的变量意味着什么?

  • 某些财务指标在 OLS 中系数很大,但被岭回归大幅压缩——这往往说明它们的高系数来自样本特异性而非真正的经济关系
  • 典型例子:某个行业虚拟变量恰好在特定年份表现突出,OLS 赋予它高权重,但岭回归’打折’处理

收缩路径相似的变量意味着什么?

  • 如果净利率和毛利率的系数路径几乎平行收缩,说明它们在解释 ROE 时高度替代
  • 从投资角度看,只需要关注其中一个即可

系数在某个 \(\lambda\) 后变号意味着什么?

  • 如果一个系数随 \(\lambda\) 增大从正变负,说明在不同正则化强度下,该变量的’净效应’方向反转
  • 这通常是多重共线性的标志——该变量的正/负效应取决于哪些其他变量也在模型中

岭回归在投资组合构建中的实际应用

岭回归在现代量化投资中有一个非常重要的直接应用:正则化协方差估计

传统马科维茨均值-方差优化的核心输入是协方差矩阵 \(\Sigma\),但直接使用样本协方差矩阵会带来严重问题:

  • 当资产数 \(p\) 接近或超过观测数 \(n\) 时,样本协方差矩阵接近奇异
  • 矩阵求逆后的结果极不稳定,导致配置权重大幅波动
  • 这就是为什么传统均值-方差模型在实践中经常’不可用’

岭回归的思想在这里有天然应用:在协方差矩阵对角线上加 \(\lambda \mathbf{I}\),等价于 Ledoit-Wolf 收缩估计,这是现在投资组合管理中最常用的协方差矩阵修正方法之一。

启示:岭回归的’对角线加常数’这个简单操作,在金融的各个角落都在被使用——从回归到组合优化到风险模型。

套索回归:把’不重要’的变量真正踢出模型

如果说岭回归是在’所有人都保留、但每个人少拿一点权重’,那么套索回归更像是在做一轮真正的筛人。

\[ \min_\beta \left\{ \text{RSS} + \lambda \sum_{j=1}^{p} |\beta_j| \right\} \]

  • \(\ell_1\) 惩罚会把一部分系数精确压到零
  • 因而套索同时完成两件事:收缩变量选择
  • 当我们相信’真正有用的变量其实只占少数’时,套索通常比岭回归更有吸引力
  • 它非常适合做可解释的稀疏模型,但代价是保留下来的系数也会被向零拉偏

一句话概括:岭回归是在分散押注,套索回归是在做取舍。

\(\ell_1\)\(\ell_2\) 惩罚的几何解释

L1与L2惩罚的几何对比 展示为什么Lasso产生稀疏解而Ridge不产生 为什么 Lasso 产生稀疏解? 岭回归 (L₂) β₁ β₂ 交点 交在光滑边界 → β₁≠0, β₂≠0 套索 (L₁) β₁ β₂ 角点 交在角点 → β₁=0(稀疏解!)

Lasso 的求解算法:坐标下降法 (Coordinate Descent)

Lasso 的优化问题由于 \(\ell_1\) 惩罚项不可微,不能像岭回归那样写出闭式解。

核心思想:每次只优化一个系数,固定其他所有系数

  1. 初始化所有系数 \(\hat{\beta}_j = 0\)
  2. 对第 \(j\) 个系数,计算不含该变量的’部分残差’
  3. 对残差做单变量回归,得到 OLS 解 \(\tilde{\beta}_j\)
  4. 应用软阈值函数

\[ \hat{\beta}_j = S(\tilde{\beta}_j, \lambda) = \text{sign}(\tilde{\beta}_j) \cdot \max(|\tilde{\beta}_j| - \lambda, 0) \]

  1. 循环遍历所有变量,直到收敛

直觉:如果某个变量的信号强度 \(|\tilde{\beta}_j|\) 不够大(小于 \(\lambda\)),它就被直接置零。

软阈值 vs 硬阈值:为什么 Lasso 更好?

理解软阈值函数,就理解了 Lasso 为什么优于简单的’阈值筛选’。

方法 处理方式 系数路径 缺点
硬阈值(子集选择) 信号弱于阈值 → 直接删除 不连续跳变 微小的数据扰动可能导致不同的变量被选中
软阈值(Lasso) 所有系数统一向零收缩 \(\lambda\) 连续平滑 被保留的系数也有一定偏差

软阈值的优势在于连续性:当数据发生微小变化时,系数不会突然从非零跳到零(或反过来),这使得 Lasso 的结果在实践中更加稳定和可复现。

套索最适合哪些经济金融问题?

只要任务具有’少数关键信号 + 大量候选变量’的特征,套索就很有吸引力。

  • 信用评分:从大量客户行为、账户特征中筛出少数关键违约信号
  • 财务预警:从几十个报表比率中筛出最能解释困境或盈利恶化的变量
  • 宏观 nowcasting:从大量高频指标中提炼出少数领先信号
  • A 股因子研究:从庞大的因子库里先做一轮稀疏筛选,再进入组合构建

在长三角上市公司研究里,套索很适合回答这种问题:‘究竟是哪几个财务指标,对企业盈利能力或偿债风险最关键?’

岭回归 vs 套索:实战对比

from sklearn.linear_model import Lasso  # 套索回归模型
from sklearn.model_selection import cross_val_score  # K折交叉验证

# 重新标准化(确保独立可运行)
feature_scaler = StandardScaler()  # 实例化标准化器
scaled_features = feature_scaler.fit_transform(high_dim_features)  # 拟合并变换
target_roe_array = high_dim_target_roe  # 目标变量

# 定义λ搜索网格
cv_lambda_range = np.logspace(-4, 2, 50)  # 50个对数等距λ值

# 对每个λ,分别用5折CV评估Ridge和Lasso
ridge_cv_mse_scores = []  # Ridge的CV MSE
lasso_cv_mse_scores = []  # Lasso的CV MSE
lasso_nonzero_counts = []  # Lasso的非零系数数量
ridge_nonzero_counts = []  # Ridge的非零系数数量

交叉验证对比循环

for current_lambda in cv_lambda_range:  # 遍历每个候选λ
    # 岭回归
    ridge_cv_model = Ridge(alpha=current_lambda)  # 创建模型
    ridge_fold_scores = cross_val_score(ridge_cv_model, scaled_features, target_roe_array, cv=5, scoring='neg_mean_squared_error')  # 5折CV
    ridge_cv_mse_scores.append(-ridge_fold_scores.mean())  # 记录平均MSE
    ridge_cv_model.fit(scaled_features, target_roe_array)  # 全数据拟合
    ridge_nonzero_counts.append(np.sum(np.abs(ridge_cv_model.coef_) > 1e-4))  # 统计非零系数

    # 套索回归
    lasso_cv_model = Lasso(alpha=current_lambda, max_iter=20000)  # 创建模型,设足够迭代次数
    lasso_fold_scores = cross_val_score(lasso_cv_model, scaled_features, target_roe_array, cv=5, scoring='neg_mean_squared_error')  # 5折CV
    lasso_cv_mse_scores.append(-lasso_fold_scores.mean())  # 记录平均MSE
    lasso_cv_model.fit(scaled_features, target_roe_array)  # 全数据拟合
    lasso_nonzero_counts.append(np.sum(np.abs(lasso_cv_model.coef_) > 1e-4))  # 统计非零系数

# 找最优λ
optimal_ridge_lambda = cv_lambda_range[np.argmin(ridge_cv_mse_scores)]  # Ridge最优λ
optimal_lasso_lambda = cv_lambda_range[np.argmin(lasso_cv_mse_scores)]  # Lasso最优λ

可视化:CV 误差与模型稀疏性

Code
fig, axes = plt.subplots(1, 2, figsize=(14, 5))  # 创建1行2列子图

# 左图:CV MSE比较
axes[0].plot(cv_lambda_range, ridge_cv_mse_scores, linewidth=2.5, label='岭回归 (Ridge)', color='#008080')  # Ridge曲线
axes[0].plot(cv_lambda_range, lasso_cv_mse_scores, linewidth=2.5, label='套索 (Lasso)', color='#E3120B')  # Lasso曲线
axes[0].axvline(optimal_ridge_lambda, color='#008080', linestyle='--', alpha=0.5)  # Ridge最优λ标记
axes[0].axvline(optimal_lasso_lambda, color='#E3120B', linestyle='--', alpha=0.5)  # Lasso最优λ标记
axes[0].set_xscale('log')  # 对数刻度
axes[0].set_xlabel('$\\lambda$', fontsize=13)  # 横轴
axes[0].set_ylabel('交叉验证 MSE', fontsize=13)  # 纵轴
axes[0].set_title('CV 误差比较', fontsize=14)  # 标题
axes[0].legend(fontsize=12)  # 图例
axes[0].grid(True, alpha=0.3)  # 网格

# 右图:稀疏性比较
axes[1].plot(cv_lambda_range, ridge_nonzero_counts, linewidth=2.5, label='岭回归', color='#008080')  # Ridge非零系数
axes[1].plot(cv_lambda_range, lasso_nonzero_counts, linewidth=2.5, label='套索', color='#E3120B')  # Lasso非零系数
axes[1].set_xscale('log')  # 对数刻度
axes[1].set_xlabel('$\\lambda$', fontsize=13)  # 横轴
axes[1].set_ylabel('非零系数数量', fontsize=13)  # 纵轴
axes[1].set_title('模型稀疏性比较', fontsize=14)  # 标题
axes[1].legend(fontsize=12)  # 图例
axes[1].grid(True, alpha=0.3)  # 网格

plt.tight_layout()  # 调整间距
plt.show()  # 显示
Figure 3: 岭回归与套索对比。左图:CV MSE。右图:非零系数数量。

Ridge vs. Lasso 结果的金融解读

上面的对比实验揭示了两个重要的金融洞察:

洞察一:预测精度 vs. 可解释性的权衡

  • 左图显示两者 CV MSE 接近——在纯预测任务中,选哪个差别不大
  • 但 Lasso 同时给出了一个只有十几个变量的稀疏模型
  • 对于基金经理写投资报告、向客户解释策略逻辑,Lasso 的结果更有沟通价值

洞察二:模型稳定性的隐含信息

  • 岭回归 CV 曲线通常更平滑——说明它对 \(\lambda\) 选择不那么敏感
  • Lasso CV 曲线可能有更多波动——因为每改一点 \(\lambda\),变量名单就可能大变
  • 在实盘交易中,模型的稳定性可能比多出来的一点预测精度更值钱

实践建议:如果你在做量化策略,先用 Lasso 筛出重要因子,然后用岭回归做最终配置——兼得稀疏选择与稳定估计。

Lasso 告诉我们哪些财务因子’真正重要’?

运行 Lasso 后,被保留的非零系数对应的变量,就是数据驱动认为最重要的预测因子

在我们的杜邦分析扩展实验中,Lasso 通常会保留以下几类因子:

因子类别 典型代表 为什么被选中
盈利能力 净利率、毛利率 直接驱动 ROE 的核心变量
杠杆水平 资产负债率 杜邦分解的核心组成部分
运营效率 资产周转率 反映资产利用效率
现金流 经营现金流/营收 区分’纸面盈利’和’真金白银’

而被 Lasso 淘汰的变量通常是:

  • 冗余变量:如流动比率和速动比率同时存在时,往往只保留一个
  • 噪声变量:如某些交叉项或高阶项,解释力微弱

Lasso 的局限:相关变量太多时会’犹豫’

套索非常强大,但它并不是’永远最优’。

  • 如果一组变量高度相关,Lasso 往往只挑其中一个,其他变量可能被随意舍弃
  • 换一批样本后,被选中的那一个变量可能会发生变化,导致选择结果不稳定
  • 套索的系数也会被惩罚向零拉偏,因此它适合预测,不一定适合直接做经济解释或因果解释
  • 如果希望’成组保留’相关变量,Elastic Net 或 Group Lasso 往往更合适

因此,套索给出的变量名单要被看作’数据驱动的候选清单’,而不是不可质疑的真理。

正则化在信用风险评估中的应用

信用风险评估是正则化方法在金融领域最典型、最成功的应用之一。

场景描述

  • 银行需要根据客户的几十甚至上百项特征(收入、负债、征信记录、消费行为等)预测违约概率
  • 特征之间高度相关(如不同口径的收入指标、多种负债率计算方式)
  • 监管要求模型具有可解释性——银行必须能说清楚’为什么拒绝这个客户’

为什么 Lasso/Elastic Net 特别合适?

需求 Lasso/Elastic Net 的优势
可解释性 自动筛选出最关键的风险变量(如收入负债比、逾期次数)
稳定性 Elastic Net 在相关特征间稳定选择
监管合规 稀疏模型更容易通过银保监会的模型验证
实时部署 变量少意味着线上评分引擎更高效

中国实践:蚂蚁集团的花呗额度模型、各大银行的信用卡审批模型,底层都大量使用了正则化逻辑回归(即 Lasso 应用于 Logistic 回归框架)。

从正则化回归到正则化分类:Logistic + Lasso

值得注意的是,我们在本章学到的所有正则化技术——Ridge、Lasso、Elastic Net——都可以无缝扩展到分类问题

在信用风险中,目标变量 \(Y\) 不是连续数值,而是违约 vs 不违约的二分类。此时只需要把目标函数从 RSS(残差平方和)替换为负对数似然

\[ \min_\beta \left\{ -\ell(\beta) + \lambda \|\beta\|_1 \right\} \]

其中 \(\ell(\beta)\) 是 Logistic 回归的对数似然函数。

  • 数学形式几乎一样:损失函数 + 惩罚项
  • 优化算法也一样:坐标下降法
  • sklearn 中,直接使用 LogisticRegression(penalty='l1') 即可

这说明正则化是一种通用的建模哲学,不局限于线性回归。

弹性网 (Elastic Net):Ridge 与 Lasso 的最佳拍档

既然岭回归和 Lasso 各有所长,一个自然的想法是:能不能把两者结合?

\[ \min_\beta \left\{ \text{RSS} + \lambda \left[ \alpha \sum_{j=1}^{p} |\beta_j| + (1-\alpha) \sum_{j=1}^{p} \beta_j^2 \right] \right\} \]

  • 参数 \(\alpha \in [0,1]\) 控制两种惩罚的混合比例
  • \(\alpha = 1\) 退化为纯 Lasso,\(\alpha = 0\) 退化为纯 Ridge
  • 介于两者之间时,模型既能像 Lasso 一样筛选变量,又能像 Ridge 一样稳定处理共线性

Elastic Net 是 Zou & Hastie (2005) 提出的,如今已成为高维建模的默认首选

Elastic Net 为什么在金融数据中格外有效?

金融数据的特点让 Elastic Net 几乎成了’量身定做’的工具。

  • 变量组效应:财务指标天然成组——盈利类、杠杆类、流动性类。Lasso 只选一个代表,Elastic Net 更愿意保留同一组的多个指标
  • 共线性普遍:规模、营收、总资产等指标高度相关,纯 Lasso 在这些变量间反复’犹豫’,Elastic Net 通过 \(\ell_2\) 项稳住选择
  • 稀疏性需求:投研报告和授信评分卡都需要可解释的稀疏模型,Elastic Net 的 \(\ell_1\) 项保证了变量筛选功能
  • 预测与解释兼顾:在 A 股多因子选股中,研究者既想筛出核心因子,又不想因为共线性导致因子暴露不稳定

经验法则:如果你不确定用 Ridge 还是 Lasso,先试 Elastic Net

Elastic Net 的混合参数 \(\alpha\):直觉与选择策略

\(\alpha\) 的选择反映了你对数据稀疏程度的先验判断

\(\alpha\) 行为特征 适用场景
\(\alpha = 0\) 纯 Ridge,保留所有变量 所有变量都可能有用
\(\alpha = 0.1 \sim 0.3\) 以 Ridge 为主,轻度筛选 变量很多且高度相关
\(\alpha = 0.5\) 均衡混合 不确定稀疏程度时的默认选择
\(\alpha = 0.7 \sim 0.9\) 以 Lasso 为主,较强筛选 相信只有少数变量重要
\(\alpha = 1\) 纯 Lasso,最强稀疏性 明确要做变量选择

实践中,\(\alpha\) 本身也可以通过交叉验证来选择,sklearnElasticNetCV 支持对 \(\alpha\)\(\lambda\) 同时搜索。

超参数调优的实战策略

在正则化方法中,我们需要选择的超参数主要包括:

  • \(\lambda\):惩罚强度(Ridge、Lasso、Elastic Net 都需要)
  • \(\alpha\)\(\ell_1\)\(\ell_2\) 的混合比例(仅 Elastic Net)
  • \(k\):交叉验证的折数

网格搜索 (Grid Search) vs 随机搜索 (Random Search)

方法 优点 缺点
网格搜索 系统全面,不会遗漏最优区域 当参数多时计算量呈指数增长
随机搜索 计算效率高,尤其当某些参数不敏感时 可能错过窄的最优区间

实践建议

  • 只有 \(\lambda\) 一个参数时(如 Ridge、Lasso),网格搜索足够
  • \(\alpha\)\(\lambda\) 两个参数时(如 Elastic Net),先粗搜再细搜
  • sklearnLassoCVElasticNetCV 内置了高效的搜索路径算法(warm start),比手动网格搜索快很多

Warm Start 的直觉:从大 \(\lambda\) 开始(所有系数接近零),逐步减小 \(\lambda\)。每一步的起点是上一步的解——这比从头开始优化快得多。

正则化方法的计算复杂度对比

选择方法时,计算成本也是一个不可忽视的实际因素。

方法 单次拟合复杂度 CV 调优总成本 实时部署难度
最优子集 \(O(2^p \cdot np)\) 天文数字 简单(选定子集后是普通 OLS)
前向逐步 \(O(p^2 \cdot n)\) 中等 简单
岭回归 \(O(np^2)\) 闭式解 低(一次矩阵分解) 极简单
Lasso \(O(np \cdot \text{迭代数})\) 低(warm start 路径) 简单
Elastic Net \(O(np \cdot \text{迭代数})\) 中等(双参数搜索) 简单
PCR \(O(np \min(n,p))\) 需存储载荷矩阵

关键洞察:在 A 股全市场选股(\(n \approx 5000\)\(p \approx 50\))的量级上,所有正则化方法都可以在几秒内完成。计算成本通常不是瓶颈——正确设置时间序列 CV 才是最耗时、最容易出错的环节。

Lasso 的求解算法:坐标下降法

Lasso 的优化问题因为 \(|\beta_j|\) 不可微,不能直接用标准微积分方法求解。

坐标下降法 (Coordinate Descent) 是目前最主流的求解策略:

  1. 固定其他所有系数 \(\beta_{-j}\),只对 \(\beta_j\) 单独优化
  2. 对单个系数的子问题,存在解析解(软阈值公式)
  3. 依次对 \(j = 1, 2, \ldots, p\) 轮流更新,重复直到收敛
  4. 每一轮只需要做简单的向量运算,计算效率极高

这个算法的优雅之处在于:虽然 \(\ell_1\) 惩罚整体不可微,但固定其他变量后,每个子问题都有闭式解。

软阈值算子:Lasso 的核心数学工具

在坐标下降的每一步中,单个系数 \(\beta_j\) 的更新公式为:

\[ \hat{\beta}_j = S\left(\frac{1}{n} \sum_{i=1}^n x_{ij} r_{ij}^{(-j)}, \; \lambda\right) \]

其中 软阈值算子 (Soft-Thresholding Operator) 定义为:

\[ S(z, \lambda) = \begin{cases} z - \lambda & \text{if } z > \lambda \\ 0 & \text{if } |z| \leq \lambda \\ z + \lambda & \text{if } z < -\lambda \end{cases} \]

  • 当信号 \(|z|\) 足够强(超过阈值 \(\lambda\)),保留系数但向零收缩 \(\lambda\) 个单位
  • 当信号太弱(\(|z| \leq \lambda\)),系数直接被压到零
  • 这就是 Lasso 能产生精确零的数学机制

岭回归的闭式解:矩阵视角

与 Lasso 不同,岭回归的优化问题有完美的闭式解

\[ \hat{\beta}^{\text{ridge}} = (\mathbf{X}^T \mathbf{X} + \lambda \mathbf{I})^{-1} \mathbf{X}^T \mathbf{y} \]

与 OLS 的闭式解 \(\hat{\beta}^{\text{OLS}} = (\mathbf{X}^T \mathbf{X})^{-1} \mathbf{X}^T \mathbf{y}\) 相比:

  • 唯一区别是在 \(\mathbf{X}^T \mathbf{X}\) 的对角线上加了 \(\lambda\)
  • 这使得矩阵总是可逆的,即使 \(p > n\) 或变量高度共线
  • \(\lambda\) 越大,解越接近零向量;\(\lambda = 0\),就退化回 OLS
  • 从数值计算角度看,加 \(\lambda \mathbf{I}\) 改善了矩阵的条件数,让求解更稳定

这个公式揭示了岭回归的本质:它是 OLS 的一个数值稳定化版本。

条件数与数值稳定性:为什么加 \(\lambda \mathbf{I}\) 就管用?

要理解岭回归为什么’总是可逆’,需要回顾一个线性代数概念:条件数

矩阵 \(\mathbf{A}\) 的条件数定义为:

\[ \kappa(\mathbf{A}) = \frac{\sigma_{\max}}{\sigma_{\min}} \]

其中 \(\sigma_{\max}\)\(\sigma_{\min}\) 分别是最大和最小奇异值。

  • 条件数越大,矩阵越接近奇异,求解越不稳定
  • \(\kappa > 10^{10}\) 时,数值求解的结果在实践中已经不可信了

岭回归加 \(\lambda \mathbf{I}\)

  • 所有奇异值变成 \(\sigma_j + \lambda\)(对于 \(\mathbf{X}^T\mathbf{X}\),特征值变成 \(\sigma_j^2 + \lambda\)
  • 最小奇异值至少为 \(\lambda\),不会趋近于零
  • 条件数变为 \(\frac{\sigma_{\max}^2 + \lambda}{\sigma_{\min}^2 + \lambda}\),显著改善

数值示例:假设 \(\mathbf{X}^T\mathbf{X}\) 的特征值为 \(\{100, 0.001\}\),则 \(\kappa = 100{,}000\);加上 \(\lambda = 1\) 后,\(\kappa = \frac{101}{1.001} \approx 101\)——条件数改善了近 1000 倍。

岭回归与主成分的深层联系

岭回归的闭式解还隐藏着一个深刻的几何直觉。

\(\mathbf{X}\) 做奇异值分解 \(\mathbf{X} = \mathbf{U} \mathbf{D} \mathbf{V}^T\),则岭回归的拟合值为:

\[ \hat{\mathbf{y}}^{\text{ridge}} = \sum_{j=1}^{p} \mathbf{u}_j \frac{d_j^2}{d_j^2 + \lambda} \mathbf{u}_j^T \mathbf{y} \]

  • 对于大奇异值 \(d_j \gg \lambda\),缩放因子 \(\frac{d_j^2}{d_j^2 + \lambda} \approx 1\),保留原始信号
  • 对于小奇异值 \(d_j \ll \lambda\),缩放因子 \(\approx 0\),压缩噪声方向
  • 因此岭回归本质上是对主成分做选择性收缩:保留方差大的方向,压缩方差小的方向

这揭示了岭回归和 PCR 之间的深层联系:两者都在’去掉噪声方向’,但岭回归是连续收缩,PCR 是硬截断。

多重共线性案例:为什么 OLS 在金融数据上经常’爆炸’?

在 A 股上市公司的财务报表中,多重共线性几乎无处不在。

  • 总资产 ≈ 总负债 + 股东权益(会计恒等式)
  • 营业收入与营业成本高度正相关
  • 资产负债率 = 总负债 / 总资产,与两个分量都强相关
  • ROE = 净利率 × 周转率 × 权益乘数(杜邦恒等式)

当我们把这些高度相关的变量全部放进 OLS 时:

  • 系数估计极度不稳定——换一个季度的数据,系数可能正负号都反转
  • 标准误膨胀到难以判断任何变量是否显著
  • 方差膨胀因子 (VIF) 飙升到 10 甚至 100 以上

岭回归通过在 \(\mathbf{X}^T \mathbf{X}\) 上加 \(\lambda \mathbf{I}\),直接缓解了这个问题。

贝叶斯定理快速复习:先验、似然与后验

如果同学们对贝叶斯方法还不熟,可以先记住一句最核心的话:

贝叶斯定理就是用’原来的判断’加上’新观察到的数据’,更新成’看完数据后的判断’。

公式写作:

\[ P(\theta \mid \text{data}) = \frac{P(\text{data} \mid \theta) P(\theta)}{P(\text{data})} \]

其中:

  • \(P(\theta)\)先验:看数据之前,我们对参数 \(\theta\) 的原始看法
  • \(P(\text{data} \mid \theta)\)似然:如果参数取某个值,当前数据出现得有多合理
  • \(P(\theta \mid \text{data})\)后验:看完数据之后,对参数的新判断
  • \(P(\text{data})\) 是归一化常数,保证后验分布总概率为 1

从直觉上看,后验 = 先验信息 × 数据证据,再做标准化。

从贝叶斯定理到参数估计:为什么会出现 MAP?

在回归问题里,我们真正关心的往往不是整条后验分布的每个细节,而是:

哪一组参数最值得相信?

这就引出 MAP 估计,也就是后验概率最大的那组参数:

\[ \hat{\beta}^{\text{MAP}} = \arg\max_{\beta} P(\beta \mid y, X) \]

根据贝叶斯定理,因为分母 \(P(y \mid X)\)\(\beta\) 无关,所以等价于:

\[ \hat{\beta}^{\text{MAP}} = \arg\max_{\beta} P(y \mid X, \beta) P(\beta) \]

也就是说,MAP 估计同时考虑两件事:

  • 这组参数能不能把数据解释好
  • 这组参数是否符合我们对参数的先验期待

这正是正则化与贝叶斯方法连起来的关键桥梁。

贝叶斯视角的正则化

现在可以把贝叶斯语言翻译回我们熟悉的正则化语言了。

如果误差项服从正态分布,那么负对数似然本质上就对应我们熟悉的 RSS。此时:

  • 数据拟合部分来自似然函数
  • 惩罚项部分来自参数的先验分布
  • 最大化后验概率就等价于最小化 RSS + 惩罚项

所以,正则化并不是凭空给损失函数’硬塞’一项惩罚,而是在说:

我们原本就相信,合理的回归系数不应该太夸张。

Ridge 与 Lasso 在贝叶斯世界里分别意味着什么?

方法 先验分布 惩罚形式 MAP 等价
岭回归 \(\beta_j \sim N(0, \tau^2)\)(正态分布) \(\lambda \sum \beta_j^2\) \(\lambda = \sigma^2 / \tau^2\)
套索 \(\beta_j \sim \text{Laplace}(0, b)\)(拉普拉斯分布) \(\lambda \sum |\beta_j|\) \(\lambda = 2\sigma^2 / b\)

这张表真正要表达的不是公式本身,而是两种不同的先验信念:

  • 岭回归的正态先验意味着:我们相信大部分系数应当靠近零,但允许它们平滑地分布在零附近
  • Lasso 的拉普拉斯先验意味着:我们更强烈地相信很多系数就该非常接近零,甚至被压成零
  • 因而,岭回归更像’温和收缩’,Lasso 更像’带筛选的收缩’

这也解释了为什么两者在同样的高维金融数据上会表现出不同的风格。

一个直观理解:先验越强,正则化越强

在上面的对应关系中,\(\lambda\) 并不是神秘的超参数,它可以被理解成’先验强度’的另一种写法。

  • 对岭回归而言,\(\tau^2\) 越小,表示我们越坚信系数应当靠近零,对应的 \(\lambda\) 越大
  • 对 Lasso 而言,\(b\) 越小,表示拉普拉斯先验越尖锐,也对应更强的压缩
  • 因此,调节 \(\lambda\) 的过程,也可以理解为在调节’我们对小系数的信念有多强’

这给了正则化一个很有解释力的含义:

不是算法在武断惩罚系数,而是研究者在表达自己对参数规模的谨慎态度。

为什么贝叶斯视角对金融学生特别有帮助?

贝叶斯解释的价值,不只是多记一个公式,而是让正则化更容易被直觉理解。

  • 在金融研究里,我们本来就常有先验判断,例如“多数财务指标的边际效应不会特别大”
  • 正则化把这种业务常识写进了模型,而不是完全交给样本噪声决定
  • 当样本较短、变量很多时,引入先验往往比盲目相信样本更稳健
  • 这也是为什么现代量化、风控、宏观预测里,贝叶斯语言和正则化语言经常并行出现

所以,这一页最重要的 takeaway 是:

正则化既是数学工具,也是把先验知识纳入建模的方式。

正则化的最新进展:从 Elastic Net 到高维因果推断

教科书里的 Ridge 和 Lasso 只是起点,现代高维建模已经沿着这条路线发展出很多分支。

  • Elastic Net:把 \(\ell_1\)\(\ell_2\) 结合起来,既能做筛选,又更愿意保留相关变量组
  • Adaptive Lasso:对不同变量施加不同惩罚,希望更精准地区分’真重要’与’假重要’
  • Group Lasso:按变量组整体选择,例如按行业、期限段、财务模块成组进入或退出
  • Double Machine Learning / Post-Lasso:在因果推断中先做高维控制变量筛选,再估计核心因果效应

这说明正则化不是一个已经结束的章节,而是一整条仍在快速演进的方法论主线。

Elastic Net 的数学形式:两种惩罚的’鸡尾酒’

Elastic Net 的优化目标在 OLS 损失函数上同时叠加了 \(\ell_1\)\(\ell_2\) 惩罚:

\[ \hat{\beta}^{\text{EN}} = \arg\min_{\beta} \sum_{i=1}^{n} (y_i - x_i^T \beta)^2 + \lambda \left[ \alpha \sum_{j=1}^{p} |\beta_j| + \frac{1-\alpha}{2} \sum_{j=1}^{p} \beta_j^2 \right] \]

其中 \(\alpha \in [0, 1]\) 控制两种惩罚的混合比例

  • \(\alpha = 1\):纯 Lasso
  • \(\alpha = 0\):纯岭回归
  • \(0 < \alpha < 1\):兼得两者的优点

关键性质\(\ell_2\) 部分强迫相关变量的系数趋于相等(组效应),而 \(\ell_1\) 部分仍然能把整组不重要的变量压到零。

Elastic Net 在金融因子筛选中的优势

在量化投资因子筛选中,Elastic Net 解决了纯 Lasso 的两个核心问题:

问题一:相关因子的随机取舍

  • 价值因子有多种衡量方式:市盈率、市净率、市销率、EV/EBITDA
  • 纯 Lasso 往往只保留其中一个,换样本后换一个
  • Elastic Net 倾向于同时保留(或同时删除)这些相关指标

问题二:\(p > n\) 时 Lasso 最多选 \(n\) 个变量

  • Lasso 在变量数超过样本量时,最多只能选出 \(n\) 个非零系数
  • Elastic Net 没有这个限制,可以选出超过 \(n\) 个变量

实践参数选择\(\alpha\)\(\lambda\) 都用交叉验证选。sklearn.linear_model.ElasticNetCV 可以同时搜索两个超参数的最优组合。

Adaptive Lasso:为什么要给不同变量’不同待遇’?

标准 Lasso 对所有变量施加相同的惩罚力度,但在现实中这未必合理。

  • 某些变量在初步估计中系数已经很大——它们可能是’真信号’,不该被重罚
  • 某些变量系数接近零——它们更可能是噪声,应该被更强地压缩

Adaptive Lasso 的做法:先做一次初始拟合(比如 OLS 或 Ridge),再根据初始系数大小为每个变量设置个性化权重 \(w_j\)

\[ \hat{\beta}^{\text{adapt}} = \arg\min_{\beta} \sum_{i=1}^{n} (y_i - x_i^T \beta)^2 + \lambda \sum_{j=1}^{p} w_j |\beta_j| \]

其中 \(w_j = 1 / |\hat{\beta}_j^{\text{init}}|^{\gamma}\)\(\gamma > 0\)

统计理论保证:在一定条件下,Adaptive Lasso 具备oracle 性质——即它选出的模型渐近地和’如果你提前知道哪些变量是真的’一样好。

Group Lasso:当变量天然分组时

在很多金融和经济问题中,变量不是独立存在的,而是天然分组的。

例如:

  • 财务报表中的盈利类指标(净利率、毛利率、ROA)形成一组
  • 技术面指标(MACD、RSI、布林带)形成另一组
  • 宏观变量(GDP增速、M2增速、CPI)也自成一组

Group Lasso 的目标不是逐个选变量,而是整组进出

\[ \hat{\beta} = \arg\min_{\beta} \sum_{i=1}^{n} (y_i - x_i^T \beta)^2 + \lambda \sum_{g=1}^{G} \sqrt{p_g} \| \beta_g \|_2 \]

其中 \(\beta_g\) 是第 \(g\) 组的系数向量,\(p_g\) 是该组的变量数。

金融应用:因子模型构建时,判断’整个风格因子是否有用’而非’单一指标是否有用’。

Post-Lasso 与双重机器学习:当正则化遇到因果推断

近年来最令人兴奋的进展之一,是将正则化方法应用于因果推断

传统因果推断要求控制混杂变量,但如果候选控制变量太多,手动选择就不现实。

Post-Lasso 策略分两步走:

  1. 第一步(选择):用 Lasso 从大量候选变量中筛选出最重要的控制变量
  2. 第二步(估计):只用被选中的变量,跑标准 OLS 来估计因果效应

Double Machine Learning (Chernozhukov et al., 2018) 更进一步:

  • 用机器学习方法(包括 Lasso)分别拟合因变量和处理变量对控制变量的关系
  • 用残差来估计因果效应,消除正则化偏差

金融应用案例:评估某项金融监管政策对上市公司融资成本的因果效应——需要控制大量公司特征变量,但不确定该控制哪些。

选择调优参数 \(\lambda\):交叉验证

交叉验证不是’调参玄学’,它做的事情非常明确:

  1. 在对数尺度上选取一组候选 \(\lambda\)
  2. 对每个 \(\lambda\),做 \(k\) 折交叉验证,计算 CV MSE
  3. 选使 CV MSE 最小的 \(\lambda^*\),或者用 1-SE 规则 选择一个更简单但表现几乎一样的模型
  4. 用选出的 \(\lambda\) 在全数据上重新拟合最终模型

在金融实践里,如果两个 \(\lambda\) 的 CV 误差差不多,研究者往往会偏向更简单、更稳定的那个,因为市场环境本来就会变。

sklearn 提供了 RidgeCVLassoCV内置交叉验证引擎,一行代码搞定:

from sklearn.linear_model import RidgeCV, LassoCV  # 带CV的正则化模型
ridge_cv = RidgeCV(alphas=np.logspace(-2, 6, 100), cv=10)  # 自动搜索最优λ
lasso_cv = LassoCV(cv=10, max_iter=10000)  # 自动搜索最优λ

1-SE 规则:为什么不总是选 CV 误差最小的?

CV 误差最小的 \(\lambda\) 不一定是最好的选择。原因在于 CV 误差本身也有抽样波动

  • 每折验证集只是数据的一个子集,不同的数据划分会产生不同的 CV 误差
  • 因此每个 \(\lambda\) 的 CV 误差都有一个标准误差 (SE)
  • 1-SE 规则:选择 CV 误差在”最小值 + 一个标准误差”范围内最简单的模型

为什么金融从业者偏爱 1-SE 规则?

  • 金融数据的分布会随时间漂移(非平稳性)
  • 过度拟合历史数据的复杂模型,在未来市场环境下更容易失效
  • 稍微简单一点的模型往往具有更好的鲁棒性

要记住的直觉:在 CV 误差曲线的”平坦区”里,选最简单的,而不是赌一个可能是噪声造成的微小优势。

金融数据的特殊挑战:标准 \(k\)-折 CV 可能失效

在金融数据上使用标准的随机 \(k\)-折交叉验证,有一个潜在的严重问题:时间泄露 (Data Leakage)

  • 标准 \(k\)-折 CV 随机分割数据,不考虑时间顺序
  • 这意味着训练集可能包含2024年的数据,验证集包含2023年的数据
  • 用未来信息预测过去,当然准!但这并不反映真实的预测能力

为什么在金融中特别危险?

  • 宏观环境、市场风格、政策周期都有时间趋势
  • 公司财务数据有季节性和趋势性
  • 近邻时间点的收益率高度相关(自相关性)

如果你在因子选股模型中用了标准 CV,得到了 5% 的年化超额收益——其中可能有很大一部分来自时间泄露,实盘后这些’超额收益’就会蒸发。

时间序列交叉验证:滚动窗口与扩展窗口

对于金融时间序列数据,正确的做法是使用时序感知的验证策略:

滚动窗口 (Rolling Window)

  • 训练集始终保持固定长度(如最近3年数据)
  • 每次向前滑动一步,丢弃最旧的一期,加入最新的一期
  • 适合市场结构可能发生结构性变化的场景

扩展窗口 (Expanding Window)

  • 训练集不断扩大,始终包含从起点到当前的所有历史数据
  • 验证集是紧接着训练集末尾的下一期
  • 适合认为历史数据一直有参考价值的场景

在 Python 中可以使用 sklearn.model_selection.TimeSeriesSplit

from sklearn.model_selection import TimeSeriesSplit  # 时序交叉验证
tscv = TimeSeriesSplit(n_splits=5)  # 5折时序CV

实践建议

  • 如果你在做因子选股,至少保留最近1年作为纯样本外测试,不参与任何模型选择
  • 滚动窗口长度的选择本身也是一个超参数——太短会丢失信息,太长会引入过时数据

金融中交叉验证的常见陷阱

即使使用了时序 CV,金融数据中仍然有几个容易踩的’坑’:

陷阱一:前视偏差 (Look-Ahead Bias)

  • 如果特征工程使用了’未来信息’(如用全样本均值标准化),即使 CV 分折正确,结果也会偏乐观
  • 正确做法:在每一折的训练集上分别计算均值和标准差,再应用到验证集

陷阱二:生存者偏差 (Survivorship Bias)

  • 如果只用当前仍在市的股票做回测,会系统性高估策略收益
  • 很多退市的公司恰恰是表现最差的——剔除它们等于’回避了最大的亏损’

陷阱三:信息泄露的隐蔽形式

  • 即使没有直接使用未来价格,但如果用了’未来的行业分类调整’或’未来确认的财报修正’,仍然是信息泄露
  • 在 A 股研究中,ST 标签的标注时间和实际公告时间不同——用错了就会引入泄露

核心原则:时间截面上的每一个决策,都只能使用截至该时点已公开的信息

方法选择地图:先问自己三个问题

真正做研究或实务时,不是先问’哪种方法最高级’,而是先问下面三个问题。

  1. 我最在意解释,还是最在意纯预测?
  2. 我相信很多变量都多少有用,还是只相信少数变量重要?
  3. 变量之间是否高度相关,样本是否明显偏少?

据此可以得到一个很实用的经验地图:

  • 想保留全部信息、处理强相关 → 岭回归
  • 想得到稀疏模型、筛出少数核心变量 → 套索
  • 想要可解释且变量不多 → 子集选择或逐步选择
  • 又想筛选、又担心相关变量被误删 → 弹性网

自动交叉验证选择最优 \(\lambda\)

Code
from sklearn.linear_model import RidgeCV, LassoCV  # 带内置CV的正则化模型

# 使用6个杜邦因子的精简数据集
raw_features = analysis_subset[financial_predictors].values  # 提取6个特征
target_values = analysis_subset['ROE'].values  # 目标变量
scaler = StandardScaler()  # 标准化器
X_scaled = scaler.fit_transform(raw_features)  # 标准化

# RidgeCV:自动搜索最优λ(10折CV)
ridge_cv_model = RidgeCV(alphas=np.logspace(-2, 6, 100), cv=10)  # 创建实例
ridge_cv_model.fit(X_scaled, target_values)  # 拟合
print(f'岭回归最优λ: {ridge_cv_model.alpha_:.4f}')  # 输出最优λ

# LassoCV:自动搜索最优λ
lasso_cv_model = LassoCV(alphas=np.logspace(-4, 2, 100), cv=10, max_iter=10000)  # 创建实例
lasso_cv_model.fit(X_scaled, target_values)  # 拟合
print(f'套索最优λ: {lasso_cv_model.alpha_:.4f}')  # 输出最优λ
print(f'套索选择的变量数量: {np.sum(lasso_cv_model.coef_ != 0)}')  # 非零系数个数
print(f'套索系数: {dict(zip(financial_predictors, np.round(lasso_cv_model.coef_, 4)))}')  # 各特征系数
岭回归最优λ: 705.4802
套索最优λ: 0.0002
套索选择的变量数量: 6
套索系数: {'Net_Margin': np.float64(0.0048), 'Asset_Turnover': np.float64(0.0345), 'Leverage': np.float64(-0.0107), 'Debt_Ratio': np.float64(-0.0377), 'Log_Assets': np.float64(0.0369), 'Cash_Ratio': np.float64(0.011)}
Figure 4

降维方法:换一个角度解决’变量太多’

前面的子集选择和收缩方法,都是直接在原始变量上操作。降维方法则换了一个思路:

先把 \(p\) 个原始变量’压缩’成 \(M < p\) 个新变量,再用这些新变量做回归。

  • 这些新变量是原始变量的线性组合,浓缩了主要信息
  • 只要 \(M\) 远小于 \(p\),模型的方差就会显著下降
  • 代价是:新变量不再有直接的经济学含义,解释性变差

两大经典降维回归方法:

  • 主成分回归 (PCR):先做 PCA 提取主成分,再用主成分做回归
  • 偏最小二乘 (PLS):提取新变量时同时考虑与 \(Y\) 的关系

PCA 快速回顾:找到数据中方差最大的方向

主成分分析 (PCA) 的核心想法非常简单:

  1. \(p\) 维空间里,找到数据散布最’散’的方向,这就是第一主成分 \(Z_1\)
  2. 在与 \(Z_1\) 正交的方向中,再找方差最大的方向,这是第二主成分 \(Z_2\)
  3. 依此类推,得到 \(Z_1, Z_2, \ldots, Z_p\),它们彼此正交且按方差递减

数学上,\(Z_m = \sum_{j=1}^p \phi_{jm} X_j\) 是原始变量的线性组合,其中 \(\phi_{jm}\) 是载荷系数。

关键性质:

  • 前几个主成分往往就捕获了大部分方差
  • 主成分之间相互正交,天然消除了多重共线性
  • 但主成分的含义需要人为解释,不像原始变量那样直观

PCA 在金融中的经典应用:利率期限结构

PCA 在金融中最成功的应用之一是分析利率期限结构——这也是 PCA 具有清晰经济解释的经典案例。

对一组不同期限(1月、3月、1年、5年、10年、30年)的国债收益率做 PCA,结果非常稳健:

主成分 方差占比 经济含义 直觉理解
PC1 ~85% 水平因子 所有利率同升同降
PC2 ~10% 斜率因子 长短端利差变化
PC3 ~3% 曲率因子 中间段凸起/凹陷

三个主成分解释了约98%的方差——这说明看似复杂的利率曲线,其实只由三个独立的’驱动力’主导。

这个结果在美国、中国、欧洲市场都高度一致,被称为利率的’三因子结构’。

如何确定保留多少个主成分?碎石图 (Scree Plot)

在实践中,一个关键问题是:到底保留前几个主成分?

碎石图是最直观的可视化工具:

  • 横轴是主成分序号(1, 2, 3, …)
  • 纵轴是每个主成分解释的方差比例
  • 在图上找到曲线开始’变平’的拐点 (elbow)——拐点之前保留,之后丢弃

常用判据

  • 方差解释比例:累计解释 80%-90% 方差即可
  • Kaiser 准则:保留特征值大于 1 的主成分(即至少比一个原始变量信息量大)
  • 交叉验证:对 PCR/PLS 来说,用 CV 直接选最优主成分数 \(M\)

在金融数据中,如果前 5 个主成分已解释 90% 方差,说明原始的 50 个变量中有大量冗余信息——这正是降维的空间所在。

主成分回归 (PCR):用少数主成分代替全部变量

PCR 的步骤非常直观:

  1. \(X\) 做 PCA,得到 \(Z_1, Z_2, \ldots, Z_p\)
  2. 只保留前 \(M\) 个主成分(\(M\) 远小于 \(p\)
  3. \(Z_1, \ldots, Z_M\)\(Y\) 做普通最小二乘回归

\[ Y = \theta_0 + \theta_1 Z_1 + \theta_2 Z_2 + \cdots + \theta_M Z_M + \epsilon \]

为什么这能降低过拟合?

  • 如果 \(p\) 很大但只用 \(M\) 个主成分,等于大幅减少了自由度
  • 前几个主成分保留了主要信号,后面的主成分往往对应噪声
  • 丢掉后面的主成分,相当于主动忽略噪声维度

选择 \(M\) 的方法同样依赖交叉验证:尝试不同的 \(M\),选择使 CV 误差最小的那个。

PCR 的一个重要局限

PCR 有一个容易被忽略的问题:

PCA 提取主成分时只看 \(X\),完全不考虑 \(Y\)

这意味着:

  • PCA 挑出的方向是 \(X\) 方差最大的方向
  • 但方差最大的方向,不一定是与 \(Y\) 最相关的方向
  • 可能出现这种情况:前几个主成分解释了 \(X\) 的 90% 方差,但对 \(Y\) 几乎没有预测力
  • 而真正有用的信号恰好隐藏在一个方差很小的方向里

在金融数据中,这并非罕见。例如,市值、总资产、营收等变量的第一主成分主要反映公司规模,但盈利能力的驱动因素可能不在这个方向上。

偏最小二乘 (PLS):降维时同时考虑 \(Y\)

偏最小二乘 (PLS) 正是为了解决 PCR 的这个缺陷而设计的。

PLS 在提取新方向时,同时考虑两个目标:

  1. 新方向要尽量解释 \(X\) 的方差(和 PCA 一样)
  2. 新方向要尽量和 \(Y\) 相关(PCA 完全忽略的部分)

具体地,PLS 的第一个方向 \(Z_1\) 是这样构造的:

\[ Z_1 = \sum_{j=1}^p \hat{\phi}_{j1} X_j, \quad \text{其中} \; \hat{\phi}_{j1} \propto \text{Corr}(Y, X_j) \]

也就是说,载荷系数直接由每个变量与 \(Y\) 的相关性决定。与 \(Y\) 相关性越高的变量,在 \(Z_1\) 中的权重越大。

PCR vs PLS:监督与无监督的降维之争

特征 PCR PLS
降维依据 只看 \(X\) 的方差 同时看 \(X\) 方差和与 \(Y\) 的相关性
是否监督 无监督降维 有监督降维
优势 主成分正交、数学性质好 更有针对性,通常需要更少的成分
风险 可能忽略与 \(Y\) 相关但方差小的方向 可能过拟合,尤其在样本量小时
金融应用 收益率协方差矩阵降维、风险因子提取 信用评分、收益率预测

实践中,PLS 并不总是比 PCR 好。当预测变量的主方差方向恰好也与 \(Y\) 相关时(这在很多金融场景中确实如此),PCR 和 PLS 的表现可能非常接近。

降维方法何时最有吸引力?

降维回归在以下场景中特别有价值:

  • 变量极多且高度相关:如宏观经济 nowcasting,几百个指标之间存在强共线性
  • 不需要对单个变量做解释:关心的是整体预测精度,而不是某个变量的边际效应
  • 数据具有潜在的因子结构:例如股票收益率受少数宏观因子驱动
  • 风险管理中的协方差估计:PCA 是缩减协方差矩阵维度的标准工具

但在需要解释’哪个变量重要’的任务中,降维方法的可解释性不如 Lasso 或子集选择。因此它更多地出现在预测和风险管理场景,而不是因果分析和政策评估中。

降维的金融实战:宏观经济 Nowcasting

降维回归在宏观经济临近预报 (Nowcasting) 中有一个极其成功的应用案例。

问题背景

  • GDP 数据滞后约 2-3 个月发布,投资者和央行需要更早知道经济状况
  • 可用的领先指标有上百个(PMI、电力消费、航运指数、消费者信心、信贷数据…)
  • 这些指标之间高度相关——直接放进回归会导致多重共线性灾难

PCA/PLS 的解决方案

  1. 对上百个领先指标做 PCA 或 PLS,提取前几个主成分
  2. 用这几个主成分预测当季 GDP 增速
  3. 每当有新数据发布,即时更新预测

中国实践:中国人民银行和多家券商研究所都在使用类似的’因子增强’预测模型。中金公司的宏观领先指数 (COFII) 就是基于 PCA 的方法,从几百个高频指标中提取信号。

从降维到因子投资:一个统一的视角

降维方法和金融领域的因子模型有着深刻的联系:

统计概念 金融对应
主成分 风险因子
载荷系数 \(\phi_{jm}\) 因子暴露 / Beta
主成分得分 \(Z_m\) 因子收益率
方差解释比例 因子对风险的贡献

Fama-French 三因子模型可以被理解为一种’事先指定主成分方向’的降维:

  • 市场因子 ≈ 第一主成分(解释大部分收益率方差)
  • 规模因子 ≈ 接近第二主成分
  • 价值因子 ≈ 接近第三主成分

关键区别:PCA 纯粹从数据中提取方向(statistical factors),Fama-French 基于经济理论指定方向(fundamental factors)。哪种更好?这至今仍是资产定价研究的核心争论之一。

PLS 在量化多因子模型中的独特价值

在量化投资中,PLS 相比 PCR 有一个关键优势:它提取的成分直接面向预测目标

典型场景:用 50 个财务/市场/另类因子预测个股下月收益率

方法 提取方向的依据 可能的问题
PCR 因子之间方差最大的方向 高方差方向未必是预测收益率最有用的方向
PLS 同时最大化因子方差和与收益率的协方差 提取出的成分直接与预测目标相关

实例:假设 50 个因子中,波动率因子的方差最大(市场波动剧烈时它变化最快),但与收益率关系最弱。PCR 可能把波动率方向选为第一主成分,浪费了预测能力。PLS 不会犯这个错误——它会跳过高方差但低预测力的方向,直接找到与收益率最相关的综合因子。

实践建议:在 A 股量化研究中,当你的因子库庞大(> 30 个因子)且因子之间存在显著相关性时,PLS 通常比 PCR 更适合做收益率预测。

四类方法的完整对比

特征 子集选择 岭回归 套索 降维回归
变量处理 保留或删除 全部保留,收缩 部分删除,收缩 投影到新空间
稀疏性
可解释性 中高
处理共线性 一般 一般
计算复杂度 \(2^p\) (最优) / \(p^2\) (逐步) \(O(np^2)\) 迭代收敛 \(O(np\min(n,p))\)
适用维度 低到中 任意 任意 高维强相关
金融典型场景 信用评分卡 收益预测 因子筛选 风险管理

方法选择的实战决策树

在实际项目中,可以按照以下三个核心问题逐步缩小方法范围:

问题 1:你的目标是预测还是解释?

  • 预测为主 → 弹性网或降维方法
  • 解释为主 → Lasso 或子集选择

问题 2:变量之间共线性强吗?

  • 强共线性 → Ridge、PCR 或 PLS
  • 弱共线性 → Lasso 或子集选择

问题 3:你相信真实模型是稀疏的吗?

  • 是(只有少数变量重要) → Lasso
  • 否(大多数变量都有贡献) → Ridge 或 PCR

’不确定’怎么办?

用弹性网,让交叉验证帮你自动在 Ridge 和 Lasso 之间选择最佳混合比例。

从本章到机器学习:正则化思想的延伸

本章介绍的正则化思想,远不止适用于线性回归——它是整个现代机器学习的核心哲学。

Ridge → 深度学习的权重衰减 (Weight Decay)

  • 训练神经网络时,通常在损失函数中加入 \(\lambda \sum w_i^2\)
  • 这与岭回归的 \(\ell_2\) 惩罚完全一样
  • 防止网络记忆训练数据中的噪声

Lasso → 稀疏注意力 / 网络剪枝

  • 将不重要的连接权重压缩为零,减小模型体积
  • 在模型部署(如手机端推理)中尤为关键

Dropout → 一种隐式的正则化

  • 训练时随机关闭部分神经元
  • 等价于训练了大量子模型的集成
  • 从贝叶斯视角看,Dropout 近似于对权重施加了一种特殊的先验分布

启示:不管你未来做传统计量还是深度学习,控制复杂度、防止过拟合这个核心原则永远不变。

本章小结

子集选择

  • 最优子集:穷举 \(2^p\) 个模型,透明但计算量大
  • 逐步选择:前向/后向,高效但非全局最优
  • 需用 BIC、\(C_p\)、CV 做复杂度惩罚

收缩方法

  • 岭回归:\(\ell_2\) 惩罚,保留所有变量,适合强共线性
  • 套索:\(\ell_1\) 惩罚,自动变量选择,适合稀疏场景
  • 弹性网:\(\ell_1 + \ell_2\) 混合,兼顾两者优点

降维方法

  • PCR:无监督降维后回归,消除共线性
  • PLS:有监督降维,兼顾预测目标
  • 适合高维强相关、不需要解释单个变量的场景

核心原则

  • \(\lambda\)\(M\) 的选择依赖交叉验证
  • 贝叶斯视角:正则化 = 给系数施加先验
  • 没有万能方法:根据业务需求选择

方法选择指南

  • 需要变量选择 → 套索或子集选择
  • 高维 (\(p \geq n\)) → 岭回归或套索
  • 相信只有少数变量重要 → 套索
  • 强共线性 → 岭回归或 PCR
  • 不确定时 → 弹性网 (Elastic Net) = 岭 + 套索的混合

课后练习:概念理解

练习 1:解释为什么岭回归的系数永远不会精确等于零,而 Lasso 的系数可以。提示:从优化问题的几何角度思考 \(\ell_1\)\(\ell_2\) 约束集的形状。

练习 2:一位分析师使用 Lasso 从 100 个财务指标中选出了 8 个’重要因子’。他声称这 8 个因子就是驱动 ROE 的’真正原因’。请从以下角度评价这个说法:

  • Lasso 的变量选择与因果关系之间有什么区别?
  • 如果存在一组高度相关的变量,Lasso 会怎么处理它们?
  • 换一个样本后,选出来的 8 个因子名单可能会怎样变化?

练习 3:在什么条件下,PCR 的表现可能不如简单的岭回归?请从’方差最大的方向是否与 \(Y\) 相关’这个角度分析。

课后练习:编程实践

练习 4(代码题):使用本地 A 股财务数据,完成以下分析流程:

  1. 选取2020-2024年长三角地区上市公司的财务报表数据
  2. 构建至少20个解释变量(盈利、杠杆、运营、增长类指标)
  3. 分别使用岭回归、Lasso 和弹性网预测下一年 ROE
  4. 使用时间序列交叉验证(而非标准 \(k\)-折 CV)评估模型表现
  5. 报告每种方法的最优 \(\lambda\)、CV MSE、以及 Lasso 保留的变量名单

练习 5(拓展题):在练习 4 的基础上,实现’先 Lasso 后 Ridge’的两步策略——先用 Lasso 筛出重要变量,再用岭回归做最终系数估计。与纯 Lasso 和纯岭回归比较,讨论预测性能和系数稳定性的变化。

课后练习:综合分析案例

练习 6(综合题):利率期限结构与降维

使用本地收益率曲线数据,完成以下分析:

  1. 读取中国国债收益率曲线数据,包含 1 年、3 年、5 年、7 年、10 年、30 年等期限
  2. 计算各期限利率的日度变化量
  3. 对利率变化量做 PCA,提取前三个主成分
  4. 分析前三个主成分的载荷向量,验证它们是否分别对应’水平’、’斜率’和’曲率’因子
  5. 用前 \(M\) 个主成分(\(M = 1, 2, 3\))做 PCR,预测 10 年期国债收益率的周度变化
  6. 比较 PCR(\(M=3\))与岭回归在同一数据上的预测性能

思考:为什么在利率期限结构分析中,PCR 比 Lasso 更受欢迎?(提示:利率曲线的各期限之间几乎不存在’某个期限完全无关’的情况。)

课堂讨论:真实场景中的方法选择

场景 A:信用评分模型

  • 银行需要从 200 个客户特征中选出 10-15 个放入评分卡
  • 监管要求模型必须可解释,每个变量的贡献清晰可见
  • 你会选哪种方法?为什么?

场景 B:量化对冲基金的因子策略

  • 基金从 500 个候选因子中构建多空组合
  • 目标是最大化夏普比率,而不是解释为什么这些因子有效
  • 因子之间存在大量共线性(如不同口径的估值指标)
  • 你会选哪种方法?为什么?

场景 C:中央银行的 GDP 预测

  • 使用 300 个宏观经济指标预测下季度 GDP 增速
  • 指标之间高度相关,且预计有潜在的因子结构
  • 你会选哪种方法?为什么?

初学者常见误区

在学习线性模型选择时,以下是最常见的几个误区:

误区 1:‘变量越多,模型越好’

  • 现实是:无关变量会增加方差,降低样本外预测能力
  • 在金融数据中尤其危险——很多看似相关的因子不过是噪声

误区 2:‘Lasso 选出的变量一定是”真正重要”的’

  • Lasso 做的是预测导向的变量选择,不是因果推断
  • 当多个变量高度相关时,Lasso 随机选出的那一个,可能只是该组的’代言人’

误区 3:‘交叉验证分数越高,模型就越好’

  • 如果 CV 的设计有问题(如时间序列中用了随机折划分),高分可能是假象
  • 金融数据中数据泄露(look-ahead bias)是最隐蔽的错误来源

误区 4:‘正则化会让模型表现变差,因为它引入了偏差’

  • 在高维或共线性场景下,一点偏差换来的方差下降是’赚’的
  • 总 MSE = 偏差² + 方差,正则化的目标是最小化总 MSE

思考题:模型选择的’元问题’

本章介绍的所有方法,本质上都在做一件事——在偏差方差之间寻找平衡。

但这引出了一个更深层的问题:

我们用什么标准来选择’选择方法的方法’?

  • 用 CV 来选 \(\lambda\),但 CV 本身也有超参数(折数 \(k\)
  • 用 BIC 来做模型选择,但 BIC 假设了真模型在候选集中
  • 用 AIC 来选模型,但 AIC 在小样本下可能不够保守
  • 用时间序列 CV,但窗口长度的选择也是一种模型选择

这个问题没有完美的答案。实践中的建议:

  • 多种方法交叉验证,看结果是否一致
  • 结果一致 → 信心增强
  • 结果不一致 → 谨慎行事,选择更保守的模型

这种’方法三角验证’(Methodological Triangulation)的思维方式,不仅适用于模型选择,也是所有实证研究的黄金法则。