Skip to content

Latest commit

 

History

History
616 lines (406 loc) · 24.9 KB

File metadata and controls

616 lines (406 loc) · 24.9 KB

三、基于指数平滑的方法

本章介绍了对时间序列信号的数据平滑处理。 本章的结构如下:

  • 时间序列平滑介绍
  • 一阶指数平滑
  • 二阶指数平滑
  • 建模高阶指数平滑
  • 概括

时间序列平滑介绍

时间序列数据由信号和噪声组成,其中信号捕获了过程的内在动力。 但是,噪声代表信号的未建模分量。 时间序列信号的内在动力学可以与过程的平均值一样简单,也可以是观测值内的复杂功能形式,如下所示:

*x[t] = f(x[i]) + ε[t]* for *i=1,2,3, ... t-1*

此处,x [t] 是观察值,而ε [t] 是白噪声。f(x [i] )表示功能形式; 常量作为函数形式的示例如下:

x [t] =μ+ε [t]

此处,上式中的常数值μ用作漂移参数,如下图所示:

图 3.1:带有漂移参数的时间序列示例

由于ε [t] 是白噪声,因此这种基于平滑的方法可以通过消除固有函数形式与随机噪声进行分离。 平滑预测方法可以视为采用输入并分离趋势和噪声成分的过滤器,如下图所示:

图 3.2:平滑过程的框架

估计趋势和噪声的提取效率取决于与时间序列信号组成相关的其他参数,例如趋势,季节性和残差(噪声)的存在。 为了处理时间序列的每个组成部分,需要进行不同的处理。 本章将介绍多种平滑处理时间序列信号不同成分的方法。 使用从 1946 年 1 月到 1959 年 12 月的每月水平收集的纽约出生数据集,演示了一个由趋势,季节性和白噪声组成的时间序列信号示例:

Import requests 
import statsmodels.api as sm 
import io 
import pandas as pd 

# Load Dataset 
DATA_URL="http://robjhyndman.com/tsdldata/data/nybirths.dat" 
fopen = requests.get(DATA_URL).content 
ds=pd.read_csv(io.StringIO(fopen.decode('utf-8')),  header=None, names=['birthcount']) 
print(ds.head()) 

# Add time index 
date=pd.date_range("1946-01-01", "1959-12-31", freq="1M") 
ds['Date']=pd.DataFrame(date) 
ds = ds.set_index('Date') 

# decompose dataset 
res = sm.tsa.seasonal_decompose(ds.birthcount, model="additive") 
resplot = res.plot() 

代码中的不同功能如下使用:

  • 前面脚本中的requests.get函数用于从 URL DATA_URL 获取数据。
  • 要处理数据集,请使用 pandas DataFrame。
  • 统计模型模块的seasonal_decompose功能用于将时间序列信号分解为趋势,季节性和残差成分。 如第 2 章,“时间序列简介”中所述,分解可以是加法运算或乘法运算。 下图显示了信号不同成分的示例:

图 3.3:时间序列信号的分解

先前的时间序列信号由趋势,季节性和残差(噪声)组成。 如图进行平滑处理的框架所示,平滑有助于去除残留分量,并捕获预测信号的趋势和季节性分量。

包括均值,趋势和非季节性模式的第一步模型是使用平滑外推法。 第 2 章,“了解时间序列数据”中讨论了使用移动平均的基本平滑。 移动平均平滑使用先前的所有观察评估期望 E(xt),如下所示:

通常,在窗口上执行简单的移动平均; 因此,使用目标函数在最佳窗口上评估估计的预测,以最大程度地减少误差:

平滑方法基于以下假设:时间序列数据是局部平稳的,且均值变化很小。 因此,我们可以使用时间t的平均值来预测时间[delta]小到足以保持信号平稳的 t + 1。 该模型是没有漂移模型的均值和随机游走之间的折衷方案。 该模型也称为平滑模型,因为它可以平滑数据集中的颠簸。 这些基于移动平均的方法的主要局限性在于,它会同等地对待平滑中使用的所有n样本,而忽略了观察新近度的影响,即,将较高的权重赋给最近的观察,如以下等式所示 :

