作者 | luanhz

来源 | 小数志

导读

时序预测是一类经典的问题,在学术界和工业界都有着广泛的研究和应用。甚至说,世间万物加上时间维度后都可抽象为时间序列问题,例如股票价格、天气变化等等。关于时序预测问题的相关理论也极为广泛,除了经典的各种统计学模型外,当下火热的机器学习以及深度学习中的循环神经网络也都可以用于时序预测问题的建模。今天,本文就来介绍三种方式的简单应用,并在一个真实的时序数据集上加以验证。

时间序列预测,其主要任务是基于某一指标的历史数据来预测其在未来的取值,例如上图中的曲线记录了1949年至1960年共12年144个月份的每月航班乘客数(具体单位未经考证),那么时序预测要解决的问题就是:给定前9年的历史数据,例如1949-1957,那么能否预测出1958-1960两年间的乘客数量的问题。

为了解决这一问题,大概当前主流的解决方式有4种:

  • 统计学模型,较为经典的AR系列,包括AR、MA、ARMA以及ARIMA等,另外Facebook(准确的讲,现在应该叫Meta了)推出的Prophet模型,其实本质上也是一种统计学模型,只不过是传统的趋势、周期性成分的基础上,进一步细化考虑了节假日、时序拐点等因素的影响,以期带来更为精准的时序规律刻画;

  • 机器学习模型,在有监督机器学习中,回归问题主要解决的是基于一系列Feature来预测某一Label的可能取值的问题,那么当以历史数据作为Feature时其实自然也就可以将时序预测问题抽象为回归问题,从这一角度讲,所有回归模型都可用于解决时序预测。关于用机器学习抽象时序预测,推荐查看这篇论文《Machine Learning Strategies for Time Series Forecasting》;

  • 深度学习模型,深度学习主流的应用场景当属CV和NLP两大领域,其中后者就是专门用于解决序列问题建模的问题,而时间序列当然属于序列数据的一种特殊形式,所以自然可以运用循环神经网络来建模时序预测;

  • 隐马尔科夫模型,马尔科夫模型是用于刻画相邻状态转换间的经典抽象,而隐马尔科夫模型则在其基础上进一步增加了隐藏状态,来以此丰富模型的表达能力。但其一大假设条件是未来状态仅与当前状态有关,而不利于利用多个历史状态来共同参与预测,较为常用的可能就是天气预报的例子了。

本文主要考虑前三种时序预测建模方法,并分别选取:1)Prophet模型,2)RandomForest回归模型,3)LSTM三种方案加以测试。

首先在这个航班乘客真实数据集上进行测试,依次对比三个所选模型的预测精度。该数据集共有12年间每个月的乘客数量,以1958年1月作为切分界面划分训练集和测试集,即前9年的数据作为训练集,后3年的数据作为测试集验证模型效果。数据集切分后的示意图如下:

df = pd.read_csv("AirPassengers.csv", parse_dates=["date"]).rename(columns={"date":"ds", "value":"y"})
X_train = df[df.ds<"19580101"]
X_test = df[df.ds>="19580101"]plt.plot(X_train['ds'], X_train['y'])
plt.plot(X_test['ds'], X_test['y'])

1.Prophet模型预测。Prophet是一个高度封装好的时序预测模型,接受一个DataFrame作为训练集(要求有ds和y两个字段列),在预测时也接受一个DataFrame,但此时只需有ds列即可,关于模型的详细介绍可参考其官方文档:https://facebook.github.io/prophet/。模型训练及预测部分核心代码如下:

from prophet import Prophet
pro = Prophet()
pro.fit(X_train)
pred = pro.predict(X_test)pro.plot(pred)

训练后的结果示意图如下:

当然,这是通过Prophet内置的可视化函数给出的结果,也可通过手动绘制测试集真实标签与预测结果间的对比:

易见,虽然序列的整体走势上具有良好的拟合结果,但在具体取值上其实差距还是比较大的。

2.机器学习模型,这里选用常常用作各种baseline的RandomForest模型。在使用机器学习实现时序预测时,通常需要通过滑动窗口的方式来提取特征和标签,而后在实现预测时实际上也需滑动的截取测试集特征实现单步预测,参考论文《Machine Learning Strategies for Time Series Forecasting》中的做法,该问题可大致描述如下:

据此,设置特征提取窗口长度为12,构建训练集和测试集的方式如下:

data = df.copy()
n = 12
for i in range(1, n+1):data['ypre_'+str(i)] = data['y'].shift(i)
data = data[['ds']+['ypre_'+str(i) for i in range(n, 0, -1)]+['y']]# 提取训练集和测试集
X_train = data[data['ds']<"19580101"].dropna()[['ypre_'+str(i) for i in range(n, 0, -1)]]
y_train = data[data['ds']<"19580101"].dropna()[['y']]
X_test = data[data['ds']>="19580101"].dropna()[['ypre_'+str(i) for i in range(n, 0, -1)]]
y_test = data[data['ds']>="19580101"].dropna()[['y']]# 模型训练和预测
rf = RandomForestRegressor(n_estimators=10, max_depth=5)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)# 结果对比绘图
y_test.assign(yhat=y_pred).plot()

可见,预测效果也较为一般,尤其是对于最后两年的预测结果,与真实值差距还是比较大的。用机器学习模型的思维很容易解释这一现象:随机森林模型实际上是在根据训练数据集来学习曲线之间的规律,由于该时序整体呈现随时间增长的趋势,所以历史数据中的最高点也不足以cover住未来的较大值,因而在测试集中超过历史数据的所有标签其实都是无法拟合的。

3.深度学习中的循环神经网络,其实深度学习一般要求数据集较大时才能发挥其优势,而这里的数据集显然是非常小的,所以仅设计一个最为简单的模型:1层LSTM+1层Linear。模型搭建如下:

class Model(nn.Module):def __init__(self):super().__init__()self.rnn = nn.LSTM(input_size=1, hidden_size=10, batch_first=True)self.linear = nn.Linear(10, 1)def forward(self, x):x, _ = self.rnn(x)x = x[:, -1, :]x = self.linear(x)return x

数据集构建思路整体同前述的机器学习部分,而后,按照进行模型训练炼丹,部分结果如下:

# 数据集转化为3D
X_train_3d = torch.Tensor(X_train.values).reshape(*X_train.shape, 1)
y_train_2d = torch.Tensor(y_train.values).reshape(*y_train.shape, 1)
X_test_3d = torch.Tensor(X_test.values).reshape(*X_test.shape, 1)
y_test_2d = torch.Tensor(y_test.values).reshape(*y_test.shape, 1)# 模型、优化器、评估准则
model = Model()
creterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters())# 训练过程
for i in range(1000):out = model(X_train_3d)loss = creterion(out, y_train_2d)optimizer.zero_grad()loss.backward()optimizer.step()if (i+1)%100 == 0:y_pred = model(X_test_3d)loss_test = creterion(y_pred, y_test_2d)print(i, loss.item(), loss_test.item())# 训练结果
99 65492.08984375 188633.796875
199 64814.4375 187436.4375
299 64462.09765625 186815.5
399 64142.70703125 186251.125
499 63835.5 185707.46875
599 63535.15234375 185175.1875
699 63239.39453125 184650.46875
799 62947.08203125 184131.21875
899 62657.484375 183616.203125
999 62370.171875 183104.671875

通过上述1000个epoch,大体可以推断该模型不会很好的拟合了,所以果断放弃吧!

当然必须指出的是,上述测试效果只能说明3种方案在该数据集上的表现,而不能代表这一类模型在用于时序预测问题时的性能。实际上,时序预测问题本身就是一个需要具体问题具体分析的场景,没有放之四海而皆准的好模型,就像“No Free Lunch”一样!

本文仅是作为时序预测系列推文的一个牛刀小试,后续将不定期更新其他相关心得和总结。

资讯

Meta开发AI语音助手,助力元宇宙

技术

10个超级常用的Python方法总结

技术

5分钟速通 AI 计算机视觉发展应用

资讯

M2芯片终于要来了?全线换新

分享

点收藏

点点赞

点在看

