Press "Enter" to skip to content

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

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

:bulb: 作者: 韩信子 @ ShowMeAI
:blue_book:机器学习实战系列: www.showmeai.tech/tutorials/4…
:blue_book:本文地址: www.showmeai.tech/article-det…
:loudspeaker: 声明:版权所有,转载请联系平台与作者并注明出处
:loudspeaker: 收藏ShowMeAI查看更多精彩内容

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

 

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

 

 

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

 

 

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

 

 

:bulb: 环境配置

 

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

 

:bulb: 工具库架构

 

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

 

 

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

 

:bulb: 数据加载

 

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) 或指数移动平均。完整预处理方法列表可以在:blue_book: 这里 查看。

 

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

 

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

 

:bulb: 模型库

 

 

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

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

 

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

 

 

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

 

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()

 

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

 

 

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

 

:bulb: 自动机器学习

 

对模型进行超参数调优也是一个很麻烦的事情,但 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)

 

:bulb: 模型选择与模型集成

 

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,完整列表可以查看 :blue_book: 这里

 

:bulb: 存储和加载模型

 

如果您想存储训练过的模型或加载,现有的 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 上效果最好的模型。不过我们创建好的配置文件包含了所有集成模型的元信息。

 

:bulb: 评估管道(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 来评估我们模型的性能。

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。