做溢出指数研究的朋友,应该都遇到过这样的尴尬:Diebold-Yilmaz的老框架好用是好用,但变量一旦多起来,VAR模型的参数就直接爆炸,方差分解矩阵算出来全是噪声,完全没法看。我自己在早期用传统DY做行业板块间风险传染时,变量加到15个以上,结果就开始“放飞自我”,今天一个说法明天另一个说法,根本没法跟客户解释。所以后来看到TVP-VAR-DY这个方向,我是兴奋的,但再往高维走,时变参数模型自身也扛不住,直到我把Elastic Net(弹性网络)搬进来,这套“HD-TVP-VAR-DY溢出指数”才算真正跑通了。
这篇文章就专门聊聊这套方法到底怎么落地:它解决的核心问题是什么、Elastic Net在里面到底起了什么作用、TVP-VAR的时变特征怎么和稀疏化估计结合,以及实操中那些参数到底该怎么调。内容会偏技术细节,但我会尽量讲人话,适合做宏观金融、资产配置、风险管理量化研究的朋友,也适合正在写相关方向论文的硕博生参考。
1. 为什么传统DY溢出指数在高维场景会“失灵”
1.1 从Diebold-Yilmaz框架说起
先说基础。Diebold和Yilmaz在2012年、2014年连续发表的文章,本质上是在构建一个“谁影响谁”的风险传染地图。其核心工具是广义预测误差方差分解(GFEVD,Generalized Forecast Error Variance Decomposition),它回答的问题是:当某变量在预测未来N步时产生预测误差,这个误差中有多大比例是由其他变量的冲击解释的。
我们知道在VAR模型里,变量的预测误差方差可以分解为各变量“贡献”的份额,这个份额矩阵就是溢出矩阵。把矩阵的非对角线元素汇总,就能得到总溢出指数(Total Spillover Index);拆开来看,又可以得到“从某变量溢出到所有其他变量”的定向溢出(Directional To)、以及“从所有其他变量接收到某变量”的定向溢出(Directional From);两者相减还得到净溢出(Net Spillover)。这套逻辑从宏观利率到股票市场、从能源价格到行业指数的应用,几乎成了实证金融的标准动作。
但传统DY的致命限制在“高维”两个字上。这里的“高维”不用特别夸张,对普通研究者来说,变量数N超过10个就已经很吃力;一旦N到了20个以上,传统方法基本宣告失效。问题出在VAR模型的参数结构上:N个变量的VAR(p)模型,光系数的个数就是N^2乘p,再加上协方差矩阵的N(N+1)/2个参数。N=10时,p=1也有110个待估参数,彼时样本量如果在200、300个观测值左右,估计已经勉强;N=30时,p=1就有930个系数,加上方差协方差矩阵,总参数突破1300,而时间序列的样本量往往只有几百,这时候模型几乎不可能稳定估计。参数过拟合的结果就是方差分解矩阵的对角线接近1,其他变量之间的溢出联系全被压缩成零,或者反过来乱给信号——结果就是溢出矩阵没有经济学意义。
1.2 高维带来的三个具体困境
我在实践里把高维DY的问题总结成三个具体的坑,这三个坑也是后续方案设计的出发点。
第一个坑是参数爆炸。这个刚才已经提到,N越大,估计所需要的样本量越高,而宏观金融数据的时间维度有限,不可能无限拉长样本。尤其是想捕捉时变特征的时候,如果再用滚动窗口,每个子样本的观测值更少,估计结果就更不稳定,这是死结。
第二个坑是共线性放大。金融时间序列本身就有强相关性,股票板块、利率期限结构、宏观指标之间往往联动显著。在高维VAR里,解释变量高度相关时,普通最小二乘(OLS)估计量的方差会剧烈膨胀,导致系数符号和大小完全不可信。溢出指数对系数极其敏感,一个变量的系数估计“爆掉”,整个溢出矩阵都会变形。
第三个坑是计算的数值稳定性。方差分解的数学表达涉及对VAR系数做矩阵运算、求无穷级数或近似逆矩阵,当维度变高,矩阵条件数迅速恶化,一个小误差会被放大成很大的错误。最直观的表现是:总溢出指数在不同扰动下相差悬殊,同一个模型换了滞后阶数结果就完全不同,这类问题我在早期测试里碰到过无数次。
所以,要让DY溢出指数在高维场景下还能用,必须解决两个问题:一是收缩模型参数空间,二是在高度相关的变量中仍然能识别出有效联系。Elastic Net正好是对这两个问题都有针对性的工具。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. HD-TVP-VAR-DY的完整方案设计
2.1 核心思路:用Elastic Net“驯服”高维系数矩阵
Elastic Net由Zou和Hastie在2005年提出,是岭回归和Lasso的“合体”。它在损失函数中同时加入L1范数惩罚和L2范数惩罚,目标函数可以写为:
code复制min ||y - X beta||^2 + lambda * (alpha * ||beta||_1 + (1 - alpha) * ||beta||_2^2)
其中alpha控制在L1和L2之间的比例,lambda控制整体惩罚强度。为什么这个组合天然适合高维溢出指数?从几个方面来看。
L1部分保证了稀疏性——在众多可能的变量连接中,只有真正重要的连接会被保留为“非零系数”。高维金融变量之间的连接大多数是“弱连接”甚至“无连接”,要求模型自动识别出少数几个强连接,这是Lasso的强项。
但Lasso有一个公认的弱点:在高度相关的变量组面前,它倾向于只从一组相关变量里随便选一个,导致变量选择结果不稳定。而金融变量恰恰是高度相关的。Elastic Net的L2部分可以有效“分摊”组内相关变量之间的系数,使得一组高度相关的变量要么同时被纳入,要么同时被压缩,而不是随机挑选一个。这一步对于方差分解至关重要——因为溢出矩阵反映的是“组合效应”,而不是单个变量孤立的作用。
我在实际测算中还发现一个容易被忽视的细节:对高维VAR的系数矩阵做Elastic Net收缩,等于在估计阶段就进行了正则化,这个正则化不仅减少了有效参数个数、克服了过拟合,还在数值上改善了矩阵的条件数。后续做广义逆和方差分解时,数值稳定性好了很多。这比先用Lasso筛选变量再用OLS重估的“两阶段法”稳定性更高,因为两阶段法忽略了筛选阶段的不确定性。
2.2 TVP-VAR部分:时变参数怎么估
传统的TVP-VAR假设回归系数随时间缓慢变化,常见做法有状态空间模型配合卡尔曼滤波(Kalman Filter),或者直接在滚动窗口内估计。前者灵活但计算复杂度高,后者简单但会损失大量样本。
HD-TVP-VAR-DY方案里采用了一种折衷设计:在滚动窗口的基础上嵌入惩罚回归。具体做法是:设定一个固定长度的窗口,例如240个交易日(约一年),在每一个时间点t上,只使用最近240个观测值来估计TVP-VAR模型的当期系数。因为每个窗口内样本都不多,直接做OLS必然不稳定,所以我们不是用传统的OLS估计VAR系数,而是用Elastic Net估计每一个时间截面的VAR系数。这样既拿到了时变特征——不同时间点对应不同的稀疏VAR系数矩阵,又通过正则化保证了每个截面的估计稳定。
有人可能问,状态空间模型不是更“正宗”吗?我试过在N=20的高维场景下跑贝叶斯VAR加随机波动,结果是:单次估计耗时就到了小时级别,而且链的收敛性不太理想。对于多数实证研究,惩罚回归加滚动窗口已经足够捕捉平滑的时变特征,同时一个小时能跑完一套完整的溢出指数序列。效率决定了这个方案可以实际被天天使用,而不是只在论文里好看。
另一个关键点是滞后阶数的选择。滞后阶数p不能太大,p越大,系数矩阵的维度越高,估计的负担就越重。高维TVP-VAR里我通常建议p=1或p=2。金融数据用p=1很多时候已经够了,因为月度收益率序列的自相关本来就不强,更高阶的信息只会拖累估计。如果非要用信息准则,BIC比AIC更倾向于低阶,因为它对参数数量的惩罚更严,这在变量多的时候是更合理的默认选择。
2.3 溢出指数的聚合:从GFEVD到总溢出
估计出TVP-VAR的系数之后,剩下的就是标准流程:对每个时间点的系数矩阵,计算对应的结构冲击,再通过广义预测误差方差分解(GFEVD)得到逐期的溢出矩阵。这里有一个容易被忽略的点:GFEVD对变量排序是不敏感的(与Cholesky分解不同),这是DY框架里非常重要的设计,因为在溢出分析中,我们并不想假设一个预先的经济顺序。
具体而言,对VAR(p)模型先写出VMA(向量移动平均)表示,得到无穷阶的移动平均系数矩阵。第0期冲击的协方差矩阵,以及h步预测误差的方差分解,可以通过标准的递归公式算出来。每个变量“接收到”的溢出,是方差分解矩阵中非对角线对应列的分量;“传递到”其他变量的溢出,是对应行的非对角线分量;总溢出指数就是所有非对角线元素之和占总预测方差的比例。
这里有一个工程细节:GFEVD计算中的广义逆和平稳性假设在高维场景下经常出问题。我建议在计算VMA系数时,先检查VAR特征多项式的特征根是否在单位圆内。若特征根接近单位圆边界,VMA系数的衰减速度会很慢,需要更大的预测步长H才能收敛。我一般设H=10,在日频和周频数据上都足够稳定;但如果你的数据月度或者更低频,H可能要到20以上。预测步长太小,方差分解的结果还会有较大的短期波动噪音;太大则可能把长期结构性的关系也混进来。实操中可以跑H=5, 10, 20几个档位做稳健性检验,看结论方向是否一致,再决定最终采用的H值。
3. 实操指南:让高维溢出指数真正跑起来
3.1 数据准备:样本量与变量选择的关系
有人以为只要有了Elastic Net,就可以无限加变量。这不对。虽然Elastic Net能在一定程度上处理N接近或超过样本量T的情况,但并不意味着可以无脑堆变量。
从数据准备的角度,我有几个经验值。如果样本量在500个观测值左右,N控制在20到30之间是合理的。如果N到了50,样本量最好有1000以上。在实际应用里,行业指数数据还好,日频收益率十年能积累2500个左右数据点,足够支撑N=50的动态溢出指数;但宏观月度数据十年只有120个观察值,做不了高维动态溢出,除非换用季度或更高频。这是第一个要认清的事实。
数据频率的选择同样重要。日频数据的优势是样本量大,但噪声也大,且时区不同步会带来伪溢出;周频数据是很好的折衷,既能保留足够多的观测,又能滤掉不少日频噪音;月频数据连续性好,但样本量常常不足。如果要研究市场间风险传染,我个人偏爱用周频数据,N=20左右,滚动窗口为104周(约两年),这样每个窗口还能保证104个观测值,配合Elastic Net估计,结果相当稳。
变量标准化这个细节也值得多说一句。Elastic Net对变量的尺度非常敏感,如果不做标准化,惩罚项会倾向于压缩数值尺度较大的变量,导致结果有偏。所以进入估计之前,所有变量必须做标准化处理(减去均值,除以标准差)。我习惯把收益率序列做标准化后再估计系数,做完溢出指数后再把结果“还原”成可解释的百分比形式。
3.2 Elastic Net参数:alpha和lambda到底怎么调
在HD-TVP-VAR-DY这个应用场景中,Elastic Net有通常意义上的alpha和lambda两个核心参数,大部分文献里直接称呼为混合参数和惩罚强度,这里把它记作alpha和lambda容易与Elastic Net的记号冲突,所以我统一这样阐述:需要调整的第一个参数是混合比例(L1与L2之间的权重),第二个是整体惩罚力度。
我实测下来的经验是:混合比例不宜太高。Elastic Net在金融数据上的最优混合比例通常在0.5及以下,甚至0.1、0.2都能有不错的效果。为什么?金融变量之间的相关性强度太高,如果L1权重过大,Lasso的“随机挑选”问题就会卷土重来;如果L2权重偏高(混合比例小),保留了组效应,但稀疏性又会下降。整体上,混合比例小一点,模型更稳定,对相关性强的金融变量组更友好。具体数值需要靠交叉验证去选,但方向是明确的:不要默认0.5,先试0.1到0.3这一段。
第二个参数是惩罚力度lambda。它在Elastic Net里控制着模型复杂度,在本文的框架下它同样控制每个时间截面的系数平滑程度。交叉验证的网格搜索是标配做法,但高维场景下我要提醒一点:lambda的取值不宜完全依赖交叉验证。交叉验证在预测误差最小的地方选出来的lambda,往往偏小,也就是惩罚不够,导致保留的变量过多。对于溢出指数研究,我倾向于在交叉验证给出的最优lambda基础上再往大调整0.5到1倍,让模型更稀疏、更稳定。这不是书上的教条,是我对比了大量模拟数据和真实市场数据后的经验,你可以根据你的数据情况微调。
3.3 滚动窗口长度的设定逻辑
TVP部分最关键的参数除了滞后阶数就是滚动窗口长度。窗口长度直接决定了时变参数的“平滑度”,窗口越短,参数变化越快,但对单次估计的样本支撑越少;窗口越长,估计越稳定,但时变特征会变得迟钝。
我通常以预测误差和结果稳定性两个标准来选择窗口。对周频数据,104周是默认起点,对应约两年,足够捕捉一轮货币政策周期或市场风格切换;对日频数据,240天是常用起点,但我会额外关注重大事件前后的变化是否被平滑掉了。事件驱动的分析里,太长的窗口会把2020年疫情、2022年加息这类结构突变“平均”进正常波动里,导致溢出指数的峰值不明显。如果研究目的就是监测危机传染,窗口可以缩短到90天甚至60天,代价是噪声会增加,需要通过Elastic Net更强的惩罚来对冲。这个平衡点需要反复试,没有唯一答案。
滞后阶数的选择同样要结合窗口长度。窗口短,滞后阶数就必须低,否则有效样本量被滞后变量吃掉太多。p=1在金融日频数据里通常已经足够,但如果你研究的是低频宏观数据,可能需要p=2或者p=3,这时窗口长度也要相应拉长。
3.4 溢出矩阵的三种口径与解读要点
计算完所有时点的GFEVD之后,会得到一系列N乘N的溢出矩阵。矩阵的对角线元素表示变量自身的方差贡献,非对角线元素是变量间的溢出。常见的解读看三个口径:总溢出指数、定向溢出指数和成对净溢出指数。
总溢出指数是一个数值序列,它显示系统整体互联性的变化。总溢出指数上升,说明风险在系统内快速传导,市场处于高联动状态;下降则说明各资产或行业相对独立。2020年3月全球市场暴跌时,用这套方法算出来的总溢出会有一个明显的脉冲峰值,这就是典型的危机传染信号。
定向溢出指数更细。每个变量有一个“to”(贡献给其他变量),一个“from”(接收到其他变量的贡献),两者之差是“net”。当一个变量的net持续为正,它是系统净的风险输出者;持续为负,则是净接收者。在做风险管理时,我会重点盯那些net值从负转正的变量,这往往意味着该部门/资产正在从“风险接收者”变成“风险源头”,是配置组合需要警惕的信号。
成对净溢出矩阵则用来识别具体的传导路径,比如某国债券向某国股市的净溢出是否在某个时间段突然放大。这个矩阵特别适合做政策分析或事件研究,只是高维下需要配合一些可视化手段(热力图、网络图)才能高效解读,这里不再展开。
4. 代码实现:从时变系数到溢出指数的完整流程
4.1 直接可参考的R语言思路与结构
虽然不同研究者的代码习惯不同,但整体流程高度一致:先做数据标准化和窗口分割,再在每个窗口内估计高维TVP-VAR系数,然后计算GFEVD,最后加总溢出指数。我用R作为主要工具,核心思路可以用下面的伪代码结构来描述,实际使用时可以根据自己的数据格式和已有工具包灵活调整。
r复制# 伪代码示例,核心逻辑示意
# data: T x N 矩阵,已经做过标准化
T <- nrow(data)
N <- ncol(data)
window_length <- 104 # 滚动窗口长度
H <- 10 # 预测步长
spillover_total <- c() # 存储总溢出指数
for (s in (window_length+1):T) {
window_data <- data[(s-window_length+1):s, ]
# 1. 构建滞后矩阵
X <- lag_matrix(window_data, p = 1) # 自建函数:生成VAR(1)设计矩阵
Y <- window_data[(p+1):nrow(window_data), ]
# 2. 用Elastic Net估计每个方程的系数
coefficients <- matrix(0, N, N)
for (j in 1:N) {
fit <- glmnet(X, Y[, j], family="gaussian",
alpha=0.2, lambda=best_lambda) # best_lambda来自交叉验证
coefficients[j, ] <- as.vector(coef(fit))[-1] # 去掉截距
}
# 3. 把系数重排成VAR系数矩阵,计算VMA表示
VAR_coef <- array(coefficients, dim = c(N, N, 1))
VMA_irf <- compute_vma(VAR_coef, cov_mat = cov(window_data), H = H)
# 4. 计算GFEVD(需处理广义逆)
fevd <- compute_gfevd(VMA_irf, cov_mat = cov(window_data), H = H)
# 5. 计算总溢出指数
total_spill <- sum(fevd[row(fevd) != col(fevd)]) / sum(fevd)
spillover_total <- c(spillover_total, total_spill)
}
这段伪代码省略了大量细节,比如glmnet函数的具体调用、滞后矩阵的生成、VMA计算和GFEVD的矩阵运算。实际写的时候,有几个地方容易踩坑,我单独指出来。
4.2 估计高频细节与易错环节
第一个坑是滞后矩阵的构建。VAR(p)的滞后矩阵不是简单地把数据平移p行,而是要把每一列滞后1、2、...、p期,然后横向拼接成一个大设计矩阵。如果搞错对齐,系数和因变量之间会产生错位,整个溢出矩阵都会失真。我的习惯是先画出几个滞后变量和因变量的散点图,做一遍简单的数据对齐再进入正式估计。
第二个坑是截距项的处理。在Elastic Net估计中我通常会把数据预先中心化,也就是把截距直接吸收进均值里,这样在glmnet里可以不拟合截距或者拟合了再剔除。如果把截距留在惩罚项里,L1惩罚会对截距也进行压缩,导致估计的均值偏移,这个问题对溢出指数的扰动虽然不如系数大,但在动量较强的市场数据里会造成虚假的持续性,需要注意。
第三个坑是协方差矩阵的估计。GFEVD需要用到残差的协方差矩阵,但高维场景下直接用样本协方差矩阵依然会得到奇异或近似奇异的矩阵。所以残差的协方差矩阵也要做正则化处理,比如直接用Ledoit-Wolf收缩估计器,或者简单地加一个较小的对角矩阵保证可逆。我自己偏向于用Ledoit-Wolf收缩,因为它有理论最优性保证,代码上R的RiskPortfolios包或者Python的sklearn.covariance都是现成的实现。
第四个坑是广义逆的处理。GFEVD计算中涉及对协方差矩阵求逆,如果矩阵不可逆,需要切换到Moore-Penrose广义逆。在N大于窗口长度时,这个问题必然会出现,所以预先写一个判断条件:若条件数过大,就使用广义逆而不是普通逆。
4.3 结果验证:三个稳健性检查必做
模型跑通了不代表结论可信。我强烈建议任何使用HD-TVP-VAR-DY的研究者至少做三个稳健性检查。
第一个是参数敏感性分析。把H从5调到20,lambda从交叉验证值往上下各调若干档,混合比例分别设为0.1、0.5、0.9,观察总溢出指数曲线的大体形状是否保持。如果某组参数下结果出现“突变式”差异,说明模型对这个参数的依赖过强,需要回到参数选择阶段寻找原因。
第二个是窗口敏感性分析。窗口长度在80、104、130之间变化时,总溢出指数的整体趋势应该一致,局部会有偏移,但不应出现峰值位置完全不同的情况。如果窗口长度稍微一变,某个经济事件的溢出信号就从有到无,那说明该信号可能更多是过拟合的产物。
第三个是与其他方法的对比。最简单的对比对象是传统滚动窗口OLS-DY,虽然高维下OLS可能不稳定,但在N较小时仍然可以作为基准参考。另一个更有说服力的对比是用Lasso替换Elastic Net重新估计一遍,如果结论发生系统性改变,说明组相关性在起作用,Elastic Net的结果更值得信任。把三个方法的曲线画在一张图里,能直接发现Elastic Net对“变量选择随机性”的平滑作用——这正是第一性原理里最核心的收益。
5. 常见问题与实战避坑经验
5.1 高频问题速查表
为了方便大家排查问题,我把自己在这个方向踩过的坎汇总成一张速查表,按问题类型、常见表现和处理办法排列。
| 问题类型 | 常见表现 | 优先排查方向 |
|---|---|---|
| 总溢出指数长期接近1或0 | 曲线没有波动或波动极小 | 检查lambda是否过大/过小,混合比例是否极端,变量标准化是否做对 |
| 单个变量的溢出指数突跳 | 曲线出现单一尖峰后回落 | 检查该变量在对应窗口内是否有极端值,窗口内样本量是否过少 |
| 矩阵不可逆报错 | 计算GFEVD时报错 | 换用Ledoit-Wolf收缩协方差估计或广义逆 |
| 估计结果对窗口长度极敏感 | 改变窗口长度结论方向反转 | 增加Elastic Net惩罚力度,考虑滞后阶数是否过高 |
| 溢出矩阵非对称且负值过多 | 净溢出指数大量为负 | 检查变量之间是否存在强共线性,调整混合比例是否合适 |
| 时间成本过高 | N=30时耗时数小时 | 减少滚动窗口步长,适当降低交叉验证网格密度,或改用Python并行实现 |
5.2 实操心得:三个“反直觉”的发现
第一个发现是:交叉验证选出的lambda往往不是最佳选择。学术和实践之间存在一个Gap——交叉验证追求的是样本外预测误差最小,但溢出指数研究追求的是结构稳定和经济解释。预测最优和结构最优并不总是一致。我通常在交叉验证的基础上将lambda提高20%到50%,结果反而更稳定,经济解释也更清晰。
第二个发现是:混合比例alpha在0.1到0.3之间时结果最稳健。很多人第一次用Elastic Net会直接选alpha=0.5(等权混合),但金融数据的强相关性决定了L2成分应该占更大权重。我做过一个N=20的行业指数测试,alpha=0.2比alpha=0.5的总溢出指数波动低大约三分之一,且对参数扰动的敏感性也低得多。
第三个发现是:变量顺序对高维GDY结果的影响虽然理论上为零(因为GFEVD对排序不敏感),但数值上因为有限精度计算,还是会有极小的差异。如果方差分解矩阵里出现极其微小但为负的值,不必太在意,直接做一个非线性变换(比如把微小负值截断为0)再归一化,不会影响结论。
5.3 高维溢出指数结果的展示与交付
最后聊聊结果怎么呈现。纯数字表格在变量多的时候毫无可读性,总溢出指数曲线是必画的。定向溢出我习惯画成堆叠面积图,能清楚看到各个变量在不同时期向系统输送或接收风险的比例变化。成对净溢出矩阵适合用热力图展示,选取某个特定时间段(比如危机期间)单独画一张,可以快速定位主要风险传导中心。
还有一点提醒:用这套方法写论文或者做投研报告的时候,一定要在图注和正文里注明参数选择(窗口、H、alpha、lambda取值)。这些参数直接决定结果曲线长什么样,不注明的话,复审时几乎肯定会被追问,到时候再补实验又费一轮时间。一次性把参数表放在附录里,既是学术诚信的问题,也是减少自身返工成本的小技巧。
最后分享一个提高效率的小习惯
在正式跑完整样本之前,我会先拿最近两年左右的数据跑一个小规模的试算。窗口取50到60,N控制在10个以内,混合比例固定在0.2,先粗略看一眼总溢出指数的变化趋势是否合理。这个小试算能帮我在投入大量时间跑几百个窗口之前,尽早发现数据处理的问题,比如某个序列有严重的单位根、某个变量存在大量缺失或异常值,或者滞后对齐出错了。等小规模试算确认一切正常,再放开跑全样本全变量,基本一次就能跑通,节省的时间非常多。
