Elastic Net · 全流程1/10
Chapter 7 · 课堂展示

弹性网在中国 A 股月度截面上的全流程实验

基于 65 个因子、119 个月的面板数据,通过滚动窗口验证弹性网(Elastic Net) 在股票收益预测中的表现。实验覆盖数据预处理、超参数搜索、系数稀疏化分析、 样本外评估与多空组合回测的完整流程。

刘景康 & 王杉羽
Elastic NetA 股截面滚动窗口
源码elastic_net_pipeline.ipynb · cell 1

1.引言:从因子到月度收益

在高维截面回归中,弹性网通过同时施加 L1 与 L2 惩罚,在变量选择与系数稳定性之间取得平衡。

实验基于中国 A 股 2010-01 至 2019-11 的月度截面面板数据。每一行代表「某月某只股票」的 65 个因子取值与其下一个月的已实现收益率。目标是用当期因子预测下期收益——一个典型的 高维回归问题(p = 65 个预测变量,每月 n ≈ 2400 个观测)。

核心工具是 sklearn 的 ElasticNet 实现。弹性网(Zou & Hastie, 2005)的提出动机在于: 纯 Lasso 在预测变量高度相关时倾向于随机选取组内一个变量而忽略其余; 纯 Ridge 虽然抗共线性但不做变量选择。弹性网在两者之间取得折中, 既保留稀疏性又对相关因子组施加均匀收缩。

实验采用滚动窗口方案:24 个月训练、12 个月验证(用于选择最优正则化强度 α)、 1 个月样本外预测,共产生 83 个 OOS 月。这种设计模拟了真实投资场景中 「只用历史信息做预测」的约束。

月份总数
119
2010-01 ~ 2019-11
截面因子
65
月度预测变量
平均股票数
≈ 2 400
每月截面
OOS 窗口
83
滚动预测月
elastic_net_pipeline.ipynb · cell 1
1import os
2import time
3import json
4import datetime
5import warnings
6warnings.filterwarnings('ignore')
7 
8import numpy as np
9import pandas as pd
10import matplotlib.pyplot as plt
11from sklearn.linear_model import ElasticNet
12 
13plt.rcParams['figure.dpi'] = 100
14plt.rcParams['savefig.dpi'] = 130
15plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
16plt.rcParams['axes.unicode_minus'] = False
17 
18BASE_DIR = os.path.dirname(os.path.abspath('__file__')) if '__file__' in dir() else os.getcwd()
19DATA_DIR = os.path.join(BASE_DIR, 'data')
20RESULTS_DIR = os.path.join(BASE_DIR, 'results')
21FIGURES_DIR = os.path.join(BASE_DIR, 'figures')
22for d in (DATA_DIR, RESULTS_DIR, FIGURES_DIR):
23 os.makedirs(d, exist_ok=True)
每月截面股票数2010-01 ~ 2019-11
讨论Zou & Hastie 2005, JRSS-B

2.Elastic Net 的数学动机

L1 选变量、L2 抗共线,弹性网在两者之间取得最优折中。

在高维回归中(p 与 n 同阶甚至 p > n),普通最小二乘(OLS)的方差爆炸, 需要通过正则化来约束系数空间。两种经典惩罚各有优劣:

  • Ridge(L2):将所有系数均匀收缩向零,但不会精确置零—— 无法做变量选择。优点是在预测变量高度相关时表现稳定。
  • Lasso(L1):可以将部分系数精确压为零,实现自动变量选择。 但当多个预测变量高度相关时,Lasso 倾向于随机选取组内一个变量而丢弃其余(Zou & Hastie 2005), 且在 p > n 时最多只能选出 n 个变量。

弹性网通过凸组合 L1 与 L2 惩罚,同时获得两者的优势。 目标函数中的 负责产生稀疏性(变量选择), 而 使目标函数严格凸, 保证解的唯一性,并通过分组效应让相关变量获得相近的系数。

从优化几何的角度看,弹性网的约束域是 L1 球与 L2 球的交集—— 一个介于菱形(Lasso)和圆形(Ridge)之间的「圆角菱形」。 这种形状既保留了 L1 在坐标轴上的尖角(产生稀疏解), 又避免了纯 L1 约束域的非光滑边界导致的解不稳定。

弹性网目标函数

:响应向量(下月收益)

:设计矩阵(因子值)

:待估系数向量

:总正则化强度

