股市预测,销量预测,病毒传播...一个时间序列建模套路搞定全部!⛵

💡 作者:韩信子@ShowMeAI
📘 深度学习实战系列https://www.showmeai.tech/tutorials/42
📘 NLP 实战系列https://www.showmeai.tech/tutorials/45
📘 本文地址https://www.showmeai.tech/article-detail/288
📢 声明:版权所有,转载请联系平台与作者并注明出处
📢 收藏ShowMeAI查看更多精彩内容

我们在日常业务中遇到的很多问题,都可以归属到时间序列范畴内——股市涨跌变化、电商销量预测、传染病传播挖掘等,其实都可以用『时间序列』解决。

时间序列建模工具库有很多,比较知名的有 Uber 开源的 📘Orbit工具库、LinkedIn 开源的 📘Greykite 工具库,提供了部分解决方法。

最近 Salesforce 团队研发的 📘Merlion 工具库声名鹊起。Merlion 作为后起之秀,覆盖非常全面,提供了很多时间序列的算法解决方案。本篇 ShowMeAI 就给大家介绍一下如何使用 Merlion 解决『时间序列』问题。

Merlion 是一个用于时间序列的智能Python 库,提供了一个端到端的机器学习框架,包括加载和转换数据,建立和训练模型,模型结果后处理,以及评估模型性能Merlion 支持各种时间序列学习任务,包括单变量和多变量时间序列的预测、异常检测和变化点检测。这个库的目的是为工程师和研究人员提供一站式解决方案,快速开发特定的时间序列需求模型,并在多个时间序列数据集上进行基准测试。

💡 环境配置

Merlion最基本的安装只需要 运行命令 pip install salesforce-merlion。但这个基础版本并不包含所有模型,如果要安装全部模型,如 LightGBM 或 Facebook 的 Prophet,我们切换成命令 pip install "salesforce-merlion[all]" 就可以。

💡 工具库架构

在深入学习使用 Merlion 解决时间序列问题之前,让我们先看看它的架构。下图按时间顺序显示了它的不同模型以及它们如何协同工作。

在本文中,ShowMeAI 将聚焦于时间序列,介绍除 后处理/post processing 模块之外的所有部分(因为这个部分仅用于异常检测,并不一定与时间序列问题相关)。

💡 数据加载

Merlion 的数据结构是 TimeSeries,支持多变量单变量时间序列。其底层是对一系列 UnivariateTimeSeries 进行的封装。

为了将数据放入所需的数据结构中,我们使用 TimeSeries 的函数 .from_pd()。这个函数接受带有 DatetimeIndex 的 DataFrame 作为输入,并且默认检查每个索引是否唯一以及是否设置了频率 freq(默认1h)。

以下为从 pandas DataFrame 加载单变量时间序列的示例代码。

# 没有缺失值情况的简单案例
from merlion.utils import TimeSeries
import pandas as pd
import numpy as np


# 注意,这里需要手动设置freq参数,否则数据会混乱
ts_series = pd.Series(data = [20, 21, 25, 18],
                      index = pd.date_range('2020-04-01', '2020-04-04', freq='D'),
                      name = 'v'
                     )
ts_df = pd.DataFrame(ts_series)

# 构建TimeSeries对象
ts = TimeSeries.from_pd(ts_df)

如果输入的『单变量时间序列』包含缺失值或 nan 值,Merlion 会删除它们及其对应的索引。

在输入『多元时间序列』面临多序列不对齐的情况时,Merlion 工具库可以检查多元时间序列『是否包含任何缺失值』或『每个变量的索引是否未对齐』(调用 TimeSeries.is_aligned 属性)。如果没有对齐(.is_aligned 属性为 False),可以调用 .align() 函数对其进行修复对齐。

# 无缺失的简单情况
from merlion.utils import TimeSeries
import pandas as pd
import numpy as np

# 多元时间序列
ts_series_1 = pd.Series(data = [20, 21, 25, 18],
                      index = pd.date_range('2020-04-01', '2020-04-04', freq='D')
                     )