w [1] > w [2] > w [3] > ... > w [T []T是窗口大小。 这对权重的评估提出了另一个挑战。 通过对观察值使用指数衰减权重进行指数平滑,可以解决移动平均值和加权移动平均值的局限性。

一阶指数平滑

一阶指数平滑或简单指数平滑适合具有恒定方差且无季节性的情况。 通常建议使用此方法进行短期预测。 第 2 章和“了解时间序列数据”引入了朴素的预测方法,其中将地平线 h 的预测定义为 t 值(或最后一个观测值):

*x[t+h] = x[t]*

该方法通过简单的移动平均值进行扩展,该方法使用多个历史点的均值扩展了朴素的方法:

该方法假定所有历史观测值都具有相同的权重,如下图所示:

图 3.4:随窗口大小增加分配给观察的权重

随着移动平均的窗口大小的增加,分配给每个观察值的权重会变小。 一阶指数通过为历史数据点提供指数,从而扩展了当前方法,历史数据点的权重从最新数据点到最早的数据点呈指数递减。 一阶指数平滑可以定义如下:

α是[0,1]之间的平滑因子,它控制权重降低的速率,x [t] 是时间时的观测值 ] t。 下图显示了平滑过程,它显示了具有不同平滑因子α的权重的衰减:

图 3.5:以不同的 alpha 值分配给历史观测值的权重示意图

α的值越高,权重衰减越快; 因此,历史数据对预测值的影响较小。 单阶指数平滑的预测方程式可以进一步简化为:

*F[1] = x[1]*
*F[2] = αx[1] + (1-α)F[1] = αx[1] + (1-α)x[1] = x[1]*
*F[3] = αx[2] + (1-α)F[2]*

...

*F[t-1] = αx[t] + (1-α)F[t-1]*

在此,F [t-1] 是在时间t的预测值,表示如下:

简化形式显示了时间 t 的预测值作为时间 t-1 处的函数预测值与时间 t 处的观测值之间的关系。 该预测也称为 Holt-Winters 预测。

从前面的等式中可以看出,在第一时间实例中,将初始值分配给第一预测值作为观察值,F [1] = x [1],第二个时间实例也采用第一个实例的值。 重新引导预测的另一种方法是使用可用数据或数据子集的平均值,如下所示:

在移动平均指数平滑中检测窗口大小和权重的类似问题要求优化平滑参数α。 正确选择α非常关键。 例如,选择α= 0 会将所有值平滑为初始分配的值,如下所示:

*F[t+1] = F[t-1]*

类似地,α= 1 表示指数平滑的最平滑情况,如下所示:

*F[t+1] = x[t]*

让我们以一个 IBM 普通股收盘示例为例,使用单一平滑方法进行预测。 第一步是加载所需的模块:

# Load modules 
from __future__ import print_function 
import os 
import pandas as pd 
import numpy as np 
from matplotlib import pyplot as plt 

当前示例将使用 Python 中的ospandasnumpymatplotlib模块。 使用pandasDataFrame将数据集加载到 Python 环境中:

# Load Dataset 
ibm_df = pd.read_csv('datasets/ibm-common-stock-closing-prices.csv') 
ibm_df.head() 

为了方便起见,我们将重命名这些列:

#Rename the second column 
ibm_df.rename(columns={'IBM common stock closing prices': 'Close_Price'},inplace=True) 

输出数据集将如图图 3.6 所示:

图 3.6:样本 IBM 收盘股价数据集

在单平滑指数方法中,预测值生成如下:

...

前面的系列可以通过以下方式在 Python 中实现:

# Function for Single exponential smoothing 
def single_exp_smoothing(x, alpha): 
    F = [x[0]] # first value is same as series 
    for t in range(1, len(x)): 
        F.append(alpha * x[t] + (1 - alpha) * F[t-1]) 
    return F  

设置有初始预测值的single_exp_smoothing功能被指定为该系列的第一个值。 让我们首先评估α= 0α= 1 的极端预测情况:

