1. 时间序列数据
1. 1 时间序列概述
百科中关于时间序列的描述为:
时间序列(或称动态数列)是指将同一统计指标的数值按其发生的时间先后顺序排列而成的数列。时间序列分析的主要目的是根据已有的历史数据对未来进行预测。经济数据中大多数以时间序列的形式给出。根据观察时间的不同,时间序列中的时间可以是年份、季度、月份或其他任何时间形式
时间序列的构成要素:
构成要素:长期趋势,季节变动,循环变动,不规则变动。
1)长期趋势(T)现象在较长时期内受某种根本性因素作用而形成的总的变动趋势。
2)季节变动(S)现象在一年内随着季节的变化而发生的有规律的周期性变动。
3)循环变动(C)现象以若干年为周期所呈现出的波浪起伏形态的有规律的变动。
4)不规则变动(I)是一种无规律可循的变动,包括严格的随机变动和不规则的突发性影响很大的变动两种类型。
金融市场中,时序数据十分常见,我们购买股票,虚拟货币,一定会获得收益吗?实际上我们没法保证一定会有很好的收益,但可以根据之前的股票/虚拟货币价格估算出近似价值。时序模型就是预测这些值的一种方式。
除此之外在很多重要的领域,比如预测太阳活动和海洋潮汐、预测某公司接下来一年的销售额,工业领域预测下个月的能源消耗等,都是根据之前每年、每月和每天的数据,预测接下来的值,这些都是可以用时间序列的应用。
2. 时序数据分析
本文使用案例为高铁服务商 JetRail 旗下高铁的乘客数量。数据下载地址:
训练集为2012 年 8 月至 2014 年 8月的数据,需要用这些数据预测接下来 7 个月的乘客数量。
实现内容如下:
安装程序库(statsmodels)
方法1——先以朴素法开始
方法2——简单平均数
方法3——移动平均数
方法4——指数平滑法
方法5——霍尔特线性趋势预测
方法6——Holt-Winters季节性预测模型
方法7——自回归移动平均模型
1.2 数据集导入与处理
1. 查看数据
读取训练集数据
import pandas as pd import numpy as np import matplotlib.pyplot as plt #Importing data df = pd.read_csv('train.csv') df
输出为:
如上面的输出语句所示,我们获得了 2012-2014 年两年每个小时的乘客数量,然后需要预测未来的乘客数量。
读取测试集数据
df_test = pd.read_csv('Test.csv') df_test
输出为:
查看训练集类型
df.info()
输出为:
可以看到空缺值,类型信息,
2. 数据处理
把Datetime一列转变为时间戳类型
df['Timestamp'] = pd.to_datetime(df['Datetime'],format='%d-%m-%Y %H:%M') df
输出为:
3. 切分数据集
取部分数据作为数据集,前 14 个月( 2012 年 8 月- 2013 年 10 月)用作训练数据,后两个月(2013 年 11 月 - 2013 年 12 月)用作测试数据。
为了解释每种方法的不同之处,我以每天为单位构造和聚合了一个数据集。
从 2012 年 8 月- 2013 年 12 月的数据中构造一个数据集。
确定( 2012 年 8 月- 2013 年 10 月)范围
df[df['Timestamp'] < "2013-10-31 23:59:59 "]
输出为:
一共0-10391共10392条数据,10392/24 = 433天
确定( 2013 年 11 月- 2013 年 12 月)范围
df[(df['Timestamp'] > "2013-10-31 23:59:59 ") & (df['Timestamp'] < "2013-12-31 23:59:59 ")]
输出为:
一共10392-11855共1462条数据,1464/24 = 61天
切分训练集和测试集
train = df[df['Timestamp'] < "2013-10-31 23:59:59 "] print(train.iloc[10391,:]) test = df[(df['Timestamp'] > "2013-10-31 23:59:59 ") & (df['Timestamp'] < "2013-12-31 23:59:59 ")] test
输出为:
训练集降采样
# 把时间戳列 设置为索引 并按照天为单位进行降采样 train.index = train.Timestamp train = train.resample('D').mean() train
输出为:
测试集降采样
# 把时间戳列 设置为索引 并按照天为单位进行降采样 test.index = test.Timestamp test = test.resample('D').mean() test
输出为:
4. 数据分析
将数据可视化(训练数据和测试数据一起),从而得知在一段时间内数据是如何变化的。
# 可视化数据 import matplotlib.pyplot as plt import matplotlib.dates as mdates plt.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文 plt.rcParams["axes.unicode_minus"]=False # 显示负号 train['Count'].plot(figsize=(15,8), title= 'Daily Ridership', fontsize=14) test['Count'].plot(figsize=(15,8), title= 'Daily Ridership', fontsize=14) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m/%d/%Y')) # 设置坐标轴格式 plt.gca().xaxis.set_major_locator(mdates.MonthLocator()) # 设置坐标轴间隔 plt.gcf().autofmt_xdate() # 自动旋转日期标记 plt.show()
输出为:
1.3 时间序列分析
1. 安装程序库(statsmodels)
安装:
pip install statsmodels -i https://pypi.tuna.tsinghua.edu.cn/simple
测试:
from statsmodels.tsa.api import ExponentialSmoothing • 1
不报错,即为安装正常
2. 方法1:先以朴素法开始
一般来说,短时间内的数据往往是平稳的,我们往往可以根据昨天的数据去预测预测第二天的值,即把明天的数据当成与今天是相同的。这种假设第一个预测点和上一个观察点相等的预测方法就叫朴素法。
用朴素法预测:
dd= np.asarray(train.Count) y_hat = test.copy() y_hat['naive'] = dd[len(dd)-1] plt.figure(figsize=(12,8)) plt.plot(train.index, train['Count'], label='Train') plt.plot(test.index,test['Count'], label='Test') plt.plot(y_hat.index,y_hat['naive'], label='Naive Forecast') plt.legend(loc='best') plt.title("Naive Forecast") plt.show() y_hat
输出为:
我们下面计算均方根误差,检查模型在测试数据集上的准确率。
from sklearn.metrics import mean_squared_error from math import sqrt rms = sqrt(mean_squared_error(test.Count, y_hat.naive)) rms
输出为:
从均方根误差值以及上面的图表可以看出,朴素法并不适合变化很大的数据集,最适合稳定性很高的数据集。我们还可以用不同的方法优化结果。下面我们试试其它方法。
3. 方法2:简单平均法
将预期值等同于之前所有观测点的平均值的预测方法就叫简单平均法.
y_hat_avg = test.copy() y_hat_avg['avg_forecast'] = train['Count'].mean() plt.figure(figsize=(12,8)) plt.plot(train['Count'], label='Train') plt.plot(test['Count'], label='Test') plt.plot(y_hat_avg['avg_forecast'], label='Average Forecast') plt.legend(loc='best') plt.show() y_hat_avg
输出为:
计算均方根误差值,检查模型的准确率。
rms = sqrt(mean_squared_error(test['Count'], y_hat_avg['avg_forecast'])) rms
输出为:
4. 方法3——移动平均法
之前的简单平均法,使用所有先前数据的平均值,这有些不合理,如果基于某窗口期的平均值预测下一段的值,这就是移动平均法。假设"滑动窗口"的大小值p,使用简单的移动平均模型,我们可以根据之前数值的固定有限数p的平均值预测某个时序中的下一个值。这样,对于所有的 i > p
y_hat_avg = test.copy() y_hat_avg['moving_avg_forecast'] = train['Count'].rolling(60).mean().iloc[-1] # 窗口为60 求均值 最后一个 131.761111 plt.figure(figsize=(16,8)) plt.plot(train['Count'], label='Train') plt.plot(test['Count'], label='Test') plt.plot(y_hat_avg['moving_avg_forecast'], label='Moving Average Forecast') plt.legend(loc='best') plt.show()
输出为:
只选择过去两个月的数据。现在计算均方根误差值,检查模型的准确度。
rms = sqrt(mean_squared_error(test['Count'], y_hat_avg['moving_avg_forecast'])) rms
输出为:
在移动平均法中,各个时间的权重是一致的,如果考虑到不同时间的观察值有着不同的权重,就叫做加权移动平均法。
加权移动平均法其实还是一种移动平均法,只是“滑动窗口期”内的值被赋予不同的权重,通常来讲,最近时间点的值发挥的作用更大了。