:L1/L2 混合比例

特殊情形

→ Lasso(纯 L1)

→ Ridge(纯 L2)

→ 本实验设定

源码elastic_net_pipeline.ipynb · cell 2–4

3.数据导入与探查

面板数据结构:每行 = 某月某股票的因子快照 + 下月收益标签。

原始数据集 CHN_sample_data.csv 包含 285,283 行 × 68 列。每行是「某月某只股票」的一条记录,列包括: 股票代码 stkcd、月份标识 Dates(如 201001 表示 2010 年 1 月)、 下月已实现收益 y,以及 65 个因子特征。

将非特征列(股票代码、日期、标签)排除后,剩余 65 列即为预测变量。 这些因子涵盖估值(BM、EP)、盈利(ROE、ROA)、动量(mom1m、mom6m、mom12m)、 流动性(dolvol)、波动率(retvol、idiovol)、规模(size、mv)等多个维度。

数据跨越 119 个月(2010-01 至 2019-11),每月截面股票数从 1,434 到 3,354 不等, 反映了 A 股市场在此期间的扩容趋势。月度截面的不等长意味着每个滚动窗口的 训练样本量不同,但弹性网对样本量变化具有较好的鲁棒性。

总行数
285 283
股票×月
总列数
68
含 stkcd/Dates/y
特征维度
65
p = 65
月份跨度
119
≈ 10 年
elastic_net_pipeline.ipynb · cell 2–4
1DATA_FILE = os.path.join(DATA_DIR, 'CHN_sample_data.csv')
2whole_data = pd.read_csv(DATA_FILE)
3print(f'Loaded shape={whole_data.shape}')
4 
5Xtodrop = ['stkcd', 'Dates', 'y']
6feature_cols = [c for c in whole_data.columns if c not in Xtodrop]
7print(f'特征数: {len(feature_cols)}')
8 
9all_month_list = sorted(whole_data['Dates'].drop_duplicates().tolist())
10month_counts = whole_data.groupby('Dates').size()
11print(f'月份数: {len(all_month_list)} 起止: {all_month_list[0]} ~ {all_month_list[-1]}')
12print(f'每月股票数 平均={month_counts.mean():.0f} 最小={month_counts.min()} 最大={month_counts.max()}')
elastic_net_pipeline.ipynb · cell 5 (数据探查)
1preview = whole_data.head(1000).copy()
2preview.to_csv(os.path.join(RESULTS_DIR, 'data_preview_1000rows.csv'), index=False)
3 
4y_stats = whole_data['y'].describe().to_dict()
5print('y 统计:', {k: round(v,4) for k,v in y_stats.items()})
6 
7fig, ax = plt.subplots(figsize=(8,4))
8ax.hist(whole_data['y'], bins=80, color='#4C78A8', edgecolor='white')
9ax.set_title('Distribution of next-month return (y)')
10ax.set_xlabel('y'); ax.set_ylabel('count')
11fig.tight_layout()
12fig.savefig(os.path.join(FIGURES_DIR, '01_y_distribution.png'))
13plt.show()
数据预览8 行 · 9/68
DatesstkcdyACCBMROEmom1mdolvolsize
20100120.00960.55270.08340.57480.12740.87780.1126
20100150.03710.47890.06570.53030.15500.50230.0058
20100160.04220.68610.08090.58140.14070.43360.0058
20100190.08440.53790.07420.57440.20310.79490.0125
201001110.02670.49580.08380.57560.16810.36300.0013
201001120.06900.48470.08740.57950.18660.61310.0126
201001140.02920.48230.06740.58040.10680.33290.0029
201001160.07020.49340.10940.54990.19910.46850.0051
完整数据集 285,283 行 × 68 列 · 显示部分代表性列
源码elastic_net_pipeline.ipynb · cell 5

4.窗口内 Min-Max 归一化

在每个滚动窗口内部统一缩放,兼顾一致性与信息隔离。

归一化函数接收一个 DataFrame 和一组「不归一」的列名。对于弹性网而言, 特征缩放至关重要:L1 惩罚对系数的绝对值施加约束,如果特征量纲不同, 量纲大的变量会被过度惩罚。Min-Max 将所有特征映射到 [0, 1] 区间, 使得惩罚项对每个特征的作用力度可比。

