时序预测的七种方法-python3

时序预测的七种方法

目录
数据读取和处理
安装库
方法 1 –以简单的方式开始
方法2 – 简单平均数
方法3 – 移动平均数
方法 4 –指数平滑法
方法5 – Holt线性趋势法
方法6 – Holt冬季季节法
方法7 –综合自回归移动平均法(ARIMA)

理解问题描述和数据集

为建模构造训练和测试文件
把数据(用于训练的和测试的)可视化,以了解在一段时间内是如何变化的。

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#读取时间序列数据
df = pd.read_csv('../testdata/train.csv', error_bad_lines=False)
print(df.head())

#切分训练集和测试集
train = df[0:550]
test = df[550:]

# 设置数据以天变化
df.time = pd.to_datetime(df.time,format='%Y-%m-%d')
df.index = df.time
df = df.resample('D').mean()
print(df)
train.time = pd.to_datetime(train.time,format='%Y-%m-%d')
train.index = train.time
train = train.resample('D').mean()
print(train)
test.time = pd.to_datetime(test.time,format='%Y-%m-%d')
test.index = test.time
test = test.resample('D').mean()
print(test)

# 数据可视化查看趋势
train.cv.plot(figsize=(15,8), title= 'Daily Ridership', fontsize=14)
test.cv.plot(figsize=(15,8), title= 'Daily Ridership', fontsize=14)
plt.show()

在这里插入图片描述

安装库(statsmodels)

用来进行时序预测的库是statsmodels。在应用很少的给定方法之前,需要安装一下。
pip3 install statsmodels

方法1: 用Naive方法开始

考虑下面的曲线图:
在这里插入图片描述
从图中我们可以看出,从一开始,硬币的价格是稳定的。大多时候我们都有一个在整个时间段都比较稳定的数据集。如果想预测第二天的价格,可以简单地用前一天的价格数据,估计第二天的价格。这种假定下一个期望点等于最后一个观测点的预测技术称为 Naive方法。
在这里插入图片描述
现在我们采用Naive 方法来预测测试数据的价格。

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#读取时间序列数据
df = pd.read_csv('../testdata/train.csv', error_bad_lines=False)
print(df.head())

#切分训练集和测试集
train = df[0:550]
test = df[550:]

# 设置数据以天变化
df.time = pd.to_datetime(df.time,format='%Y-%m-%d')
df.index = df.time
df = df.resample('D').mean()
train.time = pd.to_datetime(train.time,format='%Y-%m-%d')
train.index = train.time
train = train.resample('D').mean()
test.time = pd.to_datetime(test.time,format='%Y-%m-%d')
test.index = test.time
test = test.resample('D').mean()

#Naive Forecast
dd = np.asarray(train.cv)
y_hat = test.copy()
y_hat['naive'] = dd[len(dd)-1]
print(y_hat)
plt.figure(figsize=(12,8))
plt.plot(train.index,train['cv'],label='Train')
plt.plot(test.index,test['cv'],label='Test')
plt.plot(y_hat.index,y_hat['naive'],label='Naive Forecast')
plt.legend(loc='best')
plt.title('Naive Forecast')
plt.show()

#均方差检查模型精度
from sklearn.metrics import mean_squared_error
from math import sqrt

rms = sqrt(mean_squared_error(test.cv,y_hat.naive))
print(rms)
# 22658116.88412684
#可以从RMSE值和上面的图推断,Naive方法不适合变化频繁的数据集,它最适合稳定的数据集。

可以从RMSE值和上面的图推断,Naive方法不适合变化频繁的数据集,它最适合稳定的数据集。

方法2 简单均值法

考虑下面的图。
在这里插入图片描述
可以从图中推断,硬币的价格是以微小的幅度随机上升和下降的,平均值不变。很多时候,我们得到了一个数据集,虽然它在整个时间段内有一个较小的变化,但是每个时间段的平均值保持不变。在这种情况下,我们可以预测第二天的价格与之前每天的平均值相近。

这种预测期望值等于所有观测点平均值的预测技术称为简单均值法。
在这里插入图片描述
我们取前面已知的所有值,计算平均值,并将其作为下一个值。当然,它并不精确,而是稍微接近。作为一种预测方法,实际情况是这个技术最有效。

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#读取时间序列数据
df = pd.read_csv('../testdata/train.csv', error_bad_lines=False)
print(df.head())

#切分训练集和测试集
train = df[0:550]
test = df[550:]

# 设置数据以天变化
df.time = pd.to_datetime(df.time,format='%Y-%m-%d')
df.index = df.time
df = df.resample('D').mean()
train.time = pd.to_datetime(train.time,format='%Y-%m-%d')
train.index = train.time
train = train.resample('D').mean()
test.time = pd.to_datetime(test.time,format='%Y-%m-%d')
test.index = test.time
test = test.resample('D').mean()

