因子权重矩阵处理-因子权重收缩Shrinkage算法的探索

因子权重收缩Shrinkage算法,旨在基于历史表现计算的因子权重,向一个等权先验进行压缩。

这里示例因子权重收缩算法实现,并在代码层面逐层拆解,然后进一步分析背后的金融逻辑。

1 Shrinkage算法

如下代码实现了一个在量化金融领域非常经典的因子权重收缩Shrinkage算法。

这段代码是用统计收缩(Statistical Shrinkage)手段,将量化研究员对因子历史表现的狂热追崇,

强行拉回到一视同仁理性基准线上,防止多因子模型过拟合、提升策略稳健性的工业级标准实践。

复制代码
def shrink_weights_to_equal(
    weight_matrix: pd.DataFrame,
    lam: float,
) -> pd.DataFrame:
    """
    Row-wise shrinkage of factor weights toward the equal-weight design prior.

        w(T) = lam * w_icir(T) / sum|w_icir(T)|  +  (1 - lam) * prior(T)

    where prior(T) spreads 1 equally over the factors *supported* on that row
    (non-NaN and non-zero weights) and is 0 elsewhere. For a dense rolling-ICIR
    matrix the prior is the uniform +1/n "design sign" (all factors in this
    library are constructed so higher = expected better); for a top-k selection
    matrix (zeros = not selected) the prior is +1/k over the selected factors
    only, so unselected factors stay out.

    Rationale: rolling ICIR estimates are noisy and their signs flip in and
    out of regimes; convex shrinkage toward the prior lets a factor deviate
    from (or flip against) its design direction only when the trailing
    evidence is strong enough. lam=1 reproduces the raw rolling weights,
    lam=0 gives the pure equal-weight prior. All-NaN rows (warm-up) and
    all-zero rows (no signal / no support) are preserved as NaN.
    """
    if not 0.0 <= lam <= 1.0:
        raise ValueError("lam must be in [0, 1]")
    w = weight_matrix.astype(float)
    row_abs = w.abs().sum(axis=1)
    wn = w.div(row_abs.where(row_abs > 1e-12), axis=0)

    support = w.notna() & (w.abs() > 1e-12)
    cnt = support.sum(axis=1)
    prior = support.astype(float).div(cnt.replace(0, np.nan), axis=0)

    return lam * wn + (1.0 - lam) * prior

2 代码逻辑分析

1)输入与参数校验

weight_matrix是行索引通常是时间点(Date) ,列索引是各个因子(Factors)

单元格数值代表该时点该因子的**原始权重(**例如基于滚动ICIR算出的权重)。

这里每个单元格是因子近期在全体股票上的整体效力,不是对某只股票的效力,它不含个股信息。

lam是收缩强度系数,取值范围 0, 11代表完全不收缩,0代表完全采用先验。

复制代码
if not 0.0 <= lam <= 1.0:
    raise ValueError("lam must be in [0, 1]")
w = weight_matrix.astype(float)

2)行内 L1 归一化

算每一行所有因子权重的绝对值之和。

将每个原始权重除以该行绝对值和,得到 wn

数学表达为

这里用的是绝对值之和,而非简单求和。

这意味着保留了权重的符号(做多/做空方向),同时将总杠杆(L1范数)标准化为 1。

1e-12 是为了防止除以 0。

复制代码
row_abs = w.abs().sum(axis=1)
wn = w.div(row_abs.where(row_abs > 1e-12), axis=0)

3)有效支持域与等权先验

support是一个布尔矩阵,标记了该时间点哪些因子是活跃有效的,即非空且权重绝对值不为 0。

cnt 统计每一行有效因子的个数 k。

prior 先验矩阵,对于每一行,将1平均分配给所有有效的因子(即权重为 1/k),无效因子则为 0。

数学表达:

若因子i有效

否则

若某行全部无效(cnt=0),则替换为 NaN 保留,避免除以零。

复制代码
support = w.notna() & (w.abs() > 1e-12)
cnt = support.sum(axis=1)
prior = support.astype(float).div(cnt.replace(0, np.nan), axis=0)

4)凸组合(Convex Combination)收缩

最终的收缩权重是归一化后的原始权重wn与等权先验prior的加权平均。

完全等价于公式:

复制代码
return lam * wn + (1.0 - lam) * prior

3 蕴藏金融理论

