💡 作者:韩信子@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)
:在t0
和 tf
范围之间切出一个子集,输入参数可以是任何合理的日期时间格式,也可以是 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 提供了一系列不同的模型,可以用于时间序列等问题:
大家也可以 📘在这里 定义自己的模型。
下面的例子基于 📘航空乘客数据集,进行时间序列建模展示。
🏆 实战数据集下载(百度网盘):点击 这里 获取本文 [15] 使用 Merlion 库快速开发时间序列模型 『Monthly Airline Passenger Numbers 1949-1960 数据集』
⭐ ShowMeAI官方GitHub:https://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 包,它支持:
以下示例使用与上述相同的数据集,并展示了如何将 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 上效果最好的模型。不过我们创建好的配置文件包含了所有集成模型的元信息。
最后要提到的是,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 来评估我们模型的性能。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。