【问题标题】:Why do I get such strange results for time series analysis?为什么我会在时间序列分析中得到如此奇怪的结果?
【发布时间】:2019-12-02 10:32:35
【问题描述】:

我正在尝试建立一个模型来预测一家外卖咖啡馆的每日订单数量。这是数据,

在这里您可以看到两个主要高峰:它们是假期——分别是 2 月 14 日和 3 月 8 日。此外,您可以看到周期为 7 的明显季节性:人们在周末订购更多,而在工作日订购较少。

Dickey-Fuller 检验表明序列不是平稳的,p 值 = 0.152
然后我决定应用 Box-Cox 变换,因为偏差看起来不均匀。之后,Dickey-Fuller 检验的 p 值为 0.222,但转换后的系列现在看起来像一个正弦曲线,

然后我应用了这样的季节性差异:

data["counts_diff"] = data.counts_box - data.counts_box.shift(7)
plt.figure(figsize=(15,10))
sm.tsa.seasonal_decompose(data.counts_diff[7:]).plot()
p_value = sm.tsa.stattools.adfuller(data.counts_diff[7:])[1]

现在 p 值约为 10e-5 并且序列是平稳的

然后我绘制了 ACF 和 PACF 来选择网格搜索的初始参数,

常识和我知道的规则告诉我要选择,

Q = 1
q = 4
P = 3
p = 6

d = 0
D = 1

模型查找代码:

ps = range(0, p+1)
d=0
qs = range(0, q+1)
Ps = range(0, P+1)
D=1
Qs = range(0, Q+1)

parameters_list = []

for p in ps:
    for q in qs:
        for P in Ps:
            for Q in Qs:
                parameters_list.append((p,q,P,Q))
len(parameters_list)

%%time
from IPython.display import clear_output
results = []
best_aic = float("inf")

i = 1
for param in parameters_list:
    print("counting {}/{}...".format(i, len(parameters_list)))
    i += 1
    try:
        model=sm.tsa.statespace.SARIMAX(data.counts_diff[7:], order=(param[0], d, param[1]), 
                                        seasonal_order=(param[2], D, param[3], 7)).fit(disp=-1)

    except ValueError:
        print('wrong parameters:', param)
        continue
    except LinAlgError:
        print('LU decomposition error:', param)
        continue
    finally:
        clear_output()

    aic = model.aic
    if aic < best_aic:
        best_model = model
        best_aic = aic
        best_param = param
    results.append([param, model.aic])

网格搜索后,我得到了这个,

但是当我绘制它时,它会在零处显示一条恒定线,

残差是无偏的,没有趋势并且不是自相关的,

绘图代码在这里:

# inverse Box-Cox transformation
def invboxcox(y, lmbda):
    if lmbda == 0:
        return np.exp(y)
    else:
        return np.exp(np.log(lmbda*y+1) / lmbda)

data["model"] = invboxcox(best_model.fittedvalues, lmbda)
plt.figure(figsize(15,5))
plt.ylabel('Orders count')
data.counts.plot()
#pylab.show()
data.model.plot(color='r')
plt.ylabel('Model explanation')
pylab.show()

如果我取消注释该行,情节如下所示,

我错过了什么?我应该考虑转换系列的正弦形状吗?为什么规模如此不同?

还有代码,

data["model"] = invboxcox(best_model.fittedvalues, lmbda)  
plt.figure(figsize(15,5))  
(data.counts_diff + 1).plot()  
#pylab.show()  
data.model.plot(color='r')  
pylab.show()  

绘制两个相当相似的图,

所以,AFAIK,问题出在逆向转换中。

【问题讨论】:

  • 你能提供一些数据本身吗?顺便说一句:BoxCox 变换(包括逆变换)在 statsmodels.base.transform 中可用。
  • 是的,你可以在这里找到它:dropmefiles.com/Ac2rw

标签: python statistics time-series statsmodels


【解决方案1】:

让我们首先导入要领,加载数据并转换系列,

import matplotlib.pyplot as plt
import pandas as pd
import statsmodels.api as sm
from statsmodels.base.transform import BoxCox

# Load data
df = pd.read_csv('data.csv')
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)