# Single exponential smoothing forecasting 
ibm_df['SES0'] = single_exp_smoothing(ibm_df['Close_Price'], 0) 
ibm_df['SES0'] = single_exp_smoothing(ibm_df['Close_Price'], 1) 

上一个脚本的输出如下:

图 3.7:平滑参数为零和一的简单指数平滑

上图说明,在α= 0 时,预测值是一个常数,而对于α= 1,预测的序列偏移1时滞。 。 可以对平滑值 0.2 的单个平滑预测进行如下评估:

# Single exponential smoothing forecasting 
ibm_df['SES'] = single_exp_smoothing(ibm_df['Close_Price'], 0.8) 

可以针对实际数据绘制指数平滑的结果,如图图 3.18 所示:

### Plot Single Exponential Smoothing forecasted value 
fig = plt.figure(figsize=(5.5, 5.5)) 
ax = fig.add_subplot(2,1,1) 
ibm_df['Close_Price'].plot(ax=ax) 
ax.set_title('IBM Common Stock Close Prices during 1962-1965') 
ax = fig.add_subplot(2,1,2) 
ibm_df['SES'].plot(ax=ax, color='r') 
ax.set_title('Single Exponential Smoothing') 

图 3.8:实际值与预测值之间的比较

可以使用标准目标函数,例如平均平方误差MSE平均绝对误差MAS):

同样,MAS 的评估如下:

让我们评估α对拟合的影响。 为了评估它,使用不同的平滑参数开发了多个模型,如下所示:

#Calculate the single exponential forecast at different values 
ibm_df['SES2']  = single_exp_smoothing(ibm_df['Close_Price'], 0.2) 
ibm_df['SES6']= single_exp_smoothing(ibm_df['Close_Price'], 0.6) 
ibm_df['SES8']= single_exp_smoothing(ibm_df['Close_Price'], 0.8) 

图 3.5 将预测值与实际值进行比较:

图 3.9:alpha 的效果示意图

上图说明了 alpha 对预测的影响很大; 因此,在设置预测时获取正确的 alpha 值至关重要。 可以使用以下脚本获得以上图表:

# Plot the curves 
f, axarr = plt.subplots(3, sharex=True) 
f.set_size_inches(5.5, 5.5) 

ibm_df['Close_Price'].iloc[:45].plot(color='b', linestyle = '-', ax=axarr[0]) 
ibm_df['SES2'].iloc[:45].plot(color='r', linestyle = '-', ax=axarr[0]) 
axarr[0].set_title('Alpha 0.2') 

ibm_df['Close_Price'].iloc[:45].plot(color='b', linestyle = '-', ax=axarr[1]) 
ibm_df['SES6'].iloc[:45].plot(color='r', linestyle = '-', ax=axarr[1]) 
axarr[1].set_title('Alpha 0.6') 

ibm_df['Close_Price'].iloc[:45].plot(color='b', linestyle = '-', ax=axarr[2]) 
ibm_df['SES8'].iloc[:45].plot(color='r', linestyle = '-', ax=axarr[2]) 
axarr[2].set_title('Alpha 0.8') 

由于平滑有助于减少数据集方差,因此它将减少预测序列在零到实际数据集方差之间的方差:

解决前面的方程式将导致以下差异:

在此,T是时间序列的长度。 对于系列 x [T] 的单位方差,由预测系列捕获的方差将基于平滑参数α改变,如下所示:

图 3.10:使用 alpha 变化的简单指数平滑捕获的方差

二阶指数平滑

如果一阶指数平滑效果不佳,则时间序列数据中存在趋势。 这种趋势通常在许多领域都可以观察到,例如当电子商务公司进行营销活动时,销售的增长或公司的任何良好的年度业绩都会对其股票价格产生看涨的影响。 线性趋势可能由于时间和响应之间的线性趋势而发生:

*x[t] = constant + ωt + ε[t]*

在此,ω是导致趋势的系数。 通过将另一项包括到一阶指数平滑中,二阶指数平滑可以帮助捕获时间序列数据的趋势,如下所示:

在此,T [t] 捕获指数平滑的趋势分量,并表示如下:

