【数学建模】(时间序列模型)动态线性模型 (DLM)
在时间序列分析中,除了大家耳熟能详的 ARIMA 模型和近年来常用的深度学习模型(如 LSTM、Transformer),还有一个常见的流派------状态空间模型(State Space Models, SSM) 。而在 SSM 家族中,动态线性模型(Dynamic Linear Models, DLMs) 是其典型之一。今天我们就来看看它是如何工作的,以及如何在实际项目中使用它。
文章目录
- 【数学建模】(时间序列模型)动态线性模型 (DLM)
-
- [一、 什么是动态线性模型 (DLM)?](#一、 什么是动态线性模型 (DLM)?)
- [二、 DLM 的数学核心:两大方程](#二、 DLM 的数学核心:两大方程)
-
- [1. 观测方程 (Observation Equation)](#1. 观测方程 (Observation Equation))
- [2. 状态方程 (State/System Equation)](#2. 状态方程 (State/System Equation))
- [三、 DLM 的三步走:滤波、平滑与预测](#三、 DLM 的三步走:滤波、平滑与预测)
- [四、 ARIMA vs DLM:怎么选?](#四、 ARIMA vs DLM:怎么选?)
- [五、 Python 实战:使用 `pydlm` 构建动态线性模型](#五、 Python 实战:使用
pydlm构建动态线性模型) -
- [1. 安装依赖](#1. 安装依赖)
- [2. 代码实现](#2. 代码实现)
- 代码解析:
- [六、 总结](#六、 总结)
一、 什么是动态线性模型 (DLM)?
动态线性模型 是一种基于贝叶斯框架和状态空间的时间序列建模方法。它的核心思想是:我们观察到的数据(时间序列)是由底层某些看不见的"隐藏状态"所驱动的,并且这些隐藏状态会随着时间动态演变。
其中"动态"的意思是,DLM 认为模型的参数不是固定不变的,而是随着时间的推移而更新的。这使得 DLM 在处理非平稳时间序列、结构性突变(Structural breaks)以及缺失值时表现得异常出色。
- DLM 的两大核心优势:
- 可解释性极强: 它可以将时间序列分解为明确的成分,如趋势(Trend)、季节性(Seasonality)、自回归(AR)以及外部回归变量。
- 在线学习能力: 借助卡尔曼滤波(Kalman Filter),DLM 可以在新数据到来时实时更新对状态的估计,非常适合流数据处理。
二、 DLM 的数学核心:两大方程
要理解 DLM,必须掌握它的数学表达式。一个标准的单变量正态 DLM 由两个方程构成:观测方程 和状态方程。
1. 观测方程 (Observation Equation)
观测方程描述了我们看到的观测值 Y t Y_t Yt 是如何由隐藏的状态向量 θ t \theta_t θt 产生的:
Y t = F t θ t + v t , v t ∼ N ( 0 , V t ) Y_t = F_t \theta_t + v_t, \quad v_t \sim N(0, V_t) Yt=Ftθt+vt,vt∼N(0,Vt)
- Y t Y_t Yt:在时间 t t t 的标量观测值。
- F t F_t Ft:已知的观测矩阵(设计矩阵),它将隐藏状态映射到观测空间。
- θ t \theta_t θt:在时间 t t t 的 p p p 维隐藏状态向量(例如,当前的趋势值、季节因子等)。
- v t v_t vt:观测噪声,通常假设为均值为 0 0 0,方差为 V t V_t Vt 的正态分布。
2. 状态方程 (State/System Equation)
状态方程(或称系统方程)描述了隐藏状态 θ t \theta_t θt 是如何随着时间从 t − 1 t-1 t−1 演变到 t t t 的:
θ t = G t θ t − 1 + w t , w t ∼ N ( 0 , W t ) \theta_t = G_t \theta_{t-1} + w_t, \quad w_t \sim N(0, W_t) θt=Gtθt−1+wt,wt∼N(0,Wt)
- G t G_t Gt:已知的状态转移矩阵,描述系统随时间的演化规律。
- w t w_t wt:状态噪声(系统误差),假设为均值为 0 0 0,协方差矩阵为 W t W_t Wt 的多变量正态分布。
由这个状态方程可以发现,它认为状态转移是具有某种线性的特征的,即其名称中"线性"由来。
💡 核心逻辑: 我们的目标是根据一系列的不完美观测值 Y 1 : t Y_{1:t} Y1:t,去反推(Inference)最有可能的真实隐藏状态 θ t \theta_t θt。这个反推的过程,就是大名鼎鼎的卡尔曼滤波 (Kalman Filtering)。
三、 DLM 的三步走:滤波、平滑与预测
在 DLM 的应用中,我们通常需要解决以下三个基本问题:
- 滤波 (Filtering): 给定直到当前时刻 t t t 的所有观测数据 Y 1 : t Y_{1:t} Y1:t,估计当前状态 θ t \theta_t θt。这主要依赖前向的卡尔曼滤波算法。
- 平滑 (Smoothing): 给定整个时间序列(直到未来的大 T T T 时刻)的数据 Y 1 : T Y_{1:T} Y1:T,回头去重新估计历史时刻 t t t 的状态 θ t \theta_t θt。这可以利用未来的信息修正过去的估计,通常使用后向平滑算法(如 Rauch-Tung-Striebel 平滑器)。
- 预测 (Forecasting): 给定直到 t t t 时刻的数据 Y 1 : t Y_{1:t} Y1:t,预测未来某个时刻 t + k t+k t+k 的观测值 Y t + k Y_{t+k} Yt+k。
四、 ARIMA vs DLM:怎么选?
很多朋友会问,有了经典的 ARIMA,为什么还要学 DLM?我们来做个简单对比:
| 特性 | ARIMA 模型 | 动态线性模型 (DLM) |
|---|---|---|
| 假设 | 依赖平稳性假设(需差分) | 无需平稳性假设 |
| 参数更新 | 参数固定(批量拟合) | 参数动态更新(可在线学习) |
| 缺失值处理 | 难以直接处理,需插值 | 天然支持,视为无穷大的观测方差 |
| 可解释性 | 弱(黑盒参数) | 强(可直接拆解趋势、季节性) |
| 先验知识 | 无法直接引入 | 基于贝叶斯框架,可方便引入先验 |
结论: 如果你的数据比较平稳,只需做简单的黑盒预测,ARIMA 足够了;但如果你的数据存在突变、有很多缺失值,或者你需要向业务部门解释"趋势到底上升了多少,季节性影响占多大比例",那么 DLM 是首选。
P.S. 关于 ARIMA 模型的介绍,可以参见我之前写的这一篇文章:【数学建模】(时间序列模型)ARIMA时间序列模型 。
五、 Python 实战:使用 pydlm 构建动态线性模型
接下来,我们用 Python 中的 pydlm 库来实战演示。这个库极大地简化了 DLM 的构建过程。
1. 安装依赖
bash
pip install pydlm matplotlib numpy
2. 代码实现
我们将生成一个包含线性趋势、周期为 7 的季节性,以及一些随机噪声的时间序列,并用 DLM 将它们分离出来。
python
import numpy as np
import matplotlib.pyplot as plt
from pydlm import dlm, trend, seasonality
# ==========================================
# 1. 生成模拟数据
# ==========================================
np.random.seed(42)
n = 100
# 线性趋势 + 周期为7的季节性 + 随机噪声
base_trend = np.linspace(0, 5, n)
base_seasonality = np.sin(np.arange(n) * (2 * np.pi / 7)) * 2
noise = np.random.normal(0, 0.5, n)
data = base_trend + base_seasonality + noise
# ==========================================
# 2. 构建 DLM 模型
# ==========================================
# 初始化 DLM
my_dlm = dlm(data)
# 添加组件:
# degree=1 表示线性趋势(包含截距和斜率)
# discount 扮演了方差 W_t 的角色,取值在0-1之间。越接近1说明状态越稳定,越小说明系统越灵活易变。
my_dlm = my_dlm + trend(degree=1, discount=0.98, name='linear_trend')
# 添加周期为7的季节性组件
my_dlm = my_dlm + seasonality(period=7, discount=0.99, name='weekly_seasonality')
# ==========================================
# 3. 拟合与预测
# ==========================================
# 进行前向滤波和后向平滑
my_dlm.fit()
# ==========================================
# 4. 结果可视化
# ==========================================
# pydlm 内置了非常方便的画图方法
# 绘制原始数据与拟合/预测曲线
my_dlm.plot()
# 绘制拆解出来的各个组件 (趋势、季节性)
my_dlm.turnOff('data points')
my_dlm.plot('linear_trend')
my_dlm.plot('weekly_seasonality')
代码解析:
trend(degree=1):代表我们在状态向量中加入了局部的线性趋势。seasonality(period=7):代表加入了周期为 7 的傅里叶波。discount(折扣因子):这是pydlm中精妙的设计,它代替了繁琐的协方差矩阵 W t W_t Wt 的设定。通常设定在 0.9 0.9 0.9 到 1.0 1.0 1.0 之间,折扣因子越小,模型对近期数据的变化越敏感,越能捕捉突变;但也更容易受到噪声干扰。
六、 总结
动态线性模型 (DLM) 提供了一个数学框架来理解时间序列,它通过观测方程和状态方程,将复杂的序列分解为一个个具有明确意义的组件(隐藏状态)。它在做金融风控、交通流量预测、库存管理等对可解释性和鲁棒性要求极高的任务时会很有帮助。
如果这篇文章对你有帮助,欢迎点赞、收藏、关注!有任何问题欢迎在评论区讨论。