# Transformation
box_cox = BoxCox()
y, lmbda = box_cox.transform_boxcox(df['counts'])

在 Box-Cox 转换您的系列之后,我对其进行了单位根测试,

>>>print(sm.tsa.kpss(y)[1])
0.0808334102754407

还有,

>>>print(sm.tsa.adfuller(y)[1])
0.18415817136548102

虽然根据 ADF 测试不完全静止,但 KPSS 测试不一致。目视检查似乎表明它可能是静止的“足够”。让我们考虑一个模型,

df['counts'] = y

model = sm.tsa.SARIMAX(df['counts'], None, (1, 0, 1), (2, 1, 1, 7))
result = model.fit(method='bfgs')

还有,

>>>print(result.summary())
Optimization terminated successfully.
         Current function value: -3.505128
         Iterations: 33
         Function evaluations: 41
         Gradient evaluations: 41
                                 Statespace Model Results                                
=========================================================================================
Dep. Variable:                            counts   No. Observations:                  346
Model:             SARIMAX(1, 0, 1)x(2, 1, 1, 7)   Log Likelihood                1212.774
Date:                           Wed, 24 Jul 2019   AIC                          -2413.549
Time:                                   13:37:19   BIC                          -2390.593
Sample:                               07-01-2018   HQIC                         -2404.401
                                    - 06-11-2019                                         
Covariance Type:                             opg                                         
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
ar.L1          0.8699      0.052     16.691      0.000       0.768       0.972
ma.L1         -0.5811      0.076     -7.621      0.000      -0.731      -0.432
ar.S.L7        0.0544      0.056      0.963      0.335      -0.056       0.165
ar.S.L14       0.0987      0.060      1.654      0.098      -0.018       0.216
ma.S.L7       -0.9520      0.036    -26.637      0.000      -1.022      -0.882
sigma2      4.385e-05   2.44e-06     17.975      0.000    3.91e-05    4.86e-05
===================================================================================
Ljung-Box (Q):                       34.12   Jarque-Bera (JB):                68.51
Prob(Q):                              0.73   Prob(JB):                         0.00
Heteroskedasticity (H):               1.57   Skew:                             0.08
Prob(H) (two-sided):                  0.02   Kurtosis:                         5.20
===================================================================================

Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).

Ljung-Box 结果似乎表明残差没有表现出自相关 - 这很好!让我们对数据和结果进行逆变换,然后绘制拟合图,

# Since the first 7 days were back-filled
y_hat = result.fittedvalues[7:]

# Inverse transformations
y_hat_inv = pd.DataFrame(box_cox.untransform_boxcox(y_hat, lmbda),
                         index=y_hat.index)

y_inv = pd.DataFrame(box_cox.untransform_boxcox(y, lmbda),
                     index=df.index)

# Plot fitted values with data
_, ax = plt.subplots()
y_inv.plot(ax=ax)
y_hat_inv.plot(ax=ax)

plt.legend(['Data', 'Fitted values'])
plt.show()

我在哪里,

看起来一点也不差!

【讨论】:

  • 您可能希望在SARIMAX 模型的规范中为您的假期高峰使用exog 参数。我没有,但它应该会提高你对这些峰值的适应度。
  • 训练模型时,我收到警告:Maximum number of iterations has been exceeded.Current function value: 4.494315Iterations: 50Function evaluations: 71Gradient evaluations: 71 但是,根据您的打印,迭代次数应该少于50. 为什么会这样?
  • @Anton 你在调用SARIMAX 模型之前设置了df['counts'] = y 吗?
  • 是的,它有帮助,谢谢。顺便说一句,我是时间序列分析的新手,所以你能回答更多问题吗?你是如何选择模型的订单的?为了更好地理解这个领域,你会推荐什么读物?
  • @Anton 我可能会从FPP 开始,也许读一下Hamilton 的TSA [这真的很深入并且不回避数学],还有练习 .我没有在这里选择任何参数(这些是你的),但通常你会查看 ACF/PACF 值,以及例如AIC 或 BIC。对于算法,您可以查看auto_arima
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
相关资源
最近更新 更多