逐列计算极值范围。当某列在当前窗口内取值完全相同(range = 0)时, 直接置零——这种情况偶尔出现在某些因子在特定时段内缺乏变异的场景中, 置零等价于告诉模型「该特征在此窗口内无信息量」。

标准的 min-max 变换:x′ = (x − min) / (max − min)。 变换后每个特征的最小值为 0、最大值为 1,中间值按比例线性映射。

elastic_net_pipeline.ipynb · cell 5 (Norm)
1def Norm(in_df, no_Norm):
2 op_df = in_df.copy()
3 for col in op_df.columns:
4 if col in no_Norm:
5 continue
6 col_max = op_df[col].max()
7 col_min = op_df[col].min()
8 rng = col_max - col_min
9 if rng == 0:
10 op_df[col] = 0.0
11 else:
12 op_df[col] = (op_df[col] - col_min) / rng
13 return op_df
源码elastic_net_pipeline.ipynb · cell 7–8

5.滚动训练 / 验证 / OOS 窗口

每次取 24 个月训练、12 个月验证、1 个月样本外,向前滚动 83 次。

定义窗口参数:训练 24 个月、验证 12 个月、OOS 1 个月。START = 36 表示从第 37 个月起 才有完整的训练 + 验证 + OOS 窗口可用。

按当前索引 i 切出三段时间窗口:训练集取 i 之前的 24 个月,验证集紧接着 12 个月, OOS 就是第 i 个月本身。三段在时间上严格不重叠、单调递增。

从面板数据中按月份筛选出对应子集,再分离特征矩阵 X 和标签 y。Xtodrop 排除了 股票代码、日期和标签列,确保只有 65 个因子进入模型。

调用 EN_window(...) 完成本窗口的 5-α 网格搜索 + OOS 预测,结果追加到列表中,循环继续向前滚动。

