1

神经网络时间序列预测工具NeuralProphet

 1 year ago
source link: https://www.biaodianfu.com/neuralprophet.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

器→工具, 开源项目, 数据, 术→技巧, 法→原理, 深度学习

神经网络时间序列预测工具NeuralProphet

钱魏Way · 2023-08-31 · 0 次浏览

NeuralProphet产生背景

大多数时间序列问题需要易于理解的预测。同时,需要有效的预测。这两个愿望导致了一种权衡:可解释性与准确率。准确率的显著提高通常归因于更复杂的模型。然而,复杂性与可解释性存在天然的矛盾。

简而言之,存在两类模型:

  • 统计算法(ARIMA、GARCH …)可以在知道理论的情况下进行数学解释
  • 神经网络模型,虽然更加复杂,但已经证明了它们的性能

最初,Facebook 与 Prophet 的意愿是提供一个易于使用、可调整和可解释的工具来预测时间序列。然而,有一个问题依然存在:准确性不佳。为了解决这个问题,NeuralProphet 应运而生。

简而言之,NeuralProphet = 神经网络 + Prophet

因此,目的是通过在 Prophet(一种统计算法)中包含神经网络来结合前两个类别。目的:提高准确性,同时限制可解释性的损失。

这个介绍部分可以通过下图来大致描述:

NeuralProphet.png

NeuralProphet简介

最初的 Facebook Prophet 算法是非常轻量级但有效的时间序列预测模型。它易于使用和解释,描述很少与时间序列建模相关联。根据原始论文,该模型之所以成功,是因为研究人员将时间序列预测重新定义为曲线拟合问题,而不是自回归问题。许多先前的模型,例如 ARIMA,滞后和拟合数据,而不是试图找到我们趋势的函数形式。该模型具有三个主要组成部分。T(t) 对应于我们的时间序列在去除季节性后的趋势。 S(t) 对应于我们的季节性,无论是每周、每月还是每年。最后,E(t) 对应于预先指定的事件和假期。这些组件中的每一个都有一个拟合过程,一旦拟合,它们通常会结合起来产生可靠的预测。

2020 年,斯坦福大学和 Facebook 的研究人员对 Prophet 算法进行了重组,以包含深度学习组件。主要卖点是准确度提高了 55-92%。该模型的深度学习部分建立在 PyTorch 之上,因此它们很容易扩展。运行时间平均增加了约 4 倍,但时间序列预测很少是实时的,因此运行时间不是主要问题。

如果您需要可解释但功能强大的时间序列预测,NeuralProphet 可能是您的最佳选择。

NeuralProphet是一个基于PyTorch实现的客户友好型时间序列预测工具,延续了Facebook开源预测工具Prophet的主要功能。NeuralProphet是在一个完全模块化的架构中开发的,这使得它可以在未来增加额外组件,可扩展性很强。项目意在保留Prophet的原始特性,如Classic AR模型可解释性、可配置性,并使用了PyTorch后台进行优化,如Gradient Descent,另外还引入了AR-Net建模时间序列自相关、自己设置损失和指标、具备前馈神经网络的可配置非线性层等等特性。

Neural Prophet是升级版的Prophet。NeuralProphet模型集成了Prophet的所有优点,不仅具有不错的可解释性,还有优于Prophet的预测性能。

  • 使用PyTorch作为后端进行优化的梯度下降法。
  • 使用AR-Net对时间序列的自相关进行建模。
  • 使用seepearate前馈神经网络对滞后回归者进行建模。
  • 可配置的FFNNs非线性深层。
  • 可调整到特定的预测范围(大于1)。
  • 自定义损失和指标。

虽然官方PPT写了很多改变,但是其实就是基于两个”巨变”。

  • 分解的分量增加了一个重量级的AR(自回归),这个是超级重量级的。
    • AR模型本身在经典时序分析里面就独当一面,到了Neural Prophet里面做为辅助,它对于精度的提高是神级的。
    • 相比于传统的AR模型, AR模型借助于神经网络,拟合的更加快捷和精确。
    • 对于AR模型也添加了正则项(参数为ar_sparsity)。通过正则加持, AR模型可以看的更远,因为你有能力使用更多的历史数据而不用担心求解。
  • Pytorch作为backend。
    • Neural Prophet把所有的分量都用pytorch写了。
    • 趋势项,周期项变化不大,因为他们的算法还是和Prophet一致。
    • AR项,外部回归项变化很大,因为有了Pytorch的加持,意味着你不用再局限于线性回归。
    • 从源码看,Neural Prophet采用Relu非线性化了。
    • 神经网络适合魔改,看着结果不顺眼,改改层数,说不定就顺眼了。