在此,α是数据平滑因子,β是趋势平滑因子,其值在[0,1]之间。 下一阶段的预测可以如下生成:

在二阶平滑中,趋势分量的初始值可以通过多种方式分配:

在此,n是观察次数。 让我们演示一个二阶平滑的示例。 我们将使用啤酒产量数据。 以下是演示步骤:

  1. 第一步是加载所需的模块:
    # Load modules 
    from __future__ import print_function 
    import os 
    import pandas as pd 
    import numpy as np 
    from matplotlib import pyplot as plt 

    Load beer dataset as pandas DataFrame. 
    #Read dataset into a pandas.DataFrame 
    beer_df = pd.read_csv('datasets/quarterly-beer-production-in-
    aus-March 1956-June 1994.csv')
  1. 让我们创建一个用于双指数平滑的函数:
    # Function for double exponential smoothing 
    def double_exp_smoothing(x, alpha, beta): 
        yhat = [x[0]] # first value is same as series 
        for t in range(1, len(x)): 
            if t==1: 
                F, T= x[0], x[1] - x[0] 
            F_n_1, F = F, alpha*x[t] + (1-alpha)*(F+T) 
            T=beta*(F-F_n_1)+(1-beta)*T 
            yhat.append(F+T) 
        return yhat 

前面的函数将时间序列作为带有 alpha 和 beta 的输入。 前面的实现使用前两次出现的差来设置初始趋势值。

  1. 让我们评估一下 alpha beta 边界情况的性能,即 alpha 和 beta 平滑参数的(0,0),(0,1),(1,0)和(1,1)值:
    # Effect of alpha and beta 
    beer_df['DEF00'] = double_exp_smoothing(beer_df['Beer_Prod'],0, 0) 
    beer_df['DEF01'] = double_exp_smoothing(beer_df['Beer_Prod'],0, 1) 
    beer_df['DEF10'] = double_exp_smoothing(beer_df['Beer_Prod'],1, 0) 
    beer_df['DEF11'] = double_exp_smoothing(beer_df['Beer_Prod'],1, 1) 

下图显示了适合二阶指数平滑的前一个脚本的结果:

图 3.11:二阶指数平滑中的 alpha 和 beta 平滑参数对啤酒销售数据集的影响

当α= 0 时,初始值保持恒定; 因此,趋势参数不起作用。 但是,当α= 1 和β= 1 时,二阶指数平滑可以写为:

时间t时的预测取决于先前的值和趋势成分。 当β设置为零时,t-1 的趋势分量将取决于 t-2

因此,趋势分量值取决于初始分配值,并且是一个常数。

类似地,对于α= 1 和β= 1,二阶指数平滑可以简化如下:

与α的配置相比,在α= 1 和β= 1 的情况下,将 t-2t-3 的差与时间t预测值相加。 α= 1 和β= 0,这使预测值发生偏移,并且更接近于实际预测值。

让我们使用α和β的中间值对啤酒数据执行双指数平滑,如下所示:

beer_df['DEF'] = double_exp_smoothing(beer_df['Beer_Prod'], 0.4, 0.7) 

图 3.12:实际和双指数预测值之间的比较

我们还比较一下单指数和双指数平滑的性能:

图 3.13:单指数和双指数预测值之间的比较

上图显示,与单指数平滑相比,双指数平滑能够更好地捕获当前数据集的真实信号变化。 但是,在趋势成分趋于零的情况下,单指数和双指数平滑方法的性能是可比的。

建模高阶指数平滑

该概念可以进一步扩展为使用nth 阶多项式模型的高阶指数平滑:

在此,误差ε [t] 〜N(0,σ 2 )正态分布,均值为 0,σ [2] 方差。 用于更高阶的指数平滑器如下:

...

这是平滑器的权重。 通常,不及时使用高阶指数平滑,因为即使对于二阶平滑,计算也变得非常困难,并且使用了诸如自回归综合移动平均值ARIMA)之类的方法。 将在第 4 章,“自回归模型”中进一步讨论。