月份总数
119
2010-01 ~ 2019-11
滚动 OOS 月
83
窗口数
OOS 样本
217 018
跨股票 × 月
特征数
65
月度因子
elastic_net_pipeline.ipynb · cell 7–8
1TRAIN_M = 24
2TEST_M = 12
3OOS_M = 1
4START = TRAIN_M + TEST_M + OOS_M - 1 # = 36
5 
6for i in range(START, len(all_month_list)):
7 train_months = all_month_list[i-TEST_M-TRAIN_M : i-TEST_M]
8 test_months = all_month_list[i-TEST_M : i]
9 oos_month = all_month_list[i]
10 
11 train_data = whole_data[whole_data['Dates'].isin(train_months)]
12 test_data = whole_data[whole_data['Dates'].isin(test_months)]
13 oos_data = whole_data[whole_data['Dates'] == oos_month]
14 
15 X_train = train_data.drop(columns=Xtodrop); y_train = train_data['y'].values
16 X_test = test_data.drop(columns=Xtodrop); y_test = test_data['y'].values
17 X_oos = oos_data.drop(columns=Xtodrop)
18 
19 en_result = EN_window(X_train, y_train, X_test, y_test, X_oos, test_data, oos_data)
20 en_op.append(en_result)
elastic_net_pipeline.ipynb · cell 9–10 (汇总)
1# 汇总所有窗口的调参预测
2tuning_pred = pd.concat([r[0] for r in en_op], ignore_index=True)
3tuning_pred['Dates'] = [datetime.datetime(year=int(x//100), month=int(x%100), day=28)
4 for x in tuning_pred['Dates']]
5tuning_pred = tuning_pred.sort_values(['AlphaValue','Dates','stkcd']).reset_index(drop=True)
6print('tuning_pred shape:', tuning_pred.shape) # (1085090, 6)
7 
8# 汇总最优 alpha 的预测
9best_pred = pd.concat([r[1] for r in en_op], ignore_index=True)
10best_pred['Dates_int'] = best_pred['Dates'].astype(int)
11best_pred['Dates'] = [datetime.datetime(year=int(x//100), month=int(x%100), day=28)
12 for x in best_pred['Dates_int']]
13best_pred = best_pred.sort_values(['Dates','stkcd']).reset_index(drop=True)
14print('best_pred shape:', best_pred.shape) # (217018, 7)
15 
16# 每个窗口选出的最优 alpha 记录
17best_alpha_log = pd.DataFrame({
18 'Dates_int': all_month_list[START:],
19 'BestAlpha': [r[1]['BestAlpha'].iloc[0] for r in en_op],
20 'TestR2' : [r[1]['TestR2'].iloc[0] for r in en_op],
21})
滚动窗口示意拖动滑条改变当前 OOS 月
i = 66训练 2012-072014-06验证 2014-072015-06OOS 2015-07
源码elastic_net_pipeline.ipynb · cell 6

6.弹性网训练函数与 α 网格搜索

在 5 个对数等距的正则化强度上逐一拟合,用验证集 R² 选出最优 α。

正则化强度 α(sklearn 中的 alpha 参数) 在 5 个对数等距点上搜索:10⁻⁶, 10⁻⁵, 10⁻⁴, 10⁻³, 10⁻²。l1_ratio = 0.5 表示 L1 与 L2 惩罚各占一半权重。 在 sklearn 的参数化中,弹性网的目标函数为:

其中 α 控制总惩罚强度,ρ(即 l1_ratio)控制 L1 与 L2 的相对比例。 α 越大,系数被压缩得越厉害;ρ = 0.5 意味着 L1 和 L2 惩罚等权混合。

对每个候选 α,用训练集拟合模型,然后在验证集上计算预测 R²。 这里的 R² 定义为:

注意分母是 Σy²(而非 Σ(y − ȳ)²),这是金融文献中常用的「无截距 R²」, 衡量模型相对于「预测为零」这一 null model 的改进程度。 当 R² < 0 时,说明模型预测还不如直接预测零。

同时记录每个 α 下的 OOS 预测值和系数向量。系数向量coef_records[a]是一个以特征名为索引的 Series,后续用于分析因子重要性和稀疏度。

选出验证 R² 最高的 α 作为本窗口的最优正则化强度,用该 α 重新拟合并生成 「最优预测」记录。函数返回四个对象:全部 α 的调参预测、最优预测、系数字典、 以及各 α 的验证 R²。

α 候选数
5
对数等距
l1_ratio
0.5
L1 = L2
max_iter
2 000
坐标下降
elastic_net_pipeline.ipynb · cell 6 (EN_window)
1ALPHAS = [1e-6, 1e-5, 1e-4, 1e-3, 1e-2]
2L1_RATIO = 0.5
3 
4TRAIN_M = 24
5TEST_M = 12
6OOS_M = 1
7START = TRAIN_M + TEST_M + OOS_M - 1
8 
9def EN_window(X_train, y_train, X_test, y_test, X_oos, test_data, oos_data):
10 test_data = test_data.copy()
11 tune_records = []
12 coef_records = {}
13 test_r2 = []
14 for a in ALPHAS:
15 m = ElasticNet(l1_ratio=L1_RATIO, alpha=a, fit_intercept=True,
16 max_iter=2000, tol=1e-4, random_state=123,
17 selection='cyclic')
18 m.fit(X_train, y_train)
19 yhat_test = m.predict(X_test)
20 test_data['rethat'] = yhat_test
21 r2 = 1 - np.sum((test_data['y'] - test_data['rethat'])**2) / np.sum(test_data['y']**2)
22 test_r2.append(r2)
23 oos_pred = oos_data.copy()
24 oos_pred['rethat'] = m.predict(X_oos)
25 rec = oos_pred[['Dates','stkcd','y','rethat']].rename(columns={'rethat':'yhat'})
源码elastic_net_pipeline.ipynb · cell 9

7.系数稀疏化与因子重要性

弹性网的 L1 惩罚将大量系数压缩为零,留下的非零系数即为模型选出的活跃因子。

将 83 个滚动窗口的系数结果展开为一张大表:每行是「某 α × 某 OOS 月」的 65 维系数向量。 总计 5 × 83 = 415 行。这张表让我们可以分析系数随时间和正则化强度的变化模式。

弹性网的稀疏性来自 L1 惩罚项 。 当 α 较小(如 10⁻⁶)时,惩罚几乎不起作用,65 个系数中有 64.7 个平均非零—— 模型接近 OLS。随着 α 增大到 10⁻²,平均仅剩 2.6 个非零系数,模型变得极度稀疏。

最优 α = 10⁻³ 时,平均 21/65 个因子活跃。这意味着模型自动从 65 个候选因子中 筛选出约三分之一作为有效预测变量。被选中的因子在不同窗口间有一定稳定性, 但也存在时变性——反映了市场因子溢价的非平稳特征。

elastic_net_pipeline.ipynb · cell 9 (系数汇总)
1coef_rows = []
2for r, oos_int in zip(en_op, all_month_list[START:]):
3 coefs = r[2]
4 for a, s in coefs.items():
5 row = s.to_dict()
6 row['AlphaValue'] = a
7 row['Dates'] = oos_int
8 coef_rows.append(row)
9all_coef = pd.DataFrame(coef_rows)
10all_coef = all_coef.sort_values(['AlphaValue','Dates']).reset_index(drop=True)
11print('all_coef shape:', all_coef.shape) # (415, 67)
elastic_net_pipeline.ipynb · cell 10–11 (稀疏度 & Top-20)
1# 稀疏度统计
2sparsity_records = []
3for alpha_v in ALPHAS:
4 sub = all_coef[all_coef['AlphaValue'] == alpha_v].drop(columns=['AlphaValue','Dates'])
5 nonzero_per_window = (sub != 0).sum(axis=1)
6 sparsity_records.append({
7 'AlphaValue': alpha_v,
8 'mean_nonzero': float(nonzero_per_window.mean()),
9 'min_nonzero': int(nonzero_per_window.min()),
10 'max_nonzero': int(nonzero_per_window.max()),
11 'total_features': int(sub.shape[1]),
12 })
13 
14# Top-20 因子重要性
15top20_records = []
16for alpha_v in ALPHAS:
17 sub = all_coef[all_coef['AlphaValue'] == alpha_v].drop(columns=['AlphaValue','Dates'])
18 abs_mean = sub.abs().mean().sort_values(ascending=False).head(20)
19 for rank, (feat, val) in enumerate(abs_mean.items(), 1):
20 top20_records.append({'AlphaValue': alpha_v, 'rank': rank,
21 'feature': feat, 'abs_mean_coef': val})
系数热图 (|β| 均值)前 20 个特征,按 α=10⁻³ 排序
dolvolvoltB_FPmom1mB_HSRNAprcB_DnROEretvolDApricedelaychmomROICageTGTBIB_FFmaxretstd_dolvol10⁻610⁻510⁻410⁻310⁻2
Top-20 因子重要性α = 10⁻3
非零系数均值α 越大越稀疏
源码elastic_net_pipeline.ipynb · cell 11–12

8.样本外评估与多空组合

从预测精度和经济价值两个维度检验弹性网的样本外表现。

样本外评估的核心指标是 MSFE(均方预测误差)和 OOS R²。MSFE 定义为:

其中 N = 217,018 是所有 OOS 月的预测总数。最优 α = 10⁻³ 将 MSFE 压到 0.0286, 相比 α = 10⁻⁶(接近 OLS)的 0.0585 降低了 51%。这说明适度的正则化 显著减少了过拟合导致的预测误差。

从经济价值角度,将每个 OOS 月的股票按预测值 ŷ 分成十组(decile), 做多预测收益最高的 Top 10%、做空最低的 Bottom 10%,等权持仓一个月。 这个多空组合的月均收益为 6.6%,年化 Sharpe 比率约 2.5, 82 个月累计收益达 130 倍——表明弹性网的预测具有显著的截面排序能力。

最优 α
10⁻³
MSFE 最低
MSFE
0.029
α = 10⁻³
Sharpe
≈ 2.5
年化
累计收益
130×
82 个月
elastic_net_pipeline.ipynb · cell 11–12 (评估)
1# 整体 MSFE 与 R²
2metric_rows = []
3for a, sub in tuning_pred.groupby('AlphaValue'):
4 msfe = float(np.sum((sub['yhat'] - sub['y'])**2) / len(sub))
5 r2 = float(1 - np.sum((sub['yhat'] - sub['y'])**2) / np.sum(sub['y']**2))
6 metric_rows.append({'AlphaValue': a, 'MSFE': msfe, 'R2_OOS': r2, 'n_pred': len(sub)})
7 
8# 月度 MSFE 分解
9monthly_msfe_records = []
10for a, sub in tuning_pred.groupby('AlphaValue'):
11 m = sub.groupby('Dates').apply(lambda g: float(np.sum((g['yhat']-g['y'])**2) / len(g)))
12 df_m = m.reset_index()
不同 α 下的 MSFE 与样本外 R²最优 α = 10⁻³
月度 MSFE 走势
月度均值 y vs ŷ (α = 10⁻³)最优 alpha 下的截面平均
每期最优 α 选择验证集 R² 选定
多空组合累计收益Top10% − Bottom10% 等权
讨论Hastie et al. 2020; Shen & Xiu 2024

9.SNR 视角:Ridge 为何优于 Lasso

信噪比与信号结构共同决定正则化方法的优劣——金融弱信号环境下 Ridge 胜出。

Hastie et al. (2020):SNR 决定方法优劣

Hastie, Tibshirani & Tibshirani (2020) 在系统仿真中发现:正则化方法的相对优劣 取决于信噪比(SNR)。SNR 衡量真实信号方差与噪声方差的比值。

  • 低 SNR(< 1):Lasso 的收缩特性有利于控制方差,优于 Best Subset
  • 高 SNR(> 2):Best Subset 的无偏估计更优,Lasso 的收缩成为负担
  • Relaxed Lasso:通过参数 γ 自适应调节收缩程度,在所有 SNR 水平上表现最优

金融月度收益的 SNR 通常远低于 0.05(PVE < 5%),处于论文测试范围的下界之外。 我们的 A 股数据估计 SNR ≈ 0.001–0.05,OOS R² 均为负值,印证了这一判断。

Shen & Xiu (2024):弱信号下 Ridge 优于 Lasso

修大成(Dacheng Xiu)与 Shen (2024) 的论文 "Can Machines Learn Weak Signals?" 提出了 一个关键的补充视角:方法选择不仅取决于 SNR,还取决于信号结构

  • Lasso 的稀疏假设失效:Lasso 假设真实模型是稀疏的(少数强预测变量)。 但金融收益的预测能力分散在大量弱信号中——没有单个因子足够强到能被可靠"选中"。
  • 变量选择在弱信号下不可靠:当所有信号都很弱时,Lasso 无法区分该保留哪些变量。 错误的选择导致 OOS 表现甚至不如零基准。
  • Ridge 的均匀收缩保留集体预测力:Ridge 保留所有变量但均匀缩小系数。 当预测能力来自众多微弱贡献的累加时,"不丢弃"是最优策略。

实验验证:Ridge Sharpe = 3.89

我们在相同的 A 股滚动窗口框架下(24 月训练 / 12 月验证 / 1 月 OOS), 对比了 Ridge、Lasso、Elastic Net 和 Relaxed Lasso 四种方法。 Ridge 的年化多空 Sharpe 达到 3.89,几乎是 Lasso (2.03) 的两倍。

  • 优势来源:Ridge 的月度多空波动率仅 6.55%(vs Lasso 8.42%、EN 10.05%)。 保留所有 65 个因子的集体信息使截面排序更加稳定。
  • 低 SNR 窗口中优势最大:在估计 SNR 最低的 25% 窗口中, Ridge 多空收益 10.9% vs Lasso 2.5%——信号越弱,变量选择越不可靠,Ridge 越有价值。
  • 点预测 vs 经济价值:Relaxed Lasso 的 MSFE (0.0294) 最低, 但 Ridge 的 Sharpe 最高。排序稳定性比点预测精度更重要。

实践建议

  • 多空策略 / 排序任务 → Ridge(最稳定的截面排序,最高 Sharpe)
  • 点预测 / 风险模型 → Relaxed Lasso(最低 MSFE,自适应收缩)
  • 因子筛选 / 可解释性 → Lasso(稀疏解,但牺牲经济价值)
  • Elastic Net → 不推荐(在两个维度上都不是最优)
信噪比定义
方差解释比例
Ridge 闭式解

:真实系数向量

:特征协方差矩阵

:噪声方差

:正则化强度

实验结果:4 种方法对比
方法SharpeMSFE非零
Ridge3.890.029865
Lasso2.030.030212.8
Relaxed1.570.029411.8
EN1.260.030215.7
源码

10.下载与致谢

本实验基于 Chapter 7 的中国 A 股月度面板数据集,核心方法参考:

  • 姜富伟, 唐国豪, 马甜. 金融与财务机器学习[M]. 北京: 机械工业出版社, 2024.
  • Zou, H. & Hastie, T. (2005). Regularization and variable selection via the elastic net. JRSS-B, 67(2), 301–320.
  • Gu, S., Kelly, B. & Xiu, D. (2020). Empirical asset pricing via machine learning. RFS, 33(5), 2223–2273.
  • Hastie, T., Tibshirani, R. & Tibshirani, R. (2020). Best subset, forward stepwise or lasso? Statistical Science, 35(4), 579–592.