时序预测的三种方式:统计学模型、机器学习、循环神经网络相关推荐

  1. linux跳出循环的三种方式,shell study-13day--跳出循环(break、continue)

    1.跳出循环(break与continue) (1)跳出循环 在使用循环语句进行循环的过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell提供了两个命令来实现该功能:break和conti ...

  2. Tensorflow 2.x(keras)源码详解之第九章:模型训练和预测的三种方法(fittf.GradientTapetrain_steptf.data)

      大家好,我是爱编程的喵喵.双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中.从事机器学习以及相关的前后端开发工作.曾在阿里云.科大讯飞.CCF等比赛获得多次Top名次.现 ...

  3. 三种方式实现观察者模式 及 Spring中的事件编程模型

    观察者模式可以说是众多设计模式中,最容易理解的设计模式之一了,观察者模式在Spring中也随处可见,面试的时候,面试官可能会问,嘿,你既然读过Spring源码,那你说说Spring中运用的设计模式吧, ...

  4. 3.3 keras模型构建的三种方式

    3.3 keras模型构建的三种方式 1. 使用tf.keras.Sequential按层顺序构建模型,代码示例: model = Sequential()#卷积层conv_1_1 model.add ...

  5. Quartus II三种方式实现D触发器及时序仿真

    Quartus II三种方式实现D触发器及时序仿真 一.准备工作 (一)软件下载 (二)D触发器原理 1.简介 2.D触发器的基本结构与信号输入输出关系 3.状态转移真值表以及状态转移图 二.实验要求 ...

  6. 三种方式实现生产者-消费者模型

    前言 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了 ...

  7. Workflow 4.0 中三种方式实现workflow的触发调用

    1:使用WorkflowInvoker类中的InVoke静态方法-->WorkflowInvoker.Invoke(myWF); //myWF为自定义的workflow实例 [这种方式可以像一个 ...

  8. Django中Model继承的三种方式

    Django中Model继承的三种方式 Django中Model的继承有三种: 1.抽象继承 2.多表继承 3.proxy model(代理model) 1.抽象继承 第一种抽象继承,创建一个通用父类 ...

  9. java 创建线程_【80期】说出Java创建线程的三种方式及对比

    点击上方"Java面试题精选",关注公众号 面试刷图,查缺补漏 >>号外:往期面试题,10篇为一个单位归置到本公众号菜单栏->面试题,有需要的欢迎翻阅. 一.Ja ...

最新文章

  1. js 实现精确加减乘除运算之BigDecimal.js
  2. Servlet运行流程笔记
  3. 来来来,送开发板了。
  4. 二十、MySQL之用户权限管理(用户管理、权限管理、忘记root密码的解决方案)
  5. LeetCode--056--合并区间(java)
  6. angelajs中ajax,前端测试数据怎么利用Mock.js进行生成
  7. 中国经济蓝皮书发布 该死的房价下降成定局
  8. 深入理解mybatis一级缓存
  9. 使用cmd命令 关机
  10. 软体机器人空间感知技术综述
  11. 机器学习概述----机器学习并没有那么深奥,它很有趣(2)
  12. 入门c语言(四)顺序结构程序设计
  13. 遥志无盘如何设置副服务器,CCDisk遥志虚拟磁盘使用说明图解
  14. Go Web学习笔记(Gin和Gorm)
  15. android 动画x轴旋转,属性动画Rotation如何以中心轴旋转
  16. 转战Linux 重装系统记录 windows - fedora
  17. fl水果软件第三方插件FL Studio20.9
  18. 微信支付崩溃了,但是更让马化腾和张小龙崩溃的竟然是……
  19. 2020年外贸ERP软件排名
  20. json 布尔值 java,默认情况下,布尔值字段的JSON Post请求发送false

热门文章

  1. 创建mysql数据库,在新数据库中创建表,再尝试删除表
  2. ExtJs 备忘录(3)—— Form表单(三) [ 数据验证 ]
  3. NSMakeRange基础函数应用
  4. Phabricator是什么,代码审查工具
  5. 10624 - Super Number
  6. Android开发:setAlpha()方法和常用RGB颜色表----颜色, r g b分量数值(int), 16进制表示 一一对应...
  7. Java知识积累——String引用的判断问题
  8. 用正则表达式替换示例
  9. python中根据URL获得数据库的名称及IP
  10. 2018-3-10论文(网络评论非结构化信息表示与应用研究)笔记-----基于证据理论的综合评价模型建立