NeuralProphet原理

NeuralProphet是一个可分解的时间序列模型,和Prophet相比,类似的组成部分有趋势(trend)、季节性(seasonality)、自回归(auto-regression)、特殊事件(special events),不同之处在于引入了未来回归项(future regressors)和滞后回归项(lagged regressors)。

未来回归项(future-known regressors)是指在预测期有已知未来值的外部变量,而滞后回归项(lagged covariates)是指那些只有观察期值的外部变量。趋势trend可以通过设置变化点来建立线性或者组合多个线性趋势的模型。季节性seasonality使用傅里叶项建模,因而可以解决高频率数据的多种季节性。自回归项(auto-regression)使用AR-Net的实现来解决,这是一个用于时间序列的自回归前馈神经网络(Auto-Regressive Feed-Forward Neural Network)。滞后回归项也使用单独的前馈神经网络进行建模。未来回归项和特殊事件都是作为模型的协变量,只要single weight进行建模。

NeuralProphet模块组件

NeuralProphet模型模型由多个模块组成,每个模块都有各自的输入和建模过程。 每个模块都有自己的个人输入和建模过程。 但是,所有模块都必须产生 h 个输出,其中h 定义了一次预测未来的步数。

$$\hat{y_t} = T(t) + S(t) + E(t) + F(t) + A(t) + L(t)$$

  • T(t) = 时间 t 的趋势
  • S(t) = 时间 t 的季节性影响
  • E(t) = 时间 t 的事件和假日效应
  • F(t) = 未来已知外生变量在时间 t 的回归效应
  • A(t) = 基于过去观察的时间 t 的自回归效应
  • L(t) = t 时刻外生变量滞后观测的回归效应

所有模型组件模块都可以单独配置和组合以组成模型。 如果所有模块都关闭,则仅安装一个静态偏移参数作为趋势分量。 默认情况下,仅激活 trend 和 seasonality 模块。

Trend

趋势与之前的 Prophet 模型没有变化。简而言之,我们希望使用指数或线性增长函数来模拟趋势。使用逻辑增长是一种非常传统且广为接受的解决方案,但是原始 Prophet 模型的创新之处在于它允许函数的参数发生变化。这些变化点由模型动态确定,并为其他静态增长率和偏移参数提供了更大的自由度。

建模趋势的经典方法是将其建模为偏移量 m 和增长率 k。 $t_1 $时刻的趋势效应由增长率乘以从偏移量 m 顶部的起点 $t_0$ 开始的时间差。

$$T(t_1) = T(t_0) Z + k\cdot \Delta _t = m + k\cdot (t_1 – t_0)$$

Seasonality

季节性被定义为以特定的定期间隔发生的变化。众所周知,它很难解释,因为它可以采用多种形式。该模型的最初开发人员提出了另一个好主意——他们没有尝试使用自回归(即滞后数据)对季节性进行建模,而是尝试对季节性曲线进行建模。这就是傅立叶级数的用武之地。傅立叶级数只是一堆加在一起的正弦曲线,可用于拟合任何曲线。一旦我们有了数据的每日、每周、每月等季节性的函数形式,我们就可以简单地将这些术语添加到我们的模型中并准确预测未来的季节性。

类似Prophet,NeuralProphet也使用傅立叶项(Fourier terms)来处理Seasonality。傅立叶项定义为正弦、余弦对并允许对多个季节性以及具有非整数周期的季节性进行建模。每个季节性可以定义为多个傅里叶项。

$$S_p(t) = \sum_{j=1}^{k}(a_j\cdot \cos(\frac{2 \pi jt}{p})+b_j \cdot \sin(\frac{2 \pi jt}{p}))$$

其中 k 具有周期性p的季节性的傅立叶的数量。每一个季节性对应 2k 个系数。在 t 时刻,模型涉及的所有季节性效应可以表示为:

$$s(t) = \sum_{p\in \mathbb{P}}S^*_p(t)$$

每个季节周期性可以单独表示为 additive 或者 multiplicative 的形式:

$$S^*_p(t) = \left\{\begin{matrix}S^{\dagger}_p(t)=T(t) \cdot S_p(t) &  if\ S_p\  is\  multiplicative \\ S_p(t)& otherwise \end{matrix}\right.$$

NeuralProphet根据数据频率和长度自动激活每日、每周或每年的季节性。 既 周期大于2个季节性,激活对应季节性。默认每个季节性的傅立叶项数为:年:k=6,p=365.25,周: k=3,p=7,日:p=1,k=6。

Events and Holidays

对于初始 Prophet 模型中的最后一项,用于处理事件。季节性和事件的处理方式几乎相同 – 使用傅立叶级数。然而,我们希望傅立叶变换不是平滑曲线,而是在给定特定假期时产生非常尖的曲线。而且,由于底层函数是正弦函数,它们很容易扩展到未来。

$$E(t)=\sum_{e \in \mathbb{E}} E_e^{\star}(t)$$

$$E_e(t)=z_e e(t)$$

$$E_e^{\star}(t)= \begin{cases}E_e^{\dagger}(t)=T(t) \cdot E_e(t), & \text { if } f \text { is multiplicative } \\ E_e(t), & \text { otherwise }\end{cases}$$

Auto-Regression

自回归是回顾先前值并将其用作未来值的预测器的概念。最初的先知模型之所以如此有效,是因为它偏离了这一理念,但是为了利用深度学习,我们必须回归。自回归项使用滞后值来预测未来值。

$$y_t = c + \sum_{i=1}^{i=p}\theta _i \cdot y_{t-i} + e_t$$

$$A^t(t),A^t(t+1),…,A^t(t+h-1) = \text{AR-NET}(y_{t-1},y_{t-2},…,y_{t-p})$$

对NeuralProphet对象的n_lags参数设置一个适当的值,就可以在NeuralProphet中启用AR-Net。

例如,将5个滞后期输入AR-Net,并接收3个步骤作为预测。

m = NeuralProphet(
n_forecasts=3,
n_lags=5,
yearly_seasonality=False,
weekly_seasonality=False,
daily_seasonality=False,
m = NeuralProphet(
    n_forecasts=3,
    n_lags=5,
    yearly_seasonality=False,
    weekly_seasonality=False,
    daily_seasonality=False,
)
  • num_hidden_layers参数:增加AR-Net的复杂度
  • ar_sparsity参数:为AR-Net加入正则约束
  • highlight_nth_step_ahead_of_each_forecast参数:突出特定的预测步骤,用法:
m.highlight_nth_step_ahead_of_each_forecast(step_number=m.n_forecasts)
m.highlight_nth_step_ahead_of_each_forecast(step_number=m.n_forecasts)

Lagged Regressors

Prophet 和 NeuralProphet 模型的强大方面之一是它们允许协变量。大多数时间序列预测模型都是单变量的,尽管它们有时会提供多变量版本——ARIMA 与 MARIMA。

在处理带有时间序列预测的协变量时,我们需要确保这些协变量会提前 n 个时间段出现,否则我们的模型将无法预测。我们可以通过将当前协变量滞后 n 个时间段来做到这一点,这由 L(t) 项建模,或者对这些协变量进行预测,由 F(t) 项建模。

滞后回归用于为我们的时间序列预测目标加入其他观察变量。在 t 时刻,我们只知道t-1时刻(包括t-1)前的观察值。

$$L(t) = \sum_{x \in \mathbb{X}}L_x(x_{t-1},x_{t-2},…x_{t-p})$$

只有在启用AR-Net的情况下,才会支持Lagged Regressor

NeuralProphet通过调用add_lagged_regressor函数并给出必要的设置,将Lagged Regressor用于NeuralProphet对象中。

假如有一个名为A的滞后回归项,通过add_lagged_regressor注册它到NeuralProphet

m = m.add_lagged_regressor(names=’A’)

Future Regressors

未来回归器是指具有已知未来值的外部变量。从这个意义上说,未来回归者的功能如果和特殊事件非常相似。这些回归器的过去值对应于训练time stamps,必须与训练数据本身一起提供。

对于future regressors,在t时刻,过去和未来的回归因子(regressor) 都是知道的。

$$F(t)=\sum_{f \in \mathbb{F}} F_f^{\star}(t)$$

$$F_f(t)=d_f f(t)$$

$$F_f^{\star}(t)= \begin{cases}F_f^{\dagger}(t)=T(t) \cdot F_f(t), & \text { if } f \text { is multiplicative } \\ F_f(t), & \text { otherwise }\end{cases}$$

NeuralProphet数据预处理

Missing Data

当没有滞后变量的时候,直接丢掉缺失值就好。有滞后变量的情况下,每个缺失值会导致h + p被丢弃,因此引入数据插值机制;如果不特别指定的话,缺失值用 0 填充。

数据插值: 当Auto-regression 或者 lagged regressor使用的时候,主要采取三个步骤

  • 对于不超过10个值的缺失,使用前后已知的值线性插值;
  • 对于小于20个值的缺失,使用一个滑动窗口大小为30的计算平均值;
  • 如果超过连续30个值缺失的话,不插值,直接丢弃这部分值

Data Normalization

对于观察到的时间序列值,用户可以指定是否希望将这些值标准化。默认情况下,y 值将被最小-最大归一化。如果用户特别将 normalize_y 参数设置为 true,则数据将进行z-score归一化。对协变量也可以进行归一化处理。协变量归一化的默认模式是auto。在这种模式下,除了事件等binary features外,所有其他特征都进行z-score归一化。

用户可以设定归一化的参数,如果不设定,对于二值化数值使用minmax,其他默认使用soft。

Data-Normalization.png

NeuralProphet模型训练

Prophet 使用Stan 实现的 L-BFGS 拟合模型,NeuralProphet依赖PyTorch实现的SGD拟合模型;

Loss Function

NeuralProphet默认使用Huber loss,即smooth L1-loss,如下

$$L_{\text {huber }}(y, \hat{y})= \begin{cases}\frac{1}{2 \beta}(y-\hat{y})^2, & \text { for }|y-\hat{y}|<\beta \\ |y-\hat{y}|-\frac{\beta}{2}, & \text { otherwise }\end{cases}$$

对于给定的阈值$\beta$, 低于阈值$\beta$,损失函数变为mean squared error (MSE);高于阈值$\beta$,损失函数变为mean absolute error (MAE)。用户可以设定MSE, MAE 或者其他PyTorch实现的函数;

Regularization

NeuralProphet使用权重绝对值的缩放和对数变换偏移作为一般正则化函数。

其中$ ϵ\epsilon \in (0, \infty )$ 为偏移的倒数,$ \alpha \in (0, \infty )$为对数变换的比例。$\epsilon$控制权重参数的稀疏程度,$\alpha$控制权重值的大小;

默认情况下,设置$\epsilon =1,$\alpha = 1$

Optimizer

默认使用AdamW

AdamW(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0.0001, maximize=False, capturable=False)

也可以选用SGD

SGD(params, lr=0.01, momentum=0.9, dampening=0, weight_decay=0.001, nesterov=False)

同时也可以使用PyTorch支持的其他 optimizer。

Learning Rate

通过测试的方式来估计一个学习率,针对特定的数据集大小,测试100 + log10(10 + T ) ∗ 50) 次, 测试区间从$\eta = 1e-7$到$\eta = 1e + 2$之间。为了稳定性,分别测试三次求平均:

$$\eta^{\star}=\frac{1}{3} (\log _{10} (\eta_1)+\log _{10} (\eta_2)+\log _{10} (\eta_3)) $$

$$\eta=10^{\eta^{\star}}$$

Batch Size

如果未指定,根据数据量T来决定,

$$B^{\star} =2^{2+\left\lfloor\log _{10}(T)\right\rfloor} $$

$$B  =\min (T, \max (16, \min (256, B^{\star})))$$

Epochs

如果未指定,根据数据量T来决定,

$$ N_{\text {epoch }}^{\star}=\frac{1000 \cdot 2^{\frac{5}{2} \cdot \log _{10}(T)}}{T} $$

$$ N_{\text {epoch }}=\min (500, \max (50, \lfloor N_{\text {epoch }}^{\star} \rfloor))$$

Scheduler

采用1cycle policy,学习率在最初的30%训练时间内从$\frac{\eta}{100}$​上升到$\eta$,接着cosine曲线下降到$\frac{\eta}{5000}$​,直到训练结束。

NeuralProphet的使用

NeuralProphet的使用与Prophet类似。

## pip install neuralprophet
from neuralprophet import NeuralProphet
m = NeuralProphet()
metrics = m.fit(df)
forecast = m.predict(df)
# 可视化结果:
fig_forecast = m.plot(forecast)
fig_components = m.plot_components(forecast)
fig_model = m.plot_parameters()
m = NeuralProphet().fit(df, freq="D")
df_future = m.make_future_dataframe(df, periods=30)
forecast = m.predict(df_future)
fig_forecast = m.plot(forecast)
# 安装
## pip install neuralprophet

# 使用
from neuralprophet import NeuralProphet
m = NeuralProphet()
metrics = m.fit(df)
forecast = m.predict(df)
# 可视化结果:
fig_forecast = m.plot(forecast)
fig_components = m.plot_components(forecast)
fig_model = m.plot_parameters()
# 预测:
m = NeuralProphet().fit(df, freq="D")
df_future = m.make_future_dataframe(df, periods=30)
forecast = m.predict(df_future)
fig_forecast = m.plot(forecast)

超参数说明

class neuralprophet.forecaster.NeuralProphet(growth: Literal['off', 'linear', 'discontinuous'] = 'linear', changepoints: Optional[list] = None, n_changepoints: int = 10, changepoints_range: float = 0.8, trend_reg: float = 0, trend_reg_threshold: Optional[Union[bool, float]] = False, trend_global_local: str = 'global', yearly_seasonality: Union[Literal['auto'], bool, int] = 'auto', weekly_seasonality: Union[Literal['auto'], bool, int] = 'auto', daily_seasonality: Union[Literal['auto'], bool, int] = 'auto', seasonality_mode: Literal['additive', 'multiplicative'] = 'additive', seasonality_reg: float = 0, season_global_local: Literal['global', 'local'] = 'global', n_forecasts: int = 1, n_lags: int = 0, ar_layers: Optional[list] = [], ar_reg: Optional[float] = None, lagged_reg_layers: Optional[list] = [], learning_rate: Optional[float] = None, epochs: Optional[int] = None, batch_size: Optional[int] = None, loss_func: Union[str, torch.nn.modules.loss._Loss, Callable] = 'Huber', optimizer: Union[str, Type[torch.optim.optimizer.Optimizer]] = 'AdamW', newer_samples_weight: float = 2, newer_samples_start: float = 0.0, quantiles: List[float] = [], impute_missing: bool = True, impute_linear: int = 10, impute_rolling: int = 10, drop_missing: bool = False, collect_metrics: Union[List[str], bool, Dict[str, torchmetrics.metric.Metric]] = True, normalize: Literal['auto', 'soft', 'soft1', 'minmax', 'standardize', 'off'] = 'auto', global_normalization: bool = False, global_time_normalization: bool = True, unknown_data_normalization: bool = False, accelerator: Optional[str] = None, trainer_config: dict = {}, prediction_frequency: Optional[dict] = None)
class neuralprophet.forecaster.NeuralProphet(growth: Literal['off', 'linear', 'discontinuous'] = 'linear', changepoints: Optional[list] = None, n_changepoints: int = 10, changepoints_range: float = 0.8, trend_reg: float = 0, trend_reg_threshold: Optional[Union[bool, float]] = False, trend_global_local: str = 'global', yearly_seasonality: Union[Literal['auto'], bool, int] = 'auto', weekly_seasonality: Union[Literal['auto'], bool, int] = 'auto', daily_seasonality: Union[Literal['auto'], bool, int] = 'auto', seasonality_mode: Literal['additive', 'multiplicative'] = 'additive', seasonality_reg: float = 0, season_global_local: Literal['global', 'local'] = 'global', n_forecasts: int = 1, n_lags: int = 0, ar_layers: Optional[list] = [], ar_reg: Optional[float] = None, lagged_reg_layers: Optional[list] = [], learning_rate: Optional[float] = None, epochs: Optional[int] = None, batch_size: Optional[int] = None, loss_func: Union[str, torch.nn.modules.loss._Loss, Callable] = 'Huber', optimizer: Union[str, Type[torch.optim.optimizer.Optimizer]] = 'AdamW', newer_samples_weight: float = 2, newer_samples_start: float = 0.0, quantiles: List[float] = [], impute_missing: bool = True, impute_linear: int = 10, impute_rolling: int = 10, drop_missing: bool = False, collect_metrics: Union[List[str], bool, Dict[str, torchmetrics.metric.Metric]] = True, normalize: Literal['auto', 'soft', 'soft1', 'minmax', 'standardize', 'off'] = 'auto', global_normalization: bool = False, global_time_normalization: bool = True, unknown_data_normalization: bool = False, accelerator: Optional[str] = None, trainer_config: dict = {}, prediction_frequency: Optional[dict] = None)

超参数说明:

Parameter Default Value 说明
growth linear 传off代表没有趋势
changepoints None 手动设置拐点
n_changepoints 5 控制潜在拐点的数量
changepoints_range 0.8 默认值0.8,表示后20%的训练数据无changepoints
trend_reg 0 趋势正则项
trend_reg_threshold False 允许趋势在没有规则化的情况下发生变化。
trend_global_local global 存在多个时间序列时的趋势建模策略。
yearly_seasonality auto 默认6
weekly_seasonality auto 默认4
daily_seasonality auto 默认6
seasonality_mode additive additive,multiplicative
seasonality_reg 0 值越大正则约束越大
season_global_local global global
n_lags 0 定义是否使用AR-Net,n_lags决定AR-Net回看步数,建议取值大于n_forecasts
ar_reg 可选 在AR系数中引入多少稀疏性
ar_layers 可选 AR网络的隐藏层维度
n_forecasts 1 预测范围,1意味着将来预测一步
lagged_reg_layers 可选 Covar Net的隐藏层维度
learning_rate None 如果未指定,自动调整
epochs None 如果未指定,根据数据大小设定
batch_size None
newer_samples_weight 2.0 设置模型拟合向最近观测值倾斜的因子。
newer_samples_start 0 将“较新”样本的开头设置为训练数据的一部分。
loss_func Huber Huber,MSE,MAE或torch.nn.functional.loss
collect_metrics True 默认计算mae 和 rmse
quantiles None 介于(0,1)之间的浮点值列表,表示要估计的分位数集。
impute_missing True 是否自动估算缺失的日期/值
impute_linear 10 要线性估算的缺失日期/值的最大数量
impute_rolling 10 使用滚动平均值估算的最大缺失日期/数值
drop_missing False 是否自动从数据中删除丢失的样本
normalize soft 要应用于时间序列的规范化类型。
global_normalization False 激活全局规范化
global_time_normalization True 指定全局时间规范化
unknown_data_normalization False 指定未知数据规范化
accelerator auto 使用“自动”可自动选择可用的加速器。
trainer_config 附加训练器配置参数词典。
prediction_frequency 应进行预测的周期性间隔。

NeuralProphet实战:基于Optuna的超参数优化

NeuralProphet 主要超参介绍

  • 趋势相关
    • growth :趋势为线性还是没有趋势,NeuralProphet提供了一个新颖的增长方式discontinuous,允许趋势中断与跳跃,也就是会更灵活(与过拟合)
    • changepoints :变更点列表,一般让NeuralProphet自己找
    • n_changepoints :变更点个数
    • changepoints_range :变更点探测的区间,默认为8, 这个一般影响较大
    • trend_reg:趋势项的正则(限制),也就是趋势项的灵活程度,这就是文中开头所说的regulation之一,影响很大
  • 季节相关
    • yearly_seasonality/ weekly_seasonality /daily_seasonality : 是否自动探测这三个周期的季节分量,NeuralProphet 会根据数据集的长度,分辨率来自动设置。我一般会禁用掉,然后自己添加周期,并且调整他们的参数:傅里叶级数
    • seasonality_mode :additive还是multiplicative,一般来说multiplicative会更灵活
    • seasonality_reg:季节项的正则限制,也是影响很大
  • AR 相关
    • n_lags:滞后的阶数,如果是多步预测(n_forecasts> 1),需要大于n_forecasts
    • ar_reg: AR项的正则
  • 神经网络结构
    • ar_layers:层数,也是超参数
  • 拟合参数
    • learning_rate:学习率
    • epochs:epochs拟合次数
    • batch_size:每次拟合的batch

直接上代码:

import pandas as pd
from neuralprophet import NeuralProphet, set_log_level
import optuna
set_log_level("ERROR")
df = pd.read_csv('data/data.csv')
df['ds'] = pd.to_datetime(df['ds'])
events = pd.read_csv("data/holidays-events.csv")
# 定义NeuralProphet模型
def objective(trial):
# 定义模型参数空间
newer_samples_weight = trial.suggest_int('newer_samples_weight', 0, 100)
newer_samples_start = trial.suggest_float('newer_samples_start', 0.001, 0.999)
seasonality_reg = trial.suggest_float('seasonality_reg', 0.1, 500)
seasonality_mode = trial.suggest_categorical('seasonality_mode', ['additive', 'multiplicative'])
yearly_seasonality = trial.suggest_int('yearly_seasonality', 1, 10)
weekly_seasonality = trial.suggest_int('weekly_seasonality', 1, 10)
epochs = trial.suggest_int('epochs', 2, 30)
learning_rate = trial.suggest_float('learning_rate', 0.001, 0.1, log=True)
changepoints_range = trial.suggest_float('changepoints_range', 0.6, 0.9)
n_changepoints = trial.suggest_int('n_changepoints', 4, 10)
trend_reg = trial.suggest_float('trend_reg', 0.001, 1, log=True)
n_lags = trial.suggest_int('n_lags', 10, 30)
n_forecasts = trial.suggest_int('n_forecasts', 10, 30)
m = NeuralProphet(
newer_samples_weight=newer_samples_weight,
newer_samples_start=newer_samples_start,
yearly_seasonality=yearly_seasonality,
weekly_seasonality=weekly_seasonality,
seasonality_reg=seasonality_reg,
seasonality_mode=seasonality_mode,
learning_rate=learning_rate,
epochs=epochs,
changepoints_range=changepoints_range,
n_changepoints=n_changepoints,
trend_reg=trend_reg,
n_lags=n_lags,
n_forecasts=n_forecasts,
loss_func='MSE',
collect_metrics=['rmse']
for e in events['event'].unique():
m.add_events(e, mode='multiplicative')
df_with_events = m.create_df_with_events(df, events)
df_train, df_val = m.split_df(df_with_events, freq="D", valid_p=0.05)
metrics = m.fit(df_train, freq="D", validation_df=df_val, metrics=True, progress=False)
return metrics['RMSE_val'].min()
# 定义Optuna study对象
study = optuna.create_study(direction='minimize')
# 运行参数搜索
study.optimize(objective, n_trials=50)
# 打印最佳参数和目标值
print('Best parameter: ', study.best_params)
print('Best target value: ', study.best_value)
最终输出的结果为:
Best parameter: {'newer_samples_weight': 26, 'newer_samples_start': 0.6024308578115192, 'seasonality_reg': 306.3632013108877, 'seasonality_mode': 'multiplicative', 'yearly_seasonality': 9, 'weekly_seasonality': 4, 'epochs': 28, 'learning_rate': 0.09906363251832066, 'changepoints_range': 0.6319992574004804, 'n_changepoints': 9, 'trend_reg': 0.16600258440062496, 'n_lags': 24, 'n_forecasts': 12}
fig1 = optuna.visualization.plot_param_importances(study)
fig1.show()
fig2 = optuna.visualization.plot_optimization_history(study)
fig2.show()
fig3 = optuna.visualization.plot_parallel_coordinate(study)
fig3.show()
import pandas as pd
from neuralprophet import NeuralProphet, set_log_level
import optuna

set_log_level("ERROR")

df = pd.read_csv('data/data.csv')
df['ds'] = pd.to_datetime(df['ds'])
events = pd.read_csv("data/holidays-events.csv")


# 定义NeuralProphet模型
def objective(trial):
    # 定义模型参数空间
    newer_samples_weight = trial.suggest_int('newer_samples_weight', 0, 100)
    newer_samples_start = trial.suggest_float('newer_samples_start', 0.001, 0.999)
    seasonality_reg = trial.suggest_float('seasonality_reg', 0.1, 500)
    seasonality_mode = trial.suggest_categorical('seasonality_mode', ['additive', 'multiplicative'])
    yearly_seasonality = trial.suggest_int('yearly_seasonality', 1, 10)
    weekly_seasonality = trial.suggest_int('weekly_seasonality', 1, 10)
    epochs = trial.suggest_int('epochs', 2, 30)
    learning_rate = trial.suggest_float('learning_rate', 0.001, 0.1, log=True)
    changepoints_range = trial.suggest_float('changepoints_range', 0.6, 0.9)
    n_changepoints = trial.suggest_int('n_changepoints', 4, 10)
    trend_reg = trial.suggest_float('trend_reg', 0.001, 1, log=True)
    n_lags = trial.suggest_int('n_lags', 10, 30)
    n_forecasts = trial.suggest_int('n_forecasts', 10, 30)

    m = NeuralProphet(
        newer_samples_weight=newer_samples_weight,
        newer_samples_start=newer_samples_start,
        yearly_seasonality=yearly_seasonality,
        weekly_seasonality=weekly_seasonality,
        seasonality_reg=seasonality_reg,
        seasonality_mode=seasonality_mode,
        learning_rate=learning_rate,
        epochs=epochs,
        changepoints_range=changepoints_range,
        n_changepoints=n_changepoints,
        trend_reg=trend_reg,
        n_lags=n_lags,
        n_forecasts=n_forecasts,
        loss_func='MSE',
        collect_metrics=['rmse']
    )

    for e in events['event'].unique():
        m.add_events(e, mode='multiplicative')
    df_with_events = m.create_df_with_events(df, events)

    df_train, df_val = m.split_df(df_with_events, freq="D", valid_p=0.05)
    metrics = m.fit(df_train, freq="D", validation_df=df_val, metrics=True, progress=False)
    return metrics['RMSE_val'].min()


# 定义Optuna study对象
study = optuna.create_study(direction='minimize')

# 运行参数搜索
study.optimize(objective, n_trials=50)

# 打印最佳参数和目标值
print('Best parameter: ', study.best_params)
print('Best target value: ', study.best_value)

最终输出的结果为:
Best parameter:  {'newer_samples_weight': 26, 'newer_samples_start': 0.6024308578115192, 'seasonality_reg': 306.3632013108877, 'seasonality_mode': 'multiplicative', 'yearly_seasonality': 9, 'weekly_seasonality': 4, 'epochs': 28, 'learning_rate': 0.09906363251832066, 'changepoints_range': 0.6319992574004804, 'n_changepoints': 9, 'trend_reg': 0.16600258440062496, 'n_lags': 24, 'n_forecasts': 12}

fig1 = optuna.visualization.plot_param_importances(study)
fig1.show()

fig2 = optuna.visualization.plot_optimization_history(study)
fig2.show()

fig3 = optuna.visualization.plot_parallel_coordinate(study)
fig3.show()
hyperparameter-importances.png

基于训练好的超参数使用模型:

import pandas as pd
from neuralprophet import NeuralProphet, set_log_level
set_log_level("ERROR")
df = pd.read_csv('data/data.csv')
df['ds'] = pd.to_datetime(df['ds'])
events = pd.read_csv("data/holidays-events.csv")
para = {'newer_samples_weight': 26,
'newer_samples_start': 0.6024308578115192,
'seasonality_reg': 306.3632013108877,
'seasonality_mode': 'multiplicative',
'yearly_seasonality': 9,
'weekly_seasonality': 4,
'epochs': 28,
'learning_rate': 0.09906363251832066,
'changepoints_range': 0.6319992574004804,
'n_changepoints': 9,
'trend_reg': 0.16600258440062496,
'n_lags': 24,
'n_forecasts': 12}
m = NeuralProphet(**para)
for e in events['event'].unique():
m.add_events(e, mode='multiplicative')
df_with_events = m.create_df_with_events(df, events)
metrics = m.fit(df_with_events)
forecast = m.predict(df_with_events)
fig1 = m.plot(forecast)
fig2 = m.plot_components(forecast)
fig3 = m.plot_parameters()
fig1.show()
fig2.show()
fig3.show()
import pandas as pd
from neuralprophet import NeuralProphet, set_log_level

set_log_level("ERROR")

df = pd.read_csv('data/data.csv')
df['ds'] = pd.to_datetime(df['ds'])
events = pd.read_csv("data/holidays-events.csv")

para = {'newer_samples_weight': 26,
        'newer_samples_start': 0.6024308578115192,
        'seasonality_reg': 306.3632013108877,
        'seasonality_mode': 'multiplicative',
        'yearly_seasonality': 9,
        'weekly_seasonality': 4,
        'epochs': 28,
        'learning_rate': 0.09906363251832066,
        'changepoints_range': 0.6319992574004804,
        'n_changepoints': 9,
        'trend_reg': 0.16600258440062496,
        'n_lags': 24,
        'n_forecasts': 12}

m = NeuralProphet(**para)

for e in events['event'].unique():
    m.add_events(e, mode='multiplicative')
df_with_events = m.create_df_with_events(df, events)

metrics = m.fit(df_with_events)
forecast = m.predict(df_with_events)

fig1 = m.plot(forecast)
fig2 = m.plot_components(forecast)
fig3 = m.plot_parameters()

fig1.show()
fig2.show()
fig3.show()

参考链接:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK