06 线性模型选择与正则化

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

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

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

OLS 有两个痛点

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

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

三类替代方法的全景图

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

最优子集选择:穷举所有可能的模型

核心思想:对于每个 \(k = 1, 2, \ldots, p\),从 \(p\) 个预测变量中选取 \(k\) 个的所有组合,拟合模型并选出最优。

算法步骤

  1. \(M_0\) 为零模型(只有截距)
  2. 对每个 \(k = 1, \ldots, p\):拟合所有 \(\binom{p}{k}\) 个模型,选出 RSS 最小的 \(M_k\)
  3. 使用 \(C_p\)、BIC、调整 \(R^2\) 或交叉验证,从 \(M_0, M_1, \ldots, M_p\) 中选出最终模型

计算复杂度:总共需要拟合 \(2^p\) 个模型!

  • \(p = 10\):1,024 个模型 ✓
  • \(p = 20\):约 100 万个模型 ⚠️
  • \(p = 40\):约 1 万亿个模型 ✗

案例:杜邦分析法预测 ROE

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

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

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

我们构造 6 个候选财务指标,用最优子集选择来找出哪些因子组合对 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²随模型大小的变化

逐步选择:计算高效的替代方案

\(p\) 很大时,最优子集选择不可行。逐步选择提供了高效的替代方案。

前向逐步选择 (Forward Stepwise)

  1. 从零模型 \(M_0\)(只有截距)开始
  2. 每一步添加一个使拟合改善最大的变量
  3. 直到所有变量都被考虑

计算量对比

方法 \(p = 20\) 时需拟合的模型数
最优子集选择 \(2^{20} \approx 1,048,576\)
前向逐步选择 \(1 + \frac{p(p+1)}{2} = 211\)

代价:前向选择不能保证找到全局最优子集。

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

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

收缩方法则是一种软策略:保留所有变量,但通过添加惩罚项让系数向零收缩。

两大经典方法:

  • 岭回归 (Ridge Regression)\(\ell_2\) 惩罚 → 均匀收缩
  • 套索回归 (Lasso)\(\ell_1\) 惩罚 → 稀疏解 + 变量选择

岭回归:在拟合与复杂度之间权衡

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 \to \infty\) → 所有系数趋近于零

关键挑战:如何选择最优的 \(\lambda\)?→ 交叉验证

为什么岭回归能改善预测?

偏差-方差权衡的直接应用:

偏差方差权衡 展示随lambda增大,方差减小但偏差增大的权衡关系 模型灵活度 (低 ← λ → 高) 误差 方差 偏差² 总MSE 最优 λ

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

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₂范数比的变化。

套索回归:自动变量选择

岭回归的不足:所有系数都被收缩,但没有一个变量被剔除

套索回归\(\ell_1\) 惩罚替代 \(\ell_2\) 惩罚:

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

核心区别\(\ell_1\) 惩罚能将部分系数精确压缩为零,自动完成变量选择!

套索 = 收缩 + 变量选择,产生稀疏模型 (Sparse Models)

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

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

岭回归 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。右图:非零系数数量。

贝叶斯视角的正则化

正则化不仅是一种优化技巧,它有深刻的概率论解释

方法 先验分布 惩罚形式 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\)

直觉:拉普拉斯分布在零点有尖锐的峰 → 大量系数先验地被认为”应该接近零” → 产生稀疏解

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

标准流程

  1. 在对数尺度上选取一组候选 \(\lambda\)
  2. 对每个 \(\lambda\),做 \(k\) 折交叉验证,计算 CV MSE
  3. 选使 CV MSE 最小的 \(\lambda^*\)
  4. \(\lambda^*\) 在全数据上拟合最终模型

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)  # 自动搜索最优λ

自动交叉验证选择最优 \(\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': 0.0048, 'Asset_Turnover': 0.0345, 'Leverage': -0.0107, 'Debt_Ratio': -0.0377, 'Log_Assets': 0.0369, 'Cash_Ratio': 0.011}
Figure 4

本章小结

子集选择

  • 最优子集:穷举 \(2^p\) 个模型
  • 逐步选择:前向/后向,高效但非全局最优
  • 选择标准:\(C_p\)、BIC、调整 \(R^2\)、CV

收缩方法

  • 岭回归\(\ell_2\) 惩罚,均匀收缩不产生稀疏解
  • 套索\(\ell_1\) 惩罚,收缩 + 变量选择
  • 关键:用交叉验证选择 \(\lambda\)

方法选择指南

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