另一个非常流行的指数平滑是三重指数平滑。 三重指数平滑允许您捕获具有水平和趋势的季节性。 使用以下等式定义级别,趋势和季节性之间的关系:

在这些等式中,F [t] 捕获了在时间 t 处的观察水平。 类似地,T [t]S [t] 在时间 t 捕获趋势和季节性。 系数α,β和γ分别表示数据平滑因子,趋势平滑因子和季节性平滑因子,其值在[0,1]之间。 这些等式可用于预测下一个时间段,如下所示:

前面的等式可以推广到任何周期 m,如下所示:

术语 F [t] 捕获了季节性成分相对于最近观察到的季节性趋势的偏移。 由于将三重指数平滑应用于季节和趋势时间序列,因此可以使用这些值来计算趋势的更好的起始值。 让我们使用威斯康星州就业数据演示三阶指数平滑。

可以从这个页面下载威斯康星州就业数据,并可以使用pandas.read_csv命令在 Python 环境中加载 csv 文件。

  1. 第一步是加载所需的模块:
# Load modules 
from __future__ import print_function 
import os 
import pandas as pd 
import numpy as np 
from matplotlib import pyplot as plt 

#read the data from into a pandas.DataFrame 
wisc_emp = pd.read_csv('datasets/wisconsin-employment-time-series.csv') 

图 3.14:威斯康星州员工数据集

上图显示了威斯康星州员工时间序列数据集。 该数据集包括年度趋势和每月季节性。 我们知道数据的季节性模式。 因此,季节性信息可用于使用以下公式得出趋势的初始值,作为整个季节的平均值:

  1. 前面的等式可以在 Python 中实现,如下所示:
# Initialize trend value 
def initialize_T(x, seasonLength): 
    total=0.0 
    for i in range(seasonLength): 
        total+=float(x[i+seasonLength]-x[i])/seasonLength 
    return total 

例如,使用以下脚本,由前面的函数生成的初始趋势值是 1.69:

initialize_T(wisc_emp['Employment'], 12) 
  1. 初始季节性非常关键,可以使用以下函数进行计算:
# Initialize seasonal trend 
def initialize_seasonalilty(x, seasonLength): 
    seasons={} 
    seasonsMean=[] 
    num_season=int(len(x)/seasonLength) 
    # Compute season average 
    for i in range(num_season): 
        seasonsMean.append(sum(x[seasonLength*i:seasonLength*i+seasonLength])/float(seasonLength)) 

    # compute season intial values 
    for i in range(seasonLength): 
        tot=0.0 
        for j in range(num_season): 
            tot+=x[seasonLength*j+i]-seasonsMean[j] 
        seasons[i]=tot/num_season 
    return seasons 

将季节的初始值计算为响应 x 的平均值。

  1. 一旦获得值,我们就可以设置三重指数预测了:
# Triple Exponential Smoothing Forecast 
def triple_exp_smoothing(x, seasonLength, alpha, beta, gamma, h): 
    yhat=[] 
    S = initialize_seasonalilty(x, seasonLength) 
    for i in range(len(x)+h): 
        if i == 0: 
            F = x[0] 
            T = initialize_T(x, seasonLength) 
            yhat.append(x[0]) 
            continue 
        if i >= len(x): 
            m = i - len(x) + 1 
            yhat.append((F + m*T) + S[i%seasonLength]) 
        else: 
            obsval = x[i] 
            F_last, F= F, alpha*(obsval-S[i%seasonLength]) + (1-alpha)*(F+T) 
            T = beta * (F-F_last) + (1-beta)*T 
            S[i%seasonLength] = gamma*(obsval-F) + (1-gamma)*S[i%seasonLength] 
            yhat.append(F+T+S[i%seasonLength]) 
    return yhat 

三重指数平滑由α,β和γ控制。 是否存在任何情况都会对结果产生巨大影响。 让我们对不同的极端情况进行经验比较,如威斯康星州就业数据集所示:

图 3.15:极限值时的不同配置

使用以下代码生成使用设置为 1 的 alpha,beta 或 gamma 值的三重指数平滑的预测:

# Effect of alpha and beta 
wisc_emp['TEF001'] = triple_exp_smoothing(wisc_emp['Employment'], 12, 0, 0, 1, 0) 
wisc_emp['TEF010'] = triple_exp_smoothing(wisc_emp['Employment'], 12, 0, 1, 0, 0) 
wisc_emp['TEF100'] = triple_exp_smoothing(wisc_emp['Employment'], 12, 1, 0, 0, 0) 

# Plot alpha=0, beta=0, gamma=1 
fig = plt.figure(figsize=(5.5, 5.5)) 
ax = fig.add_subplot(3,1,1) 
wisc_emp['Employment'].plot(color='b', linestyle = '-', ax=ax)  
wisc_emp['TEF001'].plot(color='r', linestyle = '--', ax=ax) 
ax.set_title('TES: alpha=0, beta=0, gamma=1') 

# Plot alpha=0, beta=1, gamma=0 
ax = fig.add_subplot(3,1,2) 
wisc_emp['Employment'].plot(color='b', linestyle = '-', ax=ax)  
wisc_emp['TEF010'].plot(color='r', linestyle = '--', ax=ax) 
ax.set_title('TES: alpha=0, beta=1, gamma=0') 

# Plot alpha=1, beta=0, gamma=0 
ax = fig.add_subplot(3,1,3) 
wisc_emp['Employment'].plot(color='b', linestyle = '-', ax=ax)  
wisc_emp['TEF100'].plot(color='r', linestyle = '--', ax=ax) 
ax.set_title('TES: alpha=1, beta=0, gamma=0') 
fig.subplots_adjust(hspace=.5) 

图 3.16:使用(i)alpha:0,beta:0 和 gamma:1 的三重指数平滑进行预测; (ii)alpha:0,beta:1 和 gamma:0; 和(iii)alpha:0,beta:0 和 gamma:1

上图显示了使用数据平滑因子 alpha 或季节性因子 gamma 设置为 1 的三重指数平滑。 下图显示了使用此脚本针对两个参数设置为一个的相似性绘图:

# Effect of alpha and beta 
wisc_emp['TEF110'] = triple_exp_smoothing(wisc_emp['Employment'], 12, 1, 1, 0, 0) 
wisc_emp['TEF101'] = triple_exp_smoothing(wisc_emp['Employment'], 12, 1, 0, 1, 0) 
wisc_emp['TEF011'] = triple_exp_smoothing(wisc_emp['Employment'], 12, 1, 1, 1, 0)

图 3.17:使用(i)alpha:1,beta:1 和 gamma:0 的三重指数平滑进行预测; (ii)alpha:1,beta:0 和 gamma:1; 和(iii)alpha:0,beta:1 和 gamma:1

没有将 beta 设置为零的模型要优于其他模型。 让我们使用中间参数运行三次指数平滑,如下图所示:

图 3.18:实际与三次指数平滑比较

可以使用保留样本上的均方根误差来优化预测。 让我们比较一下单,双和三重指数平滑的性能,如下图所示:

图 3.19:单指数,双指数和三倍指数平滑之间的比较

根据经验研究,使用平滑或季节性的单一级别可以捕获数据趋势; 因此,所有模型均表现出色,因为单指数和双指数能够使用平滑因子进行预测,而三指数平滑能够使用平滑因子或季节性因子来捕获预测。

概括

本章介绍了用于平滑时间序列数据的指数平滑方法。 通过包括诸如平滑因子,趋势因子和季节性因子之类的术语,可以轻松地扩展这些方法以进行预测。 单阶指数平滑仅使用平滑因子执行平滑,通过包括趋势分量,第二阶平滑因子进一步扩展了平滑因子。 还涵盖了三阶平滑处理,该平滑处理将所有平滑处理,趋势和季节性因素合并到模型中。

本章详细介绍了所有这些模型的 Python 实现。 平滑方法可用于预测时间序列是否为平稳信号。 但是,该假设可能不正确。 建议使用高阶指数平滑,但计算起来会很困难。 因此,为应对这种方法,提出了其他预测技术,例如 ARIMA,将在下一章中介绍。