关键词:#正则化 #Lasso #Ridge #过拟合 #机器学习
写在前面的话:上一篇文章我们聊了线性回归在量化中的应用,很多朋友私信我说:"维克哥,我按你说的用回归模型做了个选股策略,回测收益贼猛,一上实盘就翻车了。"——恭喜你,你遇到了量化交易的头号杀手:过拟合。今天这篇文章,我来聊聊怎么治这个"病"。
�� WHY:为什么正则化很重要?
一次真实的翻车经历
先讲一个我自己的故事。
2024年初,我花了两周时间构建了一个多因子选股模型。为了追求"完美"的回测表现,我恨不得把所有能想到的因子都塞进去——市盈率、市净率、换手率、成交量、波动率、RSI、MACD、布林带宽度……前前后后一共用了47个因子。
回测结果?惊艳。
年化收益38%,最大回撤只有8%,夏普比率2.1。我当时激动得差点跟领导提涨薪。
然后我把策略丢进模拟盘,跑了一个月——亏了4.7%。
又过了两个月,实盘账户回撤超过了12%。我盯着屏幕上绿油油的持仓,心里只有一个念头:这到底是怎么回事?
后来我花了整整一周复盘,才搞清楚问题出在哪里。那个回测里"完美"的模型,本质上做的事情是——把历史数据里的每一个噪音都当成了规律。
47个因子,200只股票,3年的数据,模型有几乎无限的自由度去"记住"过去发生了什么。但市场从来不是简单的重复。那些所谓的"规律",大部分只是数据里的随机波动。模型学得太好了,好到连噪音都学会了——这就是过拟合。
打个比方:你有个朋友,记忆力超群,能把每一期的彩票开奖号码背得滚瓜烂熟。你问他下一期开什么,他把过去100期的号码分析了一遍,告诉你:"根据我的分析,下一期一定是3、7、12、18、25。"你信了吗?肯定不会。因为他分析的完全是已经发生的事情,对未来没有任何预测能力。
我的那个模型,就是那个"背彩票号码的朋友"。
过拟合:量化策略的头号杀手
过拟合不是一个新问题。但在量化交易领域,它尤其致命。原因有三个:
第一,金融数据的信噪比极低。 图像识别里的数据(比如猫和狗的图片),信号是很强的——猫就是猫,狗就是狗。但金融数据里,真正的"规律"(信号)往往被大量的噪音淹没。你以为学到了规律,其实大概率只是学到了噪音。
第二,我们总想加更多因子。 做量化的人有一种本能的贪婪——总觉得多一个因子就能多一分alpha。从5个加到15个,从15个加到50个。每加一个因子,模型在训练集上的表现就会好一点点。但这"一点点"的代价是模型复杂度的爆炸式增长。
第三,回测环境太"友好"了。 回测时,你已经看到了所有的数据。模型可以从这些数据里"偷"到无数种组合方式。但在实盘中,你面对的是完全未知的未来数据。
怎么办?
有人会说:"那我少用几个因子呗。"——道理没错,但问题是,你怎么知道哪几个因子是真正有用的,哪几个是来捣乱的?
这就是今天的主角——正则化登场的时候了。
正则化是什么?一句话解释
如果用一句话来概括正则化的本质,我会说:
正则化就是给模型"立规矩"。
你可以把它想象成给一个天赋极高但极度自律不足的学生,请了一位严厉的家教。这个家教不让学生把所有时间都花在"死记硬背"上,而是要求学生抓重点、看大局、别钻牛角尖。
从数学角度说,正则化就是在模型的损失函数里加一个"惩罚项"。模型越复杂(参数越大、越多),惩罚就越重。这样一来,模型在"拟合数据"和"保持简单"之间就必须做一个权衡——而不能一味地去拟合数据。
接下来,我们来认识正则化家族的三位成员:Lasso、Ridge,以及它们的孩子——Elastic Net。
�� HOW:Lasso、Ridge、Elastic Net分别怎么做?
在正式介绍这三位之前,我要先讲一个比喻,帮大家建立一个直觉。
一个比喻:三种减肥方案
想象你是一家减肥中心的主教练,你的任务是帮100个学员减肥。你手里有很多"工具"——不同的饮食方案、运动计划、作息调整等等。你发现,学员的减肥效果和这些工具有关,但有些工具其实没什么用,甚至有害。
现在,你有三种管理策略:
策略A(Lasso):末位淘汰制。 每次复盘时,把效果最差的几个工具直接砍掉,永远不再使用。最后留下来的,都是真正有效的核心工具。简单粗暴,但效率极高。
策略B(Ridge):降权但不淘汰。 你不会完全抛弃任何一个工具,但对于那些效果不明显的工具,你会大幅减少它们的使用频率和影响力。每个工具都还在,但贡献度被重新分配了。
策略C(Elastic Net):混合制。 先砍掉一批明显没用的工具,然后对剩下的工具做降权处理。两个策略一起用。
这三种策略,对应的就是三种正则化方法。
Ridge回归:温柔的约束
核心思想
Ridge回归(也叫L2正则化)的核心思想是:我不消灭任何一个特征,但我让所有特征的系数都变小。
回到线性回归的语境。普通线性回归的公式是这样的:
Y = β₀ + β₁X₁ + β₂X₂ + ... + βₙXₙ
每个β就是对应特征的"权重"。普通回归的目标是让预测值和真实值之间的误差最小。
Ridge回归在这个基础上加了一条规矩:所有β的平方和不能太大。
换句话说,Ridge对"大系数"零容忍。如果某个特征的系数特别大(比如β₁=50),Ridge就会重重地惩罚它。模型为了减少惩罚,不得不把系数压低。
为什么这能防止过拟合?
因为过拟合的一个典型表现就是:某些特征的系数被放得特别大。 模型为了在训练集上多拟合那一点点精度,不惜让某个系数膨胀到不合理的程度。
Ridge就像是一个经验丰富的团队管理者。他不会因为某个员工(特征)在某次项目(训练集)上表现好,就给他无限大的权力(系数)。他会说:"你的贡献我认可,但权力要适度。"
这种"温和的收缩"有一个非常好的效果:所有特征都保留了,但那些不太重要的特征的系数会变得很小,接近于零但不等于零。模型的"方差"被显著降低了——也就是模型对训练数据的"过度敏感"被抑制了。
一个直觉理解
你见过那种特别"轴"的人吗?一旦他认定某个因素重要,就会把所有赌注都压在上面。Ridge的作用就是治这种"轴"——让模型不要太依赖任何一个特征,保持均衡。
Lasso回归:铁腕的抉择
核心思想
Lasso回归(也叫L1正则化)比Ridge狠多了。它的规矩是:所有β的绝对值之和不能太大。
听起来和Ridge差不多?区别在于惩罚方式。
Ridge惩罚的是β的平方(β²),Lasso惩罚的是β的绝对值(|β|)。
这个数学上的细微差别,带来了一个巨大的实际效果差异:
Lasso会把一些特征的系数直接压缩到零。
也就是说,Lasso不仅会压缩系数,还会自动做特征选择。那些没用的特征,Lasso会直接把它们的权重变成零——相当于宣布:"这个特征,我不要了。"
回到减肥的比喻
Lasso就是那个最狠的教练。他会拿出100种工具,逐一测试,然后把效果不达标的一律扔掉。最后可能只剩下20种真正有用的工具。
为什么Lasso能做到特征选择?
这涉及一个几何直觉,我用一种简化的方式来解释。
想象你在一个二维平面上(假设有两个特征X₁和X₂)。模型的损失函数在平面上画出来是一圈一圈的等高线(像山峰的地图)。普通回归的目标是找到等高线的最低点。
但Ridge和Lasso加了约束条件,相当于在这个平面上画了一个"禁区":
• Ridge画的禁区是一个圆形(因为β₁²+β₂²≤c,这是圆的方程)。
• Lasso画的禁区是一个菱形(因为|β₁|+|β₂|≤c,这是菱形的方程)。
关键点来了:等高线和禁区的交点就是最终的解。
圆形和等高线相交时,交点通常不会恰好落在坐标轴上(即β₁=0或β₂=0的位置)。
但菱形有尖角,而且尖角就在坐标轴上。等高线和菱形的交点,有很大的概率恰好落在尖角处——也就是某个β恰好等于零的地方。
这就是Lasso能把特征系数压到零的几何原因。
在量化中的实战意义
做量化选股的时候,你手里可能有100个因子。但真正有用的,可能就15-20个。问题是,你事先不知道是哪15-20个。
Lasso的价值就在于:它能自动帮你筛选。你把100个因子全部丢给Lasso,跑完之后,那些系数变成零的因子就被自动淘汰了。
这省去了大量的人工筛选工作。
Elastic Net:集大成者
为什么需要Elastic Net?
你可能会想:既然Lasso能做特征选择,那我直接用Lasso不就行了?
问题在于,Lasso有一个已知的缺陷:当特征之间存在相关性时,Lasso倾向于随机选择其中一个,把其他的都淘汰掉。
举个例子。假设你有两个因子:动量因子5日版和动量因子10日版。它们高度相关(本质上度量的是类似的东西),但5日版可能稍微更有用一点。Lasso在遇到这种情况时,可能会随机保留5日版而淘汰10日版——但10日版其实也包含了一些独立的信息。
更麻烦的是,如果你的特征数量大于样本数量(这在量化里很常见——因子多、时间跨度短),Lasso最多只能选出和样本数量一样多的特征。
Elastic Net的解决方案
Elastic Net的思路很直接:把Lasso和Ridge结合起来用。
它的惩罚项是L1惩罚和L2惩罚的加权混合:
惩罚 = α × (Lasso惩罚) + (1-α) × (Ridge惩罚)
其中α是一个需要你设定的超参数(通常在0到1之间)。
• 当α=1时,Elastic Net退化为纯Lasso。
• 当α=0时,Elastic Net退化为纯Ridge。
• 当α在0和1之间时,两者兼而有之。
实际效果
Elastic Net的好处是:
1. 继承了Lasso的特征选择能力——不重要的特征会被淘汰。
2. 继承了Ridge处理相关特征的能力——相关的特征不会被随机淘汰,而是被"组团"保留或淘汰。
3. 没有Lasso的样本数量限制——可以选出超过样本数量的特征。
对于量化场景来说,Elastic Net通常是最稳妥的选择。因为金融数据中的特征普遍存在相关性(比如各种技术指标之间、各种基本面因子之间),纯Lasso的随机选择行为可能让你丢掉有用的信息。
三种方法的对比总结
为了帮大家更好地理解三者的区别,我做了一个对比表:
| 维度 | 普通回归 | Ridge | Lasso | Elastic Net | | --- | --- | --- | --- | --- | | 惩罚类型 | 无 | L2(系数平方和) | L1(系数绝对值和) | L1 + L2 | | 能否做特征选择 | 不能 | 不能 | 能 | 能 | | 处理相关特征 | 不稳定 | 好(系数趋于均匀) | 差(随机选一个) | 好(组团保留) | | 系数结果 | 可能很大 | 小但不为零 | 部分为零 | 部分为零 | | 适用场景 | 特征少、无噪音 | 特征多但都有用 | 特征多、需筛选 | 特征多、相关性强 | | 需要调节的超参数 | 无 | λ(惩罚力度) | λ(惩罚力度) | λ + α |
一个生活化的类比总结
把三种正则化方法想象成"收拾房间"的三种方式:
• Ridge:你不舍得扔任何东西,但会把每样东西都摆放得更紧凑,让房间看起来整洁一些。所有东西都还在,只是占的空间更小了。
• Lasso:你大刀阔斧地扔东西。打开衣柜,一年没穿的?扔!没用的杂物?扔!最后房间里只剩下真正有用的东西。但偶尔可能会误扔一些其实有用的东西。
• Elastic Net:你先用Lasso的方式扔一批明显没用的,然后再用Ridge的方式把剩下的东西整理紧凑。两步走,既精简又不会误删太多。
WHAT:用了正则化之后能得到什么?
预期效果
说完了原理,大家最关心的问题来了:用了正则化之后,我的策略到底能改善多少?
我没有办法给你一个精确的数字,因为不同的策略、不同的市场环境下效果差异很大。但我可以分享一些我自己的实证经验和学界的研究结论。
效果一:实盘表现和回测表现的差距显著缩小
这是正则化最直接的效果。
我之前那个47因子的模型,回测年化38%、实盘亏损——典型的过拟合。后来我用Elastic Net做了特征筛选和系数收缩,因子从47个减少到了18个,回测年化降到了22%。但实盘跑了半年,年化实际做到了19%。
回测和实盘的差距,从将近40个百分点缩小到了3个百分点。
这才是真正有意义的收益。
效果二:模型更稳定,回撤更可控
过拟合模型的另一个问题是"脆弱"——市场稍微一变化,模型就崩了。正则化后的模型,因为系数被约束在一个合理的范围内,对市场变化的适应能力更强。
我自己的感受是,加了正则化之后,策略的最大回撤平均缩小了20%-35%。这不只是数字上的变化,这是你晚上能不能睡好觉的区别。
效果三:因子筛选节省研究时间
Lasso和Elastic Net的特征选择功能,相当于一个自动化的"因子预筛"工具。
以前我手动筛选因子,流程是这样的:
1. 算每个因子的IC值
2. 做分层回测
3. 看因子之间的相关性
4. 手动决定保留哪些
整个过程一个因子可能要花半天时间。100个因子,光筛选就要一两个月。
用Lasso/Elastic Net,跑一次回归可能就几分钟,直接告诉你哪些因子有用、哪些没用。然后你再对保留下来的因子做深入分析就行了。
实战中的注意事项
正则化不是银弹,用不好也会出问题。以下是几个我踩过的坑:
坑1:惩罚力度(λ)的选择
λ决定了惩罚的力度。λ太小,等于没怎么正则化,过拟合还是存在。λ太大,模型被压得太狠,欠拟合——连真正的规律都学不到了。
怎么选择λ?最常用的方法是交叉验证。
简单来说,就是把数据分成K份(比如10份),轮流用其中9份训练、1份验证,看看不同的λ下模型的验证效果如何。选验证效果最好的那个λ。
在量化的场景中,我建议用时间序列交叉验证(也叫Walk-Forward验证),而不是普通的K-Fold交叉验证。因为金融数据有时间依赖性,不能随机打乱。
坑2:数据标准化
这是一个很多人忽略但非常重要的点。
Ridge和Lasso的惩罚项是基于系数大小的。如果你的特征量纲不统一——比如一个因子的值域是0-1,另一个因子的值域是100-10000——那值域大的因子对应的系数天然就小,惩罚对它的影响也就小。这显然是不公平的。
所以,在使用正则化之前,一定要对所有特征做标准化处理(通常是Z-score标准化:减去均值,除以标准差)。
坑3:不是越多正则化越好
有些朋友一听正则化能防过拟合,就把惩罚力度调到最大,恨不得让所有系数都为零。这就从一个极端走到了另一个极端——欠拟合。
好的模型应该在"拟合不足"和"拟合过度"之间找到一个平衡点。正则化的目标不是让模型越简单越好,而是让模型恰到好处地简单。
坑4:别忽视特征工程
正则化能帮你筛选特征,但它不能创造特征。如果你输入的100个因子本身就是垃圾,那正则化最多帮你选出"没那么垃圾"的几个——但结果依然不会好。
好的特征工程 + 正则化 = 好策略。
差的特征工程 + 正则化 = 矮子里拔将军。
所以,花时间在特征工程上,永远值得。
一个完整的实战流程
为了让大家对正则化的实际应用有更清晰的认知,我把自己的实战流程分享一下:
Step 1:因子池构建
先根据你的研究和经验,构建一个包含30-80个因子的候选池。不要贪多,也不要太少。
Step 2:数据预处理
• 对所有因子做缺失值处理(填充或删除)
• 做极值处理(winsorize,通常用1%和99%的分位数)
• 做标准化处理(Z-score)
• 对因子做中性化(行业和市值中性化)
Step 3:用Elastic Net做因子筛选
• 设定一个λ的范围(比如0.001到10,取50个值)
• 设定α=0.5(L1和L2各占一半,这是一个比较好的起点)
• 用Walk-Forward交叉验证选择最优的λ
• 观察哪些因子的系数被压缩到零(被淘汰),哪些被保留
Step 4:模型检验
• 用保留下来的因子重新拟合模型
• 检查模型的残差是否符合正态分布
• 检查模型在不同时间段的表现是否稳定
• 对比正则化前后的回测指标变化
Step 5:实盘验证
• 先在模拟盘上跑至少1-3个月
• 对比模拟盘表现和回测表现的差异
• 如果差异在可接受范围内(比如年化差距小于5个百分点),再考虑上实盘
几个进阶技巧
如果你已经掌握了基本用法,这里有几个进阶技巧分享给大家:
技巧1:自适应Lasso
标准的Lasso对所有特征一视同仁。但自适应Lasso(Adaptive Lasso)会先给每个特征一个初始权重(通常用Ridge的系数作为初始权重),然后对系数大的特征施加较小的惩罚,对系数小的特征施加较大的惩罚。
这样做的好处是:真正重要的特征不太容易被误淘汰。
技巧2:分组Lasso(Group Lasso)
如果你的因子是按类别分组的(比如基本面因子一组、技术面因子一组、情绪面因子一组),Group Lasso可以以"组"为单位做特征选择——要么整组保留,要么整组淘汰。
这在某些场景下更符合逻辑。
技巧3:动态调整正则化力度
市场不是一成不变的。在波动率较高的市场环境下,你可能需要更强的正则化(更大的λ)来抑制过拟合。在市场趋势明确的时期,可以适当放松正则化。
我见过有人用GARCH模型来动态调整λ——波动率高时λ增大,波动率低时λ减小。效果确实比固定λ要好一些。
写在最后:简单,是最高级的复杂
写完这篇文章,我想回到最开始的那个问题:为什么我们费尽心力构建的模型,在实盘中表现得一塌糊涂?
答案是:我们太贪心了。
我们想让模型拟合每一个数据点,想让策略抓住每一个alpha来源,想让回测曲线尽可能完美。但这种"贪心"的代价,是模型变成了一个只会"背书"的书呆子——在考试中(回测)表现完美,但遇到新题型(新数据)就傻了。
正则化的哲学,本质上是一种"克制"的智慧。
它告诉我们:不是所有的信息都值得学习。有时候,遗忘比记忆更重要。
Lasso教我们学会放弃,Ridge教我们学会克制,Elastic Net教我们在放弃与克制之间找到平衡。
这三种方法,没有哪个绝对最好。关键是理解你面对的数据和问题,选择最合适的工具。
在我的日常工作中,Elastic Net是我使用最多的工具。因为它最"全能"——既能筛选特征,又能处理特征相关性。但我也不会因此忽视Ridge和Lasso的价值。在某些特定的场景下,它们可能更合适。
最后,送给大家一句话,也是我自己贴在显示器旁边的:
"一个好的量化模型,不在于它能解释多少过去,而在于它能预测多少未来。"
共勉。
读完这篇文章,你可以立即开始做以下事情:
1. 审视你当前的模型:你的因子有多少个?回测和实盘的差距有多大?如果差距超过10个百分点,很可能存在过拟合。
2. 学习使用sklearn中的正则化工具:Python的sklearn库提供了Ridge、Lasso、ElasticNet三个现成的类,接口非常简单,十几行代码就能跑起来。
3. 实现Walk-Forward交叉验证:不要用普通的K-Fold交叉验证来选择超参数。金融数据有时间序列结构,必须用时序验证。
4. 记住数据标准化:在使用正则化之前,一定要做Z-score标准化。这一步不能省略。
5. 从小规模实验开始:先在你现有的因子池上跑一次Elastic Net,看看有多少因子被淘汰。这个结果本身就能给你很多启发。
下一篇预告:正则化帮我们筛选了因子,但因子之间的非线性关系怎么捕捉?下一篇文章,我们将聊聊"树模型"——从决策树到随机森林到XGBoost,看看这些非线性武器如何在量化中发挥作用。敬请期待!
免责声明:本文仅为个人学习笔记分享,不构成任何投资建议。量化交易有风险,策略过往表现不代表未来收益。