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

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

640.png


时间序列预测,其主要任务是基于某一指标的历史数据来预测其在未来的取值,例如上图中的曲线记录了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'])


640.png


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)


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


640.png


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


640.png

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


2.机器学习模型


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


640.png


据此,设置特征提取窗口长度为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()


640.png


可见,预测效果也较为一般,尤其是对于最后两年的预测结果,与真实值差距还是比较大的。用机器学习模型的思维很容易解释这一现象:随机森林模型实际上是在根据训练数据集来学习曲线之间的规律,由于该时序整体呈现随时间增长的趋势,所以历史数据中的最高点也不足以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”一样!


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


640.png







目录
相关文章
|
8天前
|
机器学习/深度学习 Python
验证集的划分方法:确保机器学习模型泛化能力的关键
本文详细介绍了机器学习中验证集的作用及其划分方法。验证集主要用于评估模型性能和调整超参数,不同于仅用于最终评估的测试集。文中描述了几种常见的划分方法,包括简单划分、交叉验证、时间序列数据划分及分层抽样划分,并提供了Python示例代码。此外,还强调了在划分数据集时应注意随机性、数据分布和多次实验的重要性。合理划分验证集有助于更准确地评估模型性能并进行有效调优。
|
8天前
|
机器学习/深度学习 人工智能 自然语言处理
机器学习模型之深度神经网络的特点
深度神经网络(Deep Neural Networks, DNNs)是一类机器学习模型,通过多个层级(层)的神经元来模拟人脑的工作方式,从而实现复杂的数据处理和模式识别任务。
14 1
|
16天前
|
机器学习/深度学习 算法 前端开发
R语言基础机器学习模型:深入探索决策树与随机森林
【9月更文挑战第2天】决策树和随机森林作为R语言中基础且强大的机器学习模型,各有其独特的优势和适用范围。了解并熟练掌握这两种模型,对于数据科学家和机器学习爱好者来说,无疑是一个重要的里程碑。希望本文能够帮助您更好地理解这两种模型,并在实际项目中灵活应用。
|
15天前
|
机器学习/深度学习 数据采集 存储
一文读懂蒙特卡洛算法:从概率模拟到机器学习模型优化的全方位解析
蒙特卡洛方法起源于1945年科学家斯坦尼斯劳·乌拉姆对纸牌游戏中概率问题的思考,与约翰·冯·诺依曼共同奠定了该方法的理论基础。该方法通过模拟大量随机场景来近似复杂问题的解,因命名灵感源自蒙特卡洛赌场。如今,蒙特卡洛方法广泛应用于机器学习领域,尤其在超参数调优、贝叶斯滤波等方面表现出色。通过随机采样超参数空间,蒙特卡洛方法能够高效地找到优质组合,适用于处理高维度、非线性问题。本文通过实例展示了蒙特卡洛方法在估算圆周率π和优化机器学习模型中的应用,并对比了其与网格搜索方法的性能。
96 1
|
8天前
|
机器学习/深度学习 人工智能 TensorFlow
神经网络入门到精通:Python带你搭建AI思维,解锁机器学习的无限可能
【9月更文挑战第10天】神经网络是开启人工智能大门的钥匙,不仅是一种技术,更是模仿人脑思考的奇迹。本文从基础概念入手,通过Python和TensorFlow搭建手写数字识别的神经网络,逐步解析数据加载、模型定义、训练及评估的全过程。随着学习深入,我们将探索深度神经网络、卷积神经网络等高级话题,并掌握优化模型性能的方法。通过不断实践,你将能构建自己的AI系统,解锁机器学习的无限潜能。
11 0
|
17天前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
39 0
|
17天前
|
开发者 算法 虚拟化
惊爆!Uno Platform 调试与性能分析终极攻略,从工具运用到代码优化,带你攻克开发难题成就完美应用
【8月更文挑战第31天】在 Uno Platform 中,调试可通过 Visual Studio 设置断点和逐步执行代码实现,同时浏览器开发者工具有助于 Web 版本调试。性能分析则利用 Visual Studio 的性能分析器检查 CPU 和内存使用情况,还可通过记录时间戳进行简单分析。优化性能涉及代码逻辑优化、资源管理和用户界面简化,综合利用平台提供的工具和技术,确保应用高效稳定运行。
30 0
|
17天前
|
前端开发 开发者 设计模式
揭秘Uno Platform状态管理之道:INotifyPropertyChanged、依赖注入、MVVM大对决,帮你找到最佳策略!
【8月更文挑战第31天】本文对比分析了 Uno Platform 中的关键状态管理策略,包括内置的 INotifyPropertyChanged、依赖注入及 MVVM 框架。INotifyPropertyChanged 方案简单易用,适合小型项目;依赖注入则更灵活,支持状态共享与持久化,适用于复杂场景;MVVM 框架通过分离视图、视图模型和模型,使状态管理更清晰,适合大型项目。开发者可根据项目需求和技术栈选择合适的状态管理方案,以实现高效管理。
26 0
|
17天前
|
Java 前端开发 Apache
Apache Wicket与Spring MVC等Java Web框架大PK,究竟谁才是你的最佳拍档?点击揭秘!
【8月更文挑战第31天】在Java Web开发领域,众多框架各具特色。Apache Wicket以组件化开发和易用性脱颖而出,提高了代码的可维护性和可读性。相比之下,Spring MVC拥有强大的生态系统,但学习曲线较陡;JSF与Java EE紧密集成,但在性能和灵活性上略逊一筹;Struts2虽成熟,但在RESTful API支持上不足。选择框架时还需考虑社区支持和文档完善程度。希望本文能帮助开发者找到最适合自己的框架。
27 0
|
3月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】