前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何在Python中保存ARIMA时间序列预测模型

如何在Python中保存ARIMA时间序列预测模型

作者头像
Sepmer Fi
发布2018-02-06 15:52:33
3.9K0
发布2018-02-06 15:52:33

差分自回归移动平均模型(ARIMA)是时间序列分析和预测领域流行的一个线性模型。

statsmodels库实现了在Python中使用ARIMA。(对当前序列得到的)ARIMA模型可以被保存到文件中,用于对未来的新数据进行预测。但statsmodels库的当前版本中存在一个缺陷(2017.2),这个Bug会导致模型无法被加载。

在本教程中,你将了解如何诊断和解决这个当前版本中(0.8及以前)的Bug。

现在就让我们开始吧。

如何在Python中保存ARIMA时间序列预测模型 照片由Les Chatfield拍摄,保留相应权利。
如何在Python中保存ARIMA时间序列预测模型 照片由Les Chatfield拍摄,保留相应权利。

每天女婴出生数目数据集

首先,我们可以通过一个标准的时间序列数据集,来理解statsmodels ARIMA实现中存在的问题。

这个“每日女婴出生”数据集描述了1959年加利福尼亚州每天的出生的女婴数量。

每天的数据是当天出生女婴的数量,显然共有365个数据。数据集的来源于Newton(1988)。

您可以了解更多信息并从DataMarket网站下载数据集

下载该数据集并将其放在当前工作目录中,我们将文件命名为daily-total-female-births.csv ”。

下面的代码片段将加载和绘制数据集对应的图形。

代码语言:txt
复制
from pandas import Series
from matplotlib import pyplot
series = Series.from_csv('daily-total-female-births.csv', header=0)
series.plot()
pyplot.show()

运行示例将数据集加载为Pandas序列,然后绘制数据的线图。

每日女性出生的数量
每日女性出生的数量

Python环境

确认你使用的是最新版本的statsmodels库

你可以通过运行下面的脚本来检查:

代码语言:txt
复制
import statsmodels
print('statsmodels: %s' % statsmodels.__version__)

运行脚本,如果是最新版本,会显示statsmodels 0.6或0.6.1。

代码语言:txt
复制
statsmodels: 0.6.1 
 

Python 2/3皆可。

更新:我确认在statsmodels 0.8这个问题仍然存在并会导致产生错误消息:

代码语言:txt
复制
AttributeError: 'ARIMA' object has no attribute 'dates' 

ARIMA模型保存错误

我们可以很容易地在“每日出生的女性数目”数据集上训练一个ARIMA模型。

下面的代码片段可以训练一个基于该数据集的ARIMA(1,1,1)模型。

model.fit()函数会返回一个ARIMAResults对象,我们可以调用save()函数将模型保存在文件中,使用load()函数加载现有的模型。

代码语言:txt
复制
from pandas import Series
from statsmodels.tsa.arima_model import ARIMA
from statsmodels.tsa.arima_model import ARIMAResults
# load data
series = Series.from_csv('daily-total-female-births.csv', header=0)
# prepare data
X = series.values
X = X.astype('float32')
# fit model
model = ARIMA(X, order=(1,1,1))
model_fit = model.fit()
# save model
model_fit.save('model.pkl')
# load model
loaded = ARIMAResults.load('model.pkl')

运行此示例程序,训练模型并将其保存到文件中,不会出现我之前提到的问题。

但当你尝试从文件加载模型时,会出现报错。

代码语言:txt
复制
Traceback (most recent call last):
  File "...", line 16, in <module>
    loaded = ARIMAResults.load('model.pkl')
  File ".../site-packages/statsmodels/base/model.py", line 1529, in load
    return load_pickle(fname)
  File ".../site-packages/statsmodels/iolib/smpickle.py", line 41, in load_pickle
    return cPickle.load(fin)
TypeError: __new__() takes at least 3 arguments (1 given)
 

具体来说,注意下面这行:

代码语言:txt
复制
TypeError: __new__() takes at least 3 arguments (1 given)

到截至目前,我们该如何解决这个问题呢?

ARIMA模型保存Bug的解决方法

Zae Myung Kim在2016年9月发现并报告了这个Bug。

你可以通过下面的链接,了解他的工作:

BUG: Implemented __getnewargs__() method for unpickling

这个错误的产生是因为一个pickle需要的函数(pickle,用于序列化Python对象的库)在statsmodels中没有定义。

在保存之前,必须在ARIMA模型中定义函数__getnewargs__,以定义构造对象所需的参数。

我们可以解决这个问题。修复的过程涉及两点:

  1. 定义适用于ARIMA对象的___getnewargs___函数实现 。
  2. 将定义的函数添加到ARIMA程序中。

非常感谢 Zae Myung Kim,在他的bug报告中已经提供了一个实现该函数的例子,所以我们可以直接使用它:

代码语言:txt
复制
def __getnewargs__(self):
    return ((self.endog),(self.k_lags, self.k_diff, self.k_ma)

Python允许我们可以修补一个对象,哪怕是在像statsmodels这样的库中。

我们可以通过使用赋值的方式,在现有的对象上定义一个新的函数。

我们可以对ARIMA对象上的___getnewargs___函数做如下操作:

代码语言:txt
复制
ARIMA.__getnewargs__ = __getnewargs__

下面列出了通过使用补丁在Python中加载和保存ARIMA模型的完整示例:

代码语言:txt
复制
from pandas import Series
from statsmodels.tsa.arima_model import ARIMA
from statsmodels.tsa.arima_model import ARIMAResults
 
# monkey patch around bug in ARIMA class
def __getnewargs__(self):
    return ((self.endog),(self.k_lags, self.k_diff, self.k_ma))
ARIMA.__getnewargs__ = __getnewargs__
 
# load data
series = Series.from_csv('daily-total-female-births.csv', header=0)
# prepare data
X = series.values
X = X.astype('float32')
# fit model
model = ARIMA(X, order=(1,1,1))
model_fit = model.fit()
# save model
model_fit.save('model.pkl')
# load model
loaded = ARIMAResults.load('model.pkl')

现在运行示例可以成功加载模型,而不会报错。

概要

在这篇文章中,你明白了如何解决statsmodels ARIMA实现中的一个错误,该错误会导致无法将ARIMA模型保存到文件或从文件中加载ARIMA模型。

你发现了如何编写一个补丁来解决这个bug,以及如何证明它确实已经修复了。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 每天女婴出生数目数据集
  • Python环境
  • ARIMA模型保存错误
  • ARIMA模型保存Bug的解决方法
  • 概要
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档