ts_series_2 = pd.Series(data = [20, 21, np.nan, 18],
                      index = pd.date_range('2020-04-01', '2020-04-04', freq='D')
                     )
ts_df = pd.DataFrame({'v1': ts_series_1, 'v2': ts_series_2})


# 基于Dataframe构建TimeSeries对象
ts = TimeSeries.from_pd(ts_df)

# 输出是否对齐
print(ts.is_aligned)

# 对齐操作
ts_aligned = ts.align()
print(ts_aligned.is_aligned)

默认情况下,.align() 函数将合并任何单个单变量中存在的所有时间戳,并使用线性插值来估算缺失值。

切片和分割

除了 .align() 函数,Merlion 带有另外两个方便的函数:

  • .window(t0, tf) :在t0tf 范围之间切出一个子集,输入参数可以是任何合理的日期时间格式,也可以是 Unix 时间戳。
  • .bisect(t) :类似于 .window(),将时间序列分成左右部分。

预处理

Merlion 提供常见的数据 预处理转换技术 ,例如最小-最大归一化、幂变换 (box-cox) 或指数移动平均。完整预处理方法列表可以在📘这里 查看。

比如下列代码就是在建模步骤之前使用『最小 - 最大归一化』对数据预处理:

from merlion.transform.normalize import MinMaxNormalize
# 初始化数据预处理器
transform = MinMaxNormalize()
# 拟合
transform.train(ts_aligned)
# 应用预处理器变换
ts_transformed = transform(ts_aligned)
# 逆变换
transform.invert(ts_transformed)

💡 模型库

Merlion 提供了一系列不同的模型,可以用于时间序列等问题:

  • ARIMA (自回归综合移动平均线)
  • SARIMA (具有用户指定季节性的 ARIMA)
  • ETS (误差、趋势、季节性)
  • Prophet (围绕 Facebook 的 Prophet 的包装)
  • Smoother (用于单变量时间序列预测的多尺度指数平滑器)
  • 向量自回归 用于多元时间序列预测的
  • Bagging (随机森林)和 提升树(lightgbm)
  • 长短期记忆网络

大家也可以 📘在这里 定义自己的模型。

下面的例子基于 📘航空乘客数据集,进行时间序列建模展示。

🏆 实战数据集下载(百度网盘):公众号『ShowMeAI研究中心』回复『实战』,或者点击 这里 获取本文 [15] 使用 Merlion 库快速开发时间序列模型Monthly Airline Passenger Numbers 1949-1960 数据集

ShowMeAI官方GitHubhttps://github.com/ShowMeAI-Hub

import pandas as pd
from merlion.utils import TimeSeries
# 加载数据
air_pass = pd.read_csv("airline-passengers.csv")
# 把日期设置为索引
air_pass.set_index('Month', inplace=True)
air_pass.index = pd.to_datetime(air_pass.index)
# 一定要确保freq设定好
air_pass.index.freq = 'MS'


# 读取为TimeSeries对象
air_pass_ts = TimeSeries.from_pd(air_pass, freq='MS')
print(air_pass_ts.is_aligned)


# 使用 .bisect() 函数切分数据为训练集和测试集
# 我们希望预估未来6个月的乘客量
air_pass_ts_train, air_pass_ts_test = air_pass_ts.bisect('1960-07-01')

上述代码中:我们首先读取数据为 DataFrame 格式,再将其转换为 Merlion 的 TimeSeries 数据结构,之后检查数据集是否对齐(比如有没有缺失的索引),最后我们可以将数据拆分为训练集和测试集。

from merlion.models.forecast.trees import LGBMForecaster, LGBMForecasterConfig
# 设定模型配置
lgbm_config = LGBMForecasterConfig(maxlags = 30,
                                   max_forecast_steps=len(air_pass_ts_test)
                                  )
# 初始化模型
lgbm = LGBMForecaster(lgbm_config)
# 拟合模型
lgbm.train(air_pass_ts_train)
# 预估
lgbm_fc = lgbm.forecast(air_pass_ts_test.time_stamps)

