第 5 章 · 02 L2 正则减少零权重


文档摘要

第 5 章 · 02 L2 正则减少零权重 本节摘要:本节讲均值-方差优化的一个通病——零权重过多,以及 PyPortfolioOpt 的解药: 。标准 maxsharpe 或 minvolatility 的输出往往把大量资产权重压到 0(「最优」组合只挑几只资产),这在样本内最优,但样本外常常欠分散、欠稳健。L2 正则在目标函数里加一个 惩罚项,鼓励权重分布更均匀——形式上与机器学习的 L2 正则完全一致(只是目的相反:ML 用它让权重小,这里用它让权重大)。本节拆解 L2 正则的数学形式、源码实现、γ 参数的调参经验,以及 cookbook 3 里「交易成本 + L2 正则」的完整调参案例,展示 γ 从默认 1 调小到 0.05 时权重如何从「过度均匀」回归「合理分散」。

第 5 章 · 02 L2 正则减少零权重

本节摘要:本节讲均值-方差优化的一个通病——零权重过多,以及 PyPortfolioOpt 的解药:objective_functions.L2_reg。标准 max_sharpe 或 min_volatility 的输出往往把大量资产权重压到 0(「最优」组合只挑几只资产),这在样本内最优,但样本外常常欠分散、欠稳健。L2 正则在目标函数里加一个 γ wᵀ w 惩罚项,鼓励权重分布更均匀——形式上与机器学习的 L2 正则完全一致(只是目的相反:ML 用它让权重小,这里用它让权重大)。本节拆解 L2 正则的数学形式、源码实现、γ 参数的调参经验,以及 cookbook 3 里「交易成本 + L2 正则」的完整调参案例,展示 γ 从默认 1 调小到 0.05 时权重如何从「过度均匀」回归「合理分散」。

内容来源:原项目源码 pypfopt/objective_functions.pypypfopt/base/_base_optimizer.py、文档 docs/MeanVariance.rst(L2 Regularisation 专节)、docs/UserGuide.rstcookbook/3-Advanced-Mean-Variance-Optimisation.ipynb,汉化并套用体系化模板。

学习目标

阅读完本节,你应当能够:

  1. 解释均值-方差优化零权重过多的成因与危害。
  2. 写出 L2 正则项 γ wᵀ w,理解它如何鼓励均匀分布。
  3. ef.add_objective(objective_functions.L2_reg, gamma=...) 加正则。
  4. 调节 γ 参数(默认 1,小池可起步;大池或要更多非零权重则调大)。
  5. 复述 ML 里 L2 与此处 L2 的目的差异

一、零权重过多的通病

均值-方差优化器有个让人头疼的特性:它倾向于把大多数资产权重压成 0。回顾第 1 章的 max_sharpe 输出:

GOOG: 0.0458 AAPL: 0.0674 FB: 0.2008 BABA: 0.0849 AMZN: 0.0352 GE: 0.0000 AMD: 0.0000 WMT: 0.0000 BAC: 0.0000 GM: 0.0000 T: 0.0000 UAA: 0.0000 SHLD: 0.0000 XOM: 0.0000 RRC: 0.0000 BBY: 0.0159 MA: 0.3287 PFE: 0.2039 JPM: 0.0000 SBUX: 0.0173

20 只资产里只有 8 只权重非零,其余 12 只被压成 0。这在样本内是「数学最优」,但实务上有问题:

  1. 分散不足:只押几只资产,集中风险高。
  2. 样本外欠稳健:docs/MeanVariance.rst 引用研究:零权重过多的组合样本外表现欠佳,因为「哪些资产被压零」对输入极度敏感。
  3. 不可投资:某些机构要求组合至少含 N 只资产(流动性、合规)。

二、L2 正则的数学

docs/MeanVariance.rst 的 L2 专节给出公式。以最小方差目标为例:

原目标: minimize wᵀ Σ w 加正则后: minimize wᵀ Σ w + γ wᵀ w

wᵀ w = Σ w_i² 是权重平方和。这个惩罚项的几何直觉:

  • 权重越集中(如某资产 100%),wᵀ w 越大(= 1² = 1)。
  • 权重越均匀(如 N 只等权),wᵀ w 越小(= N × (1/N)² = 1/N)。

因此最小化 wᵀ w 等价于「鼓励均匀分布」——加这个项会惩罚集中,促使优化器把权重分散到更多资产。

💡 为何叫 L2:因为这个惩罚项 wᵀ w = Σ w_i² 是权重向量的 L2 范数的平方。在机器学习里,L2 正则是 λ‖w‖²,形式完全一致——但目的相反:ML 里用它让权重小(防过拟合),这里用它让权重大且均匀(防过度集中)。文档明确指出这个「同形不同目的」的微妙之处。

三、源码逐行解析

打开 pypfopt/objective_functions.py,定位 L2_reg(源码 138-162 行):

def L2_reg(w, gamma=1): r""" L2 regularisation, i.e γ||w||^2, to increase the number of nonzero weights. Example:: ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.L2_reg, gamma=2) ef.min_volatility() """ L2_reg = gamma * cp.sum_squares(w) return _objective_value(w, L2_reg)

极其简洁:

  1. gamma(默认 1):正则强度。增大 γ → 更强均匀化、更多非零权重。
  2. cp.sum_squares(w):cvxpy 原子函数,等于 Σ w_i²,即 wᵀ w。这是凸函数(平方和),符合 DCP。
  3. gamma * cp.sum_squares(w):整个正则项是 γ 加权的权重平方和。
  4. _objective_value:同样的双模式辅助函数——w 是 ndarray 时返回数值,是 cp.Variable 时返回表达式。

四、加正则的机制

add_objective 把正则项累加到主目标上。源码(_base_optimizer.py 347-369 行):

def add_objective(self, new_objective, **kwargs): if self._opt is not None: raise InstantiationError( "Adding objectives to an already solved problem might have unintended consequences. ..." ) self._additional_objectives.append(new_objective(self._w, **kwargs))

求解时,主目标方法(min_volatility/efficient_risk 等)会把它加进去:

# min_volatility 源码片段 self._objective = objective_functions.portfolio_variance(self._w, self.cov_matrix) for obj in self._additional_objectives: self._objective += obj # 累加额外目标

所以加 L2 正则后的实际优化问题是:

minimize wᵀ Σ w + γ wᵀ w (以 min_volatility 为例) subject to sum(w) = 1, 0 ≤ w ≤ 1

⚠️ 与 max_sharpe 不兼容:回顾第 4 章第 02 节,max_sharpe 做变量替换 y = κw 后,额外目标没有按 κ 缩放,会发警告并可能失效。若要 L2 正则,改用 min_volatilityefficient_riskefficient_returnmax_quadratic_utility——它们不做变量替换,与额外目标完全兼容。

五、γ 参数的调参

γ 是 L2 正则唯一的超参数,需要调。docs/MeanVariance.rstnote 给出经验:

实务上,γ 必须调到达到你想要的正则强度。但若资产池较小(少于 20 只),gamma=1 是个好起点。对更大的资产池,或想要更多非零权重,增大 γ。

γ 取值 行为 适用
γ = 0 无正则(原始问题)
γ = 0.01~0.1 轻微正则,接近原始 想保留集中度
γ = 1(默认) 中等正则 小池(<20 资产)起步
γ = 5~20 强正则,接近等权 大池或要高度分散

六、用法示例

6.1 基本用法

from pypfopt import EfficientFrontier, objective_functions ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.L2_reg, gamma=1) ef.max_sharpe() # 注意:这里会有警告,见下方说明

README 的官方示例确实用 max_sharpe + L2,但会触发警告。更稳妥的是:

ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.L2_reg, gamma=1) ef.min_volatility() # 与额外目标完全兼容

6.2 与 efficient_risk 配合

ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.L2_reg, gamma=1) ef.efficient_risk(target_volatility=0.20)

6.3 扫 γ 看权重变化

for gamma in [0.01, 0.1, 1, 5, 10]: ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.L2_reg, gamma=gamma) ef.min_volatility() nonzero = sum(v > 1e-4 for v in ef.clean_weights().values()) print(f"γ={gamma}: {nonzero} 个非零权重")

七、cookbook 3 的完整调参案例

cookbook 3 提供了一个教科书级的 L2 调参案例,展示 γ 从大到小的权衡。背景:已有等权初始组合,想优化但考虑交易成本。

7.1 起点:交易成本 + max_sharpe-like 优化

initial_weights = np.array([1/len(tickers)] * len(tickers)) ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.transaction_cost, w_prev=initial_weights, k=0.001) ef.min_volatility() weights = ef.clean_weights()

结果:4 只资产权重为 0——不够分散。

7.2 加 L2(默认 γ=1)

ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.transaction_cost, w_prev=initial_weights, k=0.001) ef.add_objective(objective_functions.L2_reg) # gamma=1 默认 ef.min_volatility()

结果:过度均匀化——权重几乎回到等权,失去了优化的意义。

7.3 调小 γ=0.05

ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.transaction_cost, w_prev=initial_weights, k=0.001) ef.add_objective(objective_functions.L2_reg, gamma=0.05) # 减弱正则 ef.min_volatility() ef.portfolio_performance(verbose=True)

结果:合理平衡——组合相对均衡,同时对 JD(高分散价值的资产)仍给了显著权重。

💡 调参心法:γ 不是「越大越好」也不是「越小越好」,而是找到「分散度合适、又保留优化价值」的平衡点。cookbook 3 的案例展示了完整的调参弧线:从无正则(欠分散)→ γ=1(过均匀)→ γ=0.05(刚好)。这种「先加足再往回调」是常见的调参套路。

八、与其他正则/目标的搭配

L2 正则可以与多个目标叠加:

主目标 与 L2 兼容? 备注
min_volatility 最常搭配
efficient_risk
efficient_return
max_quadratic_utility
max_sharpe 警告(变量替换) 可能失效,避免

还可与交易成本、行业约束同时用:

ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.L2_reg, gamma=0.1) ef.add_objective(objective_functions.transaction_cost, w_prev=w_prev, k=0.001) ef.add_sector_constraints(sector_mapper, sector_lower, sector_upper) ef.min_volatility()

所有额外目标与约束在求解时同时生效。

本节要点回顾

  1. 通病:均值-方差优化零权重过多,样本内最优但样本外欠稳、不可投资。
  2. 数学:加 γ wᵀ w 到主目标,惩罚集中、鼓励均匀——形式同 ML 的 L2,但目的相反(让权重大且均匀)。
  3. 源码:L2_reg(w, gamma=1) = gamma * cp.sum_squares(w),凸函数。
  4. 加法机制:add_objective 累加到 _additional_objectives,求解时 += 到主目标。
  5. γ 调参:默认 1,小池起步;大池或要更多非零权重则增大;想保留集中则减小;cookbook 3 展示了 γ=1 过均匀→γ=0.05 刚好的弧线。
  6. 兼容性:与 min_volatility/efficient_risk/efficient_return/max_quadratic_utility 兼容;与 max_sharpe 有警告,避免。

下一节是本章最后一节——自定义目标函数,看如何写一个凸目标(或非凸目标)并传给优化器。


发布者: 作者: 灏天文库 转发
评论区 (0)
U