一、什么是时间序列?
时间序列是在规律性时间间隔记录的观测值序列。依赖于观测值的频率,典型的时间序列可分为每小时、每天、每周、每月、每季度和每年为单位记录。
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/data.csv', parse_dates=['date'])
df.head()
二、时间序列具有4个成分,如下所示
- Level − It is the mean value around which the series varies.
- 水平 -它是序列变化的平均值。
- Trend − It is the increasing or decreasing behavior of a variable with time.
- **趋势 -**它是变量随时间的增加或减少行为。
- Seasonality − It is the cyclic behavior of time series.
- **季节性 -**这是时间序列的周期性行为。
- Noise − It is the error in the observations added due to environmental factors.
- 噪声 -这是由于环境因素导致的观测值误差。
三、预测质量评价指标
R 平方: 可决系数,取值范围为 [0,+∞)[0,+∞) ,其值越大,表示拟合效果越好 调用接口为 sklearn.metrics.r2_score,计算公式如下:
平均绝对误差: 即所有单个观测值与算术平均值的偏差的绝对值的平均。这是一个可解释的指标,因为它与初始系列具有相同的计量单位。取值范围为 [0,+∞)[0,+∞) ,调用接口为 sklearn.metrics.mean_absolute_error ,计算公式如下:
中值绝对误差: 与平均绝对误差类似,即所有单个观测值与算术平均值的偏差的绝对值的中值。而且它对异常值是不敏感。取值范围为 [0,+∞)[0,+∞) ,调用接口为 sklearn.metrics.median_absolute_error ,计算公式如下:
**均方差:**最常用的度量标准,对大偏差给予较高的惩罚,反之亦然,取值范围为 [0,+∞)[0,+∞) ,调用接口为 sklearn.metrics.mean_squared_error ,计算公式如下:
均方对数误差: 这个与均方差类似,通过对均方差取对数而得到。因此,该评价指标也更重视小偏差。这指标通常用在呈指数趋势的数据。取值范围为 [0,+∞)[0,+∞) ,调用接口为 sklearn.metrics.mean_squared_log_error ,计算公式如下:
**平均绝对百分比误差:**这与 MAE 相同,但是是以百分比计算的。取值范围为 [0,+∞)[0,+∞) ,计算公式如下:
#平均绝对百分比误差的实现
def mean_absolute_percentage_error(y_true, y_pred):
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
四、十大时序模型:
- Naïve, SNaïve
- Seasonal decomposition (+ any model)
- Exponential smoothing
- ARIMA, SARIMA
- GARCH
- Dynamic linear models
- TBATS
- Prophet
- NNETAR
- LSTM
1、Naïve,模型
我们依据过往的观测值来预测:
这类预测假设随机模型产出时间序列是一个random walk。
Naïve模型的扩展是SNaïve,SNaïve假设时间序列是有周期性的,而且其周期为T,则:
因此,以下T时间步的预测值与之前T时间步的预测值相等。Naïve和SNaïve模型通常被用作基准模型。
2、Seasonal decomposition (+ any model)
statsmodels是一个 Python 模块,它提供了用于估计许多不同统计模型以及进行统计测试和统计数据探索的类和函数。
安装:pip install statsmodels
如果数据显示出某种周期性(例如,每日、每周、每季度、每年),则我们可以将原始时间序列分解为三个部分的总和:
其中S(t)是周期性部分,T(t)是趋势性成分,R(t)是剩余部分。针对这种分解,我们有多种经典的分解策略,例如:
- 我们可以通过rolling mean的策略来预估;
- 对于每个周期,我们通过计算平均去趋势序列来计算;
- 最后通过减法得到余数部分。
当然上面的策略还是相对简单,后来被优化为:
- 我们有非常数的周期;
- 通过分解的形式计算初始和最后的值;
- 防止过度平滑;
statsmodels.tsa.seasonal.seasonal_decompose(x,model = 'additive',filt = None,period = None,two_side = True,extrapolate_trend = 0) #使用移动平均线进行季节性分解
参数:
x:array_like,被分解的数据
model:{“additive”, “multiplicative”}, optional,"additive"(加法模型)和"multiplicative"(乘法模型)
filt:tarray_like, optional,用于滤除季节性成分的滤除系数。滤波中使用的具体移动平均法由two_side确定
period:int, optional,系列的时期。如果x不是pandas对象或x的索引没有频率,则必须使用。如果x是具有时间序列索引的pandas对象,则覆盖x的默认周期性。
two_sided:bool, optional,滤波中使用的移动平均法。如果为True(默认),则使用filt计算居中的移动平均线。如果为False,则滤波器系数仅用于过去的值
extrapolate_trend:int or ‘freq’, optional,如果设置为> 0,则考虑到许多(+1)最接近的点,由卷积产生的趋势将在两端外推线性最小二乘法(如果two_side为False,则为单一个最小二乘)。如果设置为“频率”,请使用频率最近点。设置此参数将导致趋势或残油成分中没有NaN值。
# 下面深入分解:长期趋势Trend、季节性seasonality和随机残差residuals。
# 强行补充小知识:平稳性处理之“分解”
# 所谓分解就是将时序数据分离成不同的成分。statsmodels使用的X-11分解过程,它主要将时序数据分离成长期趋势、季节趋势和随机成分。
# 与其它统计软件一样,statsmodels也支持两类分解模型,加法模型和乘法模型,model的参数设置为"additive"(加法模型)和"multiplicative"(乘法模型)。
import statsmodels.api as sm # 导入统计建模模块
# multiplicative
res = sm.tsa.seasonal_decompose(ts.values,freq=12,model="multiplicative")
# 这里用到的.tsa.seasonal_decompose()函数,经尝试:参数ts.values时,横坐标是Time;参数ts时,横坐标是date_block_num。其他不变。
# freg这个参数容后研究,这里暂且猜测是周期12个月。
# plt.figure(figsize=(16,12))
fig = res.plot()
# fig.show() # 此句,可加可不加。
# 得到不同的分解成分,接下来可以使用时间序列模型对各个成分进行拟合。
3、指数平滑
指数平滑是早期大家在做数据竞赛时最为成功的一种模型,它基础形式为:
使用指数平滑方法生成的预测是过去观测值的加权平均值,并且随着过去观测值离预测值距离的增大,权重呈指数型衰减。
权重减小率由平滑参数α控制。 如果α很大(即接近1),则对更近期的观察给予更多权重。 有两种极端情况:
-
α= 0:所有未来值的预测等于历史数据的平均值(或“平均值”),称为平均值法。
-
α= 1:简单地将所有预测设置为最后一次观测的值,统计中称为朴素方法。
Exponential smoothing:针对「没有趋势和季节性」的序列
-
一次指数平滑,从最邻近到最早的数据点的权重呈现指数型下降的规律。
-
当时间数列无明显的趋势变化,可用一次指数平滑预测。
Holt exponential smoothing:针对「有趋势但没有季节性」的序列
-
二次指数平滑,通过引入一个额外的系数来解决指数平滑无法应用于具有趋势性数据的问题。
-
二次指数平滑保留并更新两个量的状态:「平滑后的信号」和「平滑后的趋势」。
Holt-Winters exponential smoothing:针对「有趋势且有季节性」的序列
-
三次指数平滑,通过再次引入一个新系数的方式同时解决了 Holt exponential smoothing
无法解决具有季节性变化数据的不足。 -
三次指数平滑在此基础上引入季节性分量考虑时间序列周期性模式。
-
有两种不同的季节性组成部分:
当季节变化在该时间序列中大致保持不变时,通常选择加法模型;
当季节变化与时间序列的水平成比例变化时,通常选择乘法模型;
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import statsmodels.api as sm
data.index=pd.Index(sm.tsa.datetools.dates_from_range('2020m1',length=len(data)))
from statsmodels.tsa.holtwinters import ExponentialSmoothing
model1=ExponentialSmoothing(data,seasonal_periods=12,trend='add',seasonal='add',freq='1M').fit() #加法模型
model2=ExponentialSmoothing(data,seasonal_periods=12,trend='mul',seasonal='mul',freq='1M').fit() #乘法模型
summary_1=model1.summary()
summary_2=model1.summary()
print(summary_1)
print(summary_2)
#模型预测
model_forecast_2=model2.forecast(12)
print(model_forecast_2)