上述代码使用 LightGBM 模型,基于过去的数据对未来进行预测。如果我们想可视化预测结果,可以使用 Merlion 中的两种方法:

  • .plot_forecast()
  • .plot_forecast_plotly()

下面为绘图示例代码。

import matplotlib.pyplot as plt
fig, ax = lgbm.plot_forecast(time_series=air_pass_ts_test)
plt.show()

我们得到如下的预估结果和真实结果对比图。

大家可能看出来了,这个预估结果并不是太好,我们可以做进一步的调整优化(例如使用不同的参数或变换)。我们这里只做可视化的演示,暂时不纠结预估效果。

💡 自动机器学习

对模型进行超参数调优也是一个很麻烦的事情,但 Merlion 附带了一个 AutoML 包,它支持:

  • SARIMA 的自动超参数选择
  • 自动季节性检测
  • Facebook Prophet 的自动(多)季节性检测
  • ETS 的自动季节性检测

以下示例使用与上述相同的数据集,并展示了如何将 AutoML 用于 SARIMA 模型。

from merlion.models.automl.autosarima import AutoSarima, AutoSarimaConfig


sarima_config = AutoSarimaConfig(auto_pqPQ=True, auto_d=True, auto_D=True, auto_seasonality=True,
                           approximation=True, maxiter=5)
sarima = AutoSarima(sarima_config)


# 模型训练
train_pred, train_err = sarima.train(
    air_pass_ts_train, train_config={"enforce_stationarity": True,
                              "enforce_invertibility": True}
)
sarima_fc = sarima.forecast(air_pass_ts_test.time_stamps)

💡 模型选择与模型集成

Merlion 提供了两种常用的模型集成技术:

  • ① 对多个模型取平均值中位数的传统集成方法
  • ② 自动模型选择

我们先看看传统集成方法的应用:

# 使用lgbm和autosarima两个方法
from merlion.models.forecast.trees import LGBMForecaster, LGBMForecasterConfig
from merlion.models.automl.autosarima import AutoSarima, AutoSarimaConfig


# 使用模型集成技术
from merlion.evaluate.forecast import ForecastMetric
from merlion.models.ensemble.combine import Mean, ModelSelector
from merlion.models.ensemble.forecast import ForecasterEnsemble, ForecasterEnsembleConfig


# 设定训练设置
from merlion.models.ensemble.base import EnsembleTrainConfig

# 定义模型
lgbm_config = LGBMForecasterConfig(maxlags = 30, max_forecast_steps=len(air_pass_ts_test))
lgbm = LGBMForecaster(lgbm_config)


sarima_config = AutoSarimaConfig(auto_pqPQ=True, auto_d=True, auto_D=True, auto_seasonality=True, approximation=True, maxiter=5)
sarima = AutoSarima(sarima_config)


# 传统集成,多模型求均值
ensemble_config = ForecasterEnsembleConfig(
    combiner=Mean(), models=[lgbm,sarima]
)


# 集成配置
# 我们使用20%的数据作为验证集
ensemble_train_config = EnsembleTrainConfig(valid_frac=0.2,
                                            per_model_train_configs=[None,{
                                                "enforce_stationarity": True,
                                                 "enforce_invertibility": True
                                            }])
# 训练与预测
ensemble = ForecasterEnsemble(config=ensemble_config)
ensemble.train(air_pass_ts_train,train_config=ensemble_train_config)
ensemble.forecast(air_pass_ts_test.time_stamps)

下面的代码是自动模型选择的方法示例代码:

# 使用lgbm和autosarima两个方法
from merlion.models.forecast.trees import LGBMForecaster, LGBMForecasterConfig
from merlion.models.automl.autosarima import AutoSarima, AutoSarimaConfig


# 使用集成技术
from merlion.evaluate.forecast import ForecastMetric
from merlion.models.ensemble.combine import Mean, ModelSelector
from merlion.models.ensemble.forecast import ForecasterEnsemble, ForecasterEnsembleConfig


