- 1、Pandas-时间序列基础
- 2、用Python预测「周期性时间序列」的正确姿势
- 3、时间序列分析方法
Python标准库中包含用于日期和时间的数据类型,而且还有日历方面的功能,我们主要会用到datetime、time和calendar模块,datetime.datetime是用的最多的数据类型。
datetime以毫秒形式存储日期和时间,datetime.timedelta表示两个datetime对象之间的时间差.
可以给datetime对象加上或者减去一个或多个timedelta,会产生一个新对象:
利用str或者strftime方法,datetime对象和pandas的Timestamp对象可以被格式化为字符串:
datetime.strptime也可以用这些格式化编码将字符串转化为日期:
datetime.strptime是通过已知格式进行日期解析的最佳方式,但是每次都要编写格式定义很麻烦,尤其是对于一些常见的日期格式,这种情况下,可以用dateutil这个第三方包中的parser.parse方法,dateutil可以解析几乎所有人类能够理解的日期表示形式:
在国际通用格式中,日通常出现在月的前面,传入dayfirst=True即可:
pandas通常是用于处理成组日期的,不管这些日期是DataFrame的轴索引还是列,to_datetime方法可以解析多种不同的日期表示形式。
to_datetime可以处理缺失值,NAT是pandas中时间戳数据的NA值:
pandas最基本的时间序列类型就是以时间戳为索引的Series:
这里的Series索引不是普通的索引,而是DatetimeIndex,而ts变为了一个TimeSeries,同时,可以看到,pandas用Numpy的datetime64数据类型以纳秒形式存储时间戳。
跟其他Series一样,不同索引的时间序列之间的算数运算会自动对齐:
DateTimeIndex中的各个标量值是pandas的Timestamp对象.
由于TimeSeries是Series的一个子类,所以在索引以及数据选曲方面他们的行为是一样的,但是我们还可以传入一个可以被解释为日期的字符串来进行索引:
对于较长的时间序列,只需传入年或年月即可轻松选取数据的切片:
通过日期进行切片的方式只对规则Series有效:
还有一个等价的实例方法也可以截取两个日期之间的TimeSeries:
DataFrame也同样适用上面的规则
pandas中的时间序列一般被认为是不规则的,也就是说,没有固定的频率,对于大部分程序而言,这是无所谓的,但是,他常常需要以某种相对固定的频率进行分析,比如每月,每日,每15min等。pandas有一套标准时间序列频率以及用于重采样,频率推断,生成固定频率日期范围的工具.
例如,我们可以将之前的时间序列转换为一个具有固定频率(每日)的时间序列,只需调用resample即可.返回DatetimeIndexResampler,获取值使用asfreq():
生成日期范围使用date_range函数
默认情况下,date_range会产生按天计算的时间点,如果只传入起始或结束日期,那就还得传入一个表示一段时间的数字:
如果你不想按天生成数据,想要按照一定的频率生成,我们传入freq参数即可.如想按5小时生成数据:
如果你想生成一个由每月最后一个工作日组成的日期索引,可以使用BM频率:
date_range默认会保留起始和结束的时间戳的时间信息,但是如果我们想产生一组规范化到午夜的时间戳,normalize选项可以实现这个功能:
WOM(week of Month)是一种非常实用的频率类,它以WOM开头,它使你能获得诸如每月第三个星期五之类的日期:
公司平台上有不同的api,供内部或外部调用,这些api承担着不同的功能,如查询账号、发版、抢红包等等。日志会记录下每分钟某api被访问了多少次,即一个api每天会有1440条记录(1440分钟),将每天的数据连起来观察,有点类似于股票走势的意思。我想通过前N天的历史数据预测出第N+1天的流量访问情况,预测值即作为合理参考,供新一天与真实值做实时对比。当真实流量跟预测值有较大出入,则认为有异常访问,触发报警。
我放了一份样例数据在data文件夹下,
看一下数据大小和结构
画图看一下序列的走势:(一些画图等探索类的方法放在了test_stationarity.py 文件中,包含时间序列图,移动平均图,有兴趣的可以自己尝试下)。
看这糟心的图,那些骤降为0的点这就是我遇到的第一个坑,我当初一拿到这份数据就开始做了。后来折腾了好久才发现,那些骤降为0的点是由于数据缺失,ETL的同学自动补零造成的,沟通晚了(TДT)。
把坑填上,用前后值的均值把缺失值补上,再看一眼:
发现这份数据有这样几个特点,在模型设计和数据预处理的时候要考虑到:
前六天的数据做训练,第七天做测试集。
消除数据的毛刺,可以用移动平均法,我这里没有采用,因为我试过发现对于我的数据来说,移动平均处理完后并不能使数据平滑,我这里采用的方法很简单,但效果还不错:把每个点与上一点的变化值作为一个新的序列,对这里边的异常值,也就是变化比较离谱的值剃掉,用前后数据的均值填充,注意可能会连续出现变化较大的点:
平滑后的训练数据:
采用statsmodels工具包:
对分解出来的趋势部分单独用arima模型做训练:
预测出趋势数据后,加上周期数据即作为最终的预测结果,但更重要的是,我们要得到的不是具体的值,而是一个合理区间,当真实数据超过了这个区间,则触发报警,误差高低区间的设定来自刚刚分解出来的残差residual数据:
预测并完成最后的加法处理,得到第七天的预测值即高低置信区间:
对第七天作出预测,评估的指标为均方根误差rmse,画图对比和真实值的差距:
可以看到,均方根误差462.8,相对于原始数据几千的量级,还是可以的。测试数据中的两个突变的点,也超过了置信区间,能准确报出来。
前文提到不同的api形态差异巨大,本文只展示了一个,我在该项目中还接触了其他形态的序列,有的有明显的上升或下降趋势;有的开始比较平缓,后面开始增长… … ,但是都属于典型的周期性时间序列,它的核心思想很简单:做好分解,做好预测结果的还原,和置信区间的设置,具体操作可根据具体业务逻辑做调整,祝大家建模愉快:-D。
时间序列是指一组在连续时间上测得的数据,其在数学上的定义是一组向量x(t), t=0,1,2,3,…,其中t表示数据所在的时间点,x(t)是一组按时间顺序(测得)排列的随机变量。包含单个变量的时间序列称为单变量时间序列,而包含多个变量的时间序列则称为多变量。
时间序列在很多方面多有涉及到,如天气预报,每天每个小时的气温,股票走势等等,在商业方面有诸多应用,如:
下面我们将通过一个航班数据来说明如何使用已有的工具来进行时间序列数据预测。常用来处理时间序列的包有三个:
对于基于AR、MA的方法一般需要数据预处理,因此本文分为三部分:
通过简单的初步处理以及可视化可以帮助我们有效快速的了解数据的分布(以及时间序列的趋势)。
观察数据的频率直方图以及密度分布图以洞察数据结构,从下图可以看出:
使用 statsmodels 对该时间序列进行分解,以了解该时间序列数据的各个部分,每个部分都代表着一种模式类别。借用 statsmodels 序列分解我们可以看到数据的主要趋势成分、季节成分和残差成分,这与我们上面的推测相符合。
如果一个时间序列的均值和方差随着时间变化保持稳定,则可以说这个时间序列是稳定的。
大多数时间序列模型都是在平稳序列的前提下进行建模的。造成这种情况的主要原因是序列可以有许多种(复杂的)非平稳的方式,而平稳性只有一种,更加的易于分析,易于建模。
在直觉上,如果一段时间序列在某一段时间序列内具有特定的行为,那么将来很可能具有相同的行为。譬如已连续观察一个星期都是六点出太阳,那么可以推测明天也是六点出太阳,误差非常小。
而且,与非平稳序列相比,平稳序列相关的理论更加成熟且易于实现。
一般可以通过以下几种方式来检验序列的平稳性:
如果时间序列是平稳性的,那么在ACF/PACF中观测点数据与之前数据点的相关性会急剧下降。
下图中的圆锥形阴影是置信区间,区间外的数据点说明其与观测数据本身具有强烈的相关性,这种相关性并非来自于统计波动。
PACF在计算X(t)和X(t-h)的相关性的时候,挖空在(t-h,t)上所有数据点对X(t)的影响,反应的是X(t)和X(t-h)之间真实的相关性(直接相关性)。
从下图可以看出,数据点的相关性并没有急剧下降,因此该序列是非平稳的。
如果序列是平稳的,那么其滑动均值/方差会随着时间的变化保持稳定。
但是从下图我们可以看到,随着时间的推移,均值呈现明显的上升趋势,而方差也呈现出波动式上升的趋势,因此该序列是非平稳的。
一般来讲p值小于0.05我们便认为其是显著性的,可以拒绝零假设。但是这里的p值为0.99明显是非显著性的,因此接受零假设,该序列是非平稳的。
从上面的平稳性检验我们可以知道该时间序列为非平稳序列。此外,通过上面1.3部分的序列分解我们也可以看到,该序列可分解为3部分:
我们可以使用数据转换来对那些较大的数据施加更大的惩罚,如取对数、开平方根、立方根、差分等,以达到序列平稳的目的。
滑动平均后数据失去了其原来的特点(波动式上升),这样损失的信息过多,肯定是无法作为后续模型的输入的。
差分是常用的将非平稳序列转换平稳序列的方法。ARIMA中的 ‘I’ 便是指的差分,因此ARIMA是可以对非平稳序列进行处理的,其相当于先将非平稳序列通过差分转换为平稳序列再来使用ARMA进行建模。
一般差分是用某时刻数值减去上一时刻数值来得到新序列。但这里有一点区别,我们是使用当前时刻数值来减去其对应时刻的滑动均值。
我们来看看刚刚差分的结果怎么样。
让我们稍微总结下我们刚刚的步骤:
通过上面的3步我们成功的将一个非平稳序列转换成了一个平稳序列。上面使用的是最简单的滑动均值,下面我们试试指数滑动平均怎么样。
上面是最常用的指数滑动平均的定义,但是pandas实现的指数滑动平均好像与这个有一点区别,详细区别还得去查pandas文档。
指数滑动均值的效果看起来也很差。我们使用差分+指数滑动平均再来试试吧。
在上面我们通过 取log+(指数)滑动平均+差分 已经成功将非平稳序列转换为了平稳序列。
下面我们看看,转换后的平稳序列的各个成分是什么样的。不过这里我们使用的是最简单的差分,当前时刻的值等于原始序列当前时刻的值减去原始序列中上一时刻的值,即: x'(t) = x(t) – x(t-1)。
看起来挺不错,是个平稳序列的样子。不过,还是检验一下吧。
可以看到,趋势(Trend)部分已基本被去除,但是季节性(seasonal)部分还是很明显,而ARIMA是无法对含有seasonal的序列进行建模分析的。
在一开始我们提到了3个包均可以对时间序列进行建模。
为了简便,这里 pmdarima 和 statsmodels.tsa 直接使用最好的建模方法即SARIMA,该方法在ARIMA的基础上添加了额外功能,可以拟合seasonal部分以及额外添加的数据。
在使用ARIMA(Autoregressive Integrated Moving Average)模型前,我们先简单了解下这个模型。这个模型其实可以包括三部分,分别对应着三个参数(p, d, q):
因此ARIMA模型就是将AR和MA模型结合起来然后加上差分,克服了不能处理非平稳序列的问题。但是,需要注意的是,其仍然无法对seasonal进行拟合。
下面开始使用ARIMA来拟合数据。
(1) 先分训练集和验证集。需要注意的是这里使用的原始数据来进行建模而非转换后的数据。
(2)ARIMA一阶差分建模并预测
(3)对差分结果进行还原
先手动选择几组参数,然后参数搜索找到最佳值。需要注意的是,为了避免过拟合,这里的阶数一般不太建议取太大。
可视化看看结果怎么样吧。
(6)最后,我们还能对拟合好的模型进行诊断看看结果怎么样。
我们主要关心的是确保模型的残差(residual)部分互不相关,并且呈零均值正态分布。若季节性ARIMA(SARIMA)不满足这些属性,则表明它可以进一步改善。模型诊断根据下面的几个方面来判断残差是否符合正态分布:
同样的,为了方便,我们这里使用 pmdarima 中一个可以自动搜索最佳参数的方法 auto_arima 来进行建模。
一般来说,在实际生活和生产环节中,除了季节项,趋势项,剩余项之外,通常还有节假日的效应。所以,在prophet算法里面,作者同时考虑了以上四项,即:
上式中,
更多详细Prophet算法内容可以参考 Facebook 时间序列预测算法 Prophet 的研究 。
Prophet算法就是通过拟合这几项,然后把它们累加起来得到时间序列的预测值。
Prophet提供了直观且易于调整的参数:
Prophet对输入数据有要求:
关于 Prophet 的使用例子可以参考 Prophet example notebooks
下面使用 Prophet 来进行处理数据。
参考:
Facebook 时间序列预测算法 Prophet 的研究
Prophet example notebooks
auto_arima documentation for selecting best model
数据分析技术:时间序列分析的AR/MA/ARMA/ARIMA模型体系
时间序列分析
My First Time Series Comp (Added Prophet)
Prophet官方文档:
原创文章,作者:PB6HP,如若转载,请注明出处:https://www.506064.com/n/127233.html