#Average Forecast
y_hat_avg = test.copy()
y_hat_avg['avg'] = train['cv'].mean()
print(y_hat_avg)
plt.figure(figsize=(12,8))
plt.plot(train.index,train['cv'],label='Train')
plt.plot(test.index,test['cv'],label='Test')
plt.plot(y_hat_avg.index,y_hat_avg['avg'],label='Average Forecast')
plt.legend(loc='best')
plt.title('Average Forecast')
plt.show()

#均方差检查模型精度
from sklearn.metrics import mean_squared_error
from math import sqrt

rms = sqrt(mean_squared_error(test.cv,y_hat_avg.avg))
print(rms)
#9298381.954466905
#可以从RMSE值和上面的图推断,这种方法在每个时间段的平均值保持不变的时候效果最好。

可以看出这种模式没有提高我们的分数。因此,我们能从得分推断,这种方法在每个时间段的平均值保持不变的时候效果最好。虽然Naive法的得分优于均值法,但这并不意味着Naive法在所有数据集上都优于均值法。

方法3 移动均值法

考虑下面曲线图,
在这里插入图片描述
从图中可以推断,硬币的价格在一段时间以前大幅度地提高了,但现在是稳定的。很多时候,我们得到了一个数据集,其中一段时间以前对象的价格/销售量急剧增加/急剧下降。使用初期的价格会对下一个时间段的预测产生很大影响。所以相对于简单均值法的改进,只计算最后几个时间段的平均价格。显然,只有最近的值才是重要的。这种利用时间窗计算平均值的预测技术称为移动均值法。

利用一个简单的移动均值模型,根据一个不变的有限数p的平均值来预测时间序列中的下一个或多个值。因此,对所有的 i > p。
在这里插入图片描述

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#读取时间序列数据
df = pd.read_csv('../testdata/train.csv', error_bad_lines=False)
print(df.head())

#切分训练集和测试集
train = df[0:600]
test = df[600:]

# 设置数据以天变化
df.time = pd.to_datetime(df.time,format='%Y-%m-%d')
df.index = df.time
df = df.resample('D').mean()
train.time = pd.to_datetime(train.time,format='%Y-%m-%d')
train.index = train.time
train = train.resample('D').mean()
test.time = pd.to_datetime(test.time,format='%Y-%m-%d')
test.index = test.time
test = test.resample('D').mean()

#Moving Average Forecast
y_hat_avg = test.copy()
y_hat_avg['mov_avg'] = train['cv'].rolling(10).mean().iloc[-1]
print(y_hat_avg)
plt.figure(figsize=(12,8))
plt.plot(train.index,train['cv'],label='Train')
plt.plot(test.index,test['cv'],label='Test')
plt.plot(y_hat_avg.index,y_hat_avg['mov_avg'],label='Moving Average Forecast')
plt.legend(loc='best')
plt.title('Moving Average Forecast')
plt.show()

#均方差检查模型精度
from sklearn.metrics import mean_squared_error
from math import sqrt

rms = sqrt(mean_squared_error(test.cv,y_hat_avg.mov_avg))
print(rms)
#1432105.0414506379
#可以从RMSE值和上面的图推断,所以相对于简单均值法的改进,只计算最后几个时间段的平均价格。显然,只有最近的值才是重要的。这种利用时间窗计算平均值的预测技术称为移动均值法。

移动均值法的改进方法——加权移动均值法。在上述移动均值法中,我们同样权衡过去的N个观测值。但我们可能遇到的情况是,过去的每一次观察都以不同的方式影响预测。这种以不同的方式权衡过去观测值的技术称为加权移动均值技术。
加权移动均值是一个移动平均值,在滑动窗口的值中赋予不同的权重。
在这里插入图片描述
选择窗口的大小,需要一个权重列表。例如,如果选择[ 0.40,0.25,0.20,0.15 ]作为权重,将分别给出40%,25%,20%和15%。

方法4 简单指数平滑法

在理解了上述方法之后,可以注意到,简单均值法和加权移动均值法是完全相反的。我们需要在这两个方法之间采取某种方法,这两个方法在用不同的方式权衡数据点的同时要考虑所有数据。这种技术称为简单指数平滑法。预测是用加权平均来计算的,之前观测值的权重是指数递减的,最小的权重与最早的观测值相关:
在这里插入图片描述
0≤ α ≤1是参数。

先一步预测时间T + 1是一个序列中的所有观测值的加权平均值Y1,…,YT。权重下降的速率由参数α决定。

如果观察足够长的时间,你会看到,期望ŷx是α⋅YT和(1−α)⋅ŶT-1的和。

也可以写成 :
在这里插入图片描述
所以基本上我们已经有了一个1−α和α的加权移动平均值:。

可以看到,1−α乘以之前预期的表达递归的值ŷx−1。这就是为什么这种方法被称为Exponential。在时间t + 1的预测等于最近观察值yt 和最近预测值 ŷ t|t−1之间的加权平均值。

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#读取时间序列数据
df = pd.read_csv('../testdata/train.csv', error_bad_lines=False)
print(df.head())

#切分训练集和测试集
train = df[0:600]
test = df[600:]

# 设置数据以天变化
df.time = pd.to_datetime(df.time,format='%Y-%m-%d')
df.index = df.time
df = df.resample('D').mean()
train.time = pd.to_datetime(train.time,format='%Y-%m-%d')
train.index = train.time
train = train.resample('D').mean()
test.time = pd.to_datetime(test.time,format='%Y-%m-%d')
test.index = test.time
test = test.resample('D').mean()

#Exponential Forecast
from statsmodels.tsa.api import ExponentialSmoothing,SimpleExpSmoothing,Holt
y_hat_avg = test.copy()
fit2 = SimpleExpSmoothing(np.asarray(train['cv'])).fit(smoothing_level=0.6,optimized=False)
y_hat_avg['SES'] = fit2.forecast(len(test))
print(y_hat_avg)
plt.figure(figsize=(12,8))
plt.plot(train.index,train['cv'],label='Train')
plt.plot(test.index,test['cv'],label='Test')
plt.plot(y_hat_avg.index,y_hat_avg['SES'],label='Exponential Forecast')
plt.legend(loc='best')
plt.title('Exponential Forecast')
plt.show()

#均方差检查模型精度
from sklearn.metrics import mean_squared_error
from math import sqrt

rms = sqrt(mean_squared_error(test.cv,y_hat_avg.SES))
print(rms)
#1425009.0760642842

可以看到,用alpha值为0.6的简单指数模型形成一个更好的模型,到现在为止,生成一个更好的方法

5 霍尔特线性趋势法

我们现在已经学会了几种预测方法,但可以看到,这些模型在变化较大数据上不是太好。
在这里插入图片描述
趋势是在一段时间内观察到的价格的一般模式。如Naive方法会假定最后两点之间的趋势将保持不变,或者可以在所有点之间的平均斜率得到一个平均趋势,使用移动趋势均值或指数平滑法。

但我们需要一种方法,能准确无误地绘制趋势图。考虑数据集趋势的这种方法称为霍尔特线性趋势法。每个时间序列的数据集可以被分解为不同趋势的组成部分,季节性和剩余。任何跟随趋势的数据集都可以使用Holt线性趋势法进行预测。

霍尔特扩展简单指数平滑方法,允许有趋势的数据预测。它只适用于两个等级(多个序列的平均值)和趋势的指数平滑方法。用数学符号表示,现在需要三个等式:一个用于等级,一个用于趋势,一个结合等级与得到预测值Ŷ的趋势

作为简单指数平滑法,这里的等级等式表明它是一个观察数的加权平均值和样本内前步预测。趋势等式表明,这是一个基于ℓ(t)−ℓ(t−1)和和b(t−1)的时间t的预测趋势的加权平均值。

我们将添加这些等式来生成预测等式。也可以通过乘以趋势和等级而不是增加,来生成乘法预测等式。当趋势呈线性上升或下降时,则采用加法等式,而当趋势呈指数下降时,则采用乘法等式。实践表明乘法是一种更稳定的预测,但加性方法更容易理解。

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#读取时间序列数据
df = pd.read_csv('../testdata/train.csv', error_bad_lines=False)
print(df.head())

#切分训练集和测试集
train = df[0:580]
test = df[580:]

# 设置数据以天变化
df.time = pd.to_datetime(df.time,format='%Y-%m-%d')
df.index = df.time
df = df.resample('D').mean()
train.time = pd.to_datetime(train.time,format='%Y-%m-%d')
train.index = train.time
train = train.resample('D').mean()
test.time = pd.to_datetime(test.time,format='%Y-%m-%d')
test.index = test.time
test = test.resample('D').mean()

#Holt Linear
from statsmodels.tsa.api import ExponentialSmoothing,SimpleExpSmoothing,Holt
y_hat_avg = test.copy()
fit2 = Holt(np.asarray(train['cv'])).fit(smoothing_level=0.3,smoothing_slope=0.1)
y_hat_avg['holt_linear'] = fit2.forecast(len(test))
print(y_hat_avg)
plt.figure(figsize=(12,8))
plt.plot(train.index,train['cv'],label='Train')
plt.plot(test.index,test['cv'],label='Test')
plt.plot(y_hat_avg.index,y_hat_avg['holt_linear'],label='Holt Linear')
plt.legend(loc='best')
plt.title('Holt Linear')
plt.show()

#均方差检查模型精度
from sklearn.metrics import mean_squared_error
from math import sqrt

rms = sqrt(mean_squared_error(test.cv,y_hat_avg.holt_linear))
print(rms)
#7062387.952482162

方法6 Holt-Winters方法

考虑一个位于山上的旅馆。在夏季期间有很高的访问量,而今年余下时间的游客相对较少。因此,业主的利润在夏季比其他季节都要好得多。而且每年都一样,是季节性的。数据集在一段固定的时间间隔内显示出相似性。
在这里插入图片描述

由于季节性因素,使用霍尔特冬季方法将是其它模型中最好的选择。霍尔特-温特斯季节性方法包括预测等式和三个平滑等式-一个似乎等级ℓt,一个是趋势bt,一个是季节组成部分 st,平滑参数α,β和γ。

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#读取时间序列数据
df = pd.read_csv('../testdata/train.csv', error_bad_lines=False)
print(df.head())

#切分训练集和测试集
train = df[0:600]
test = df[600:]

# 设置数据以天变化
df.time = pd.to_datetime(df.time,format='%Y-%m-%d')
df.index = df.time
df = df.resample('D').mean()
train.time = pd.to_datetime(train.time,format='%Y-%m-%d')
train.index = train.time
train = train.resample('D').mean()
test.time = pd.to_datetime(test.time,format='%Y-%m-%d')
test.index = test.time
test = test.resample('D').mean()

#Holt Linear
from statsmodels.tsa.api import ExponentialSmoothing,SimpleExpSmoothing,Holt
y_hat_avg = test.copy()
fit1 = ExponentialSmoothing(np.asarray(train['cv']) ,seasonal_periods=7 ,trend='add', seasonal='add',).fit()
y_hat_avg['Holt_Winter'] = fit1.forecast(len(test))
plt.figure(figsize=(16,8))
plt.plot( train['cv'], label='Train')
plt.plot(test['cv'], label='Test')
plt.plot(y_hat_avg['Holt_Winter'], label='Holt_Winter')
plt.legend(loc='best')
plt.show()

#均方差检查模型精度
from sklearn.metrics import mean_squared_error
from math import sqrt

rms = sqrt(mean_squared_error(test.cv,y_hat_avg.Holt_Winter))
print(rms)
#2627706.3047538185

方法7 ARIMA
另一个在数据科学家中非常流行的时间序列模型是ARIMA。它代表自回归积分移动平均(Autoregressive Integrated Moving average)。指数平滑模型是基于对趋势和季节性数据的描述,ARIMA模型的目的是描述数据之间的相关性。ARIMA的改进考虑到数据集的季节性,就像Holt-Winters方法一样。

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#读取时间序列数据
df = pd.read_csv('../testdata/train.csv', error_bad_lines=False)
print(df.head())

#切分训练集和测试集
train = df[0:600]
test = df[600:]

# 设置数据以天变化
df.time = pd.to_datetime(df.time,format='%Y-%m-%d')
df.index = df.time
df = df.resample('D').mean()
train.time = pd.to_datetime(train.time,format='%Y-%m-%d')
train.index = train.time
train = train.resample('D').mean()
test.time = pd.to_datetime(test.time,format='%Y-%m-%d')
test.index = test.time
test = test.resample('D').mean()

#SARIMA
import statsmodels.api as sm
y_hat_avg = test.copy()
fit1 = sm.tsa.statespace.SARIMAX(train.cv, order=(2, 1, 4),seasonal_order=(0,1,1,7)).fit()
y_hat_avg['SARIMA'] = fit1.predict(start="2020-08-22", end="2020-09-03", dynamic=True)
plt.figure(figsize=(16,8))
plt.plot( train['cv'], label='Train')
plt.plot(test['cv'], label='Test')
plt.plot(y_hat_avg['SARIMA'], label='SARIMA')
plt.legend(loc='best')
plt.show()

#均方差检查模型精度
from sklearn.metrics import mean_squared_error
from math import sqrt

rms = sqrt(mean_squared_error(test.cv,y_hat_avg.SARIMA))
print(rms)
#1511711.2373576711

可以看到,使用季节性ARIMA生成一个类似Holt’s Winter的解决方案。我们选择的参数为ACF和PACF图。

猜你喜欢

转载自blog.csdn.net/qq_30868737/article/details/108470954