# 通过评估指标来选择模型
from merlion.evaluate.forecast import ForecastMetric


# 定义模型
lgbm_config = LGBMForecasterConfig(maxlags = 5, max_forecast_steps=len(air_pass_ts_test))
lgbm = LGBMForecaster(lgbm_config)

sarima_config = AutoSarimaConfig(auto_pqPQ=True, auto_d=True, auto_D=True, auto_seasonality=True, approximation=True, maxiter=5)
sarima = AutoSarima(sarima_config)

# 通过sMAPE指标选择最佳模型
selector_config = ForecasterEnsembleConfig(
    combiner=ModelSelector(metric=ForecastMetric.sMAPE))
selector = ForecasterEnsemble(
    config=selector_config, models=[lgbm, sarima])

selector.train(air_pass_ts_train)
selector.forecast(air_pass_ts_test.time_stamps)

除了 sMAPE Merlion 还支持许多其他错误指标,例如 MAE 或 RMSE,完整列表可以查看 📘这里

💡 存储和加载模型

如果您想存储训练过的模型或加载,现有的 Merlion 的所有模型都带有 .save().load() 类方法。您还可以在适用于任意模型的 modelFactory 包的帮助下加载模型。这 .save() 方法在给定路径创建一个新目录,它存储模型的配置(json)以及它的状态(二进制)。

以下示例显示了我们如何从上面的集成示例中保存和加载模型。

# 存储与加载模型
from merlion.models.factory import ModelFactory
import json
import pprint

# 我们只保存使用了的模型
selector.save("models",save_only_used_models=True)

# 我们输出模型配置看一下
pp = pprint.PrettyPrinter()
with open("models/config.json") as f:
    pp.pprint(json.load(f))

# 使用ForecasterEnsemble加载模型
selector_loaded = ForecasterEnsemble.load('models/')

# 或者使用ModelFactory加载模型
mdl_factory_selector = ModelFactory.load(name="ForecasterEnsemble", model_path='models/')

默认情况下 .save() 方法会将所有定义的模型存储在我们本地。在这个例子中,我们设置 save_only_used_models=True,所以我们只存储评估指标 sMAPE 上效果最好的模型。不过我们创建好的配置文件包含了所有集成模型的元信息。

💡 评估管道(pipeline)

最后要提到的是,Merlion 有一个非常酷的功能来模拟实时模型部署。这使我们能够根据(多个)评估指标来评估我们开发的预测器的质量。

这种模拟评估与滑动交叉验证(rolling cross validation)非常相似,在时间序列建模中是很常见的验证方法。

下述代码是我们在之前开发的 lgbm 模型上模拟部署:

from merlion.evaluate.forecast import ForecastEvaluator, ForecastEvaluatorConfig, ForecastMetric


def create_evaluator(model):
    # 重新初始化模型
    model.reset()
    evaluator = ForecastEvaluator(
        model=model, config=ForecastEvaluatorConfig(
            cadence="90d", horizon="180d", retrain_freq="90d", train_window="360d")
    )
    return evaluator

lgbm_evaluator = create_evaluator(lgbm)
lgbm_train_result, lgbm_test_result = lgbm_evaluator.get_predict(train_vals=air_pass_ts_train, test_vals=air_pass_ts_test)

rmse = lgbm_evaluator.evaluate(
    ground_truth=air_pass_ts_test,
    predict=lgbm_test_result,
    metric=ForecastMetric.RMSE)

print(f"{type(lgbm).__name__} RMSE:  {rmse:.3f}")

在本例中,我们将间隔设置为 90d 意味着每 3 个月训练模型预测未来 6 个月(horizon = 180d)。其他的参数设定,包括模型每 3 个月重新训练一次(retrain_freq=90d) 并使用 12 个月(train_window=360)的训练数据。最后,我们计算 RMSE 来评估我们模型的性能。

💡 相关资源

posted @ 2022-08-08 21:52  ShowMeAI  阅读(201)  评论(0编辑  收藏  举报