这段代码绝不仅是数学运算,它深刻嵌入了贝叶斯估计、因子投资组合构建和风险控制核心思想。

1)滚动 ICIR

滚动 ICIR即信息系数信息比率

在多因子量化模型中,通常用滚动 ICIR计算每个因子的IC,并除以其标准差得到 ICIR。

原始权重(weight_matrix)通常正比于ICIR(即ICIR 越高,赋予该因子的权重越高)。

然而 ICIR滚动估计噪声极大 ,且因子收益存在明显**风格切换(**Sign Flip),

今天有效的因子明天可能失效甚至反向。

2)收缩估计量

收缩估计量(Shrinkage Estimator)与偏差-方差权衡,

这本质上是 James-Stein 估计量 在投资组合权重中的应用。

原始权重(基于ICIR)是无偏但高方差的估计;等权先验是有偏但低方差的估计。

通过向先验收缩,显著降低了权重序列的波动率,减少了因估计误差导致的极端做多/做空头寸,从而提高样本外的夏普比率(Sharpe Ratio)。

3)设计先验(Design Prior)

构建等权先验是引入因子动量反转的防守机制,默认均值回归。

因子在构造时被标准化为方向性一致(数值越大,预期未来收益越高)。

等权先验(1/k)代表了无信息或中性的态度。

在没有充分的近期数据证据之前,默认所有有效因子的预测能力相同,给予相同的暴露。

这种先验属于保守型先验,防止模型过度依赖某个因子的近期虚假繁荣。

4)L1归一化与风险预算

绝对值求和归一化,目的是控制组合总杠杆(Gross Exposure),防止权重膨胀

除以 sum(|w|) 而不是 sum(w),是为了确保多空总杠杆恒定。

如果只除以普通求和,多空抵消后会放大净权重,导致实际杠杆失控。

归一化后,无论原始权重多大或多小,每一期的总多头暴露 + 总空头暴露之和恒为1(因为L1范数 = 1),这使得不同时间点的组合可比且风险预算可控。

5)稀疏性与Top-K选股支持域

识别非零有效因子目的是实现因子层面的贝叶斯模型平均,仅在当前活跃的因子池中进行配置

如果原始权重矩阵是稠密的,所有因子都有非零权重,则先验是等权分配给所有因子。

如果原始权重矩阵是稀疏的(即采用了 Top-K 筛选,未选中的因子直接赋为 0),则support自动排除这些零值,先验只在被选中的 K 个因子之间等权分配。

这保证了收缩过程不会复活那些被逻辑规则(如显著性检验)剔除出去的因子。如

果某个因子未进入筛选池,说明它当前没有信号支持,哪怕收缩也不应该给它仓位。

6)参数λ的经济学含义

凸组合收缩是经典的收缩估计,在偏差(Bias)和方差(Variance)间取得最优平衡

另外λ可以理解为对历史数据的信心强度。

当市场处于平稳期,因子规律稳定时,可设置较高的 λ(如 0.8)。

当市场处于高波动/风格急剧切换期,设置较低的 λ(如 0.3),强制权重回归等权,避免被短期的极端 ICIR 值误导,这是一种防守型风控手段。

reference


ICIR权重矩阵如何加权标准化为综合因子

https://blog.csdn.net/liliang199/article/details/164484760

基于信号强度的稀疏选股算法的探索分析

https://blog.csdn.net/liliang199/article/details/164597602

相关推荐
用户8356290780511 小时前
使用 Python 在 Excel 中添加和编辑形状
后端·python
2601_962300471 小时前
python在运维上可以干什么,请举几个具体的例子
运维·python·系统管理·网络监控·自动化脚本
小刘在重生~2 小时前
Java 异常体系完整笔记
java·笔记·python
用户8356290780512 小时前
使用 Python 为 PDF 添加和管理超链接
后端·python
千千寰宇2 小时前
[Python/测试] pytest:简洁、可扩展的 Python 测试框架
python·软件质量保障与测试
少陽君2 小时前
Python 并发编程:IO 等待用线程/asyncio,CPU 计算才用进程
数据库·python·php
aramae2 小时前
模拟实现strstr函数(C语言)
c语言·开发语言·算法
2601_962284502 小时前
Python 和Java 哪个更适合做自动化测试?
java·自动化测试·python·接口测试·性能测试
liliangcsdn2 小时前
因子权重矩阵处理-滞回缓冲带+降频稳定化动态重选
开发语言·python·算法