지수 평활
이번 시간에는 지수평활이라는 기법에 대해서 알아보도록 하겠습니다
평활(smoothing)은 시계열 그래프를 매끄럽게 그린다는 뜻입니다. 이동 평균이랑 좀 비슷한 아이디어인데 이동 평균은 어떤 구간이 있으면 이 구간의 모든 값을 다 평균 내는 이런 방식이죠. 12달 이동 평균을 한다 그러면 12달 전에 데이터하고 이번 달 거하고 똑같이 12분의 1씩 반영이 된다는 얘기입니다. 좀 불합리하다고 할 수 있죠.
지수평활은 가까운 일에는 많이, 먼 과거의 일은 적게 반영하는 방식으로 평활을 합니다. 이렇게 하면 시간이 갈수록 현재의 평활된 값에 미치는 영향은 지수적으로 감소하게 됩니다.
호주 관광객 데이터
우리가 실습해볼 데이터는 호주 관광객 데이터입니다.
import pandas as pd
df = pd.read_excel('ausvisitor.xlsx')
y = df.visitor
이 데이터에서 df.visitor를 지수 평활해서 그려보겠습니다. $\alpha = 0.1$로 설정합니다. 이것은 직전의 평활치 90% 반영하고, 현재 값에 10%를 반영하여 새로운 평활치를 계산하는 방식입니다.
y.plot()
y.ewm(alpha=0.1).mean().plot();
단순 지수 평활: ETS(A, N, N)
ETS 모형은 오차(Error), 추세(Trend), 계절성(Seasonality)으로 구성된 모형입니다. 이 모형은 각각의 형태에 따라 다양한 모형으로 나눠집니다.
ETS(A, N, N)은 덧셈(Additive) 오차를 가지고 추세와 계절성은 가지지 않는 모형으로 단순 지수 평활과 동일한 모형입니다.
이 모형은 ETSModel
함수로 추정할 수 있습니다. initial_level
은 초기값, smoothing_level
이 $\alpha$가 됩니다.
from statsmodels.tsa.api import ETSModel
ets_ann = ETSModel(y).fit()
ets_ann.summary()
Dep. Variable: | visitor | No. Observations: | 68 |
---|---|---|---|
Model: | ETS(ANN) | Log Likelihood | -240.535 |
Date: | Sun, 28 May 2023 | AIC | 487.070 |
Time: | 16:05:13 | BIC | 493.729 |
Sample: | 0 | HQIC | 489.709 |
- 68 | Scale | 69.178 | |
Covariance Type: | approx |
coef | std err | z | P>|z| | [0.025 | 0.975] | |
---|---|---|---|---|---|---|
smoothing_level | 0.1964 | 0.048 | 4.101 | 0.000 | 0.103 | 0.290 |
initial_level | 27.5115 | 4.976 | 5.529 | 0.000 | 17.758 | 37.265 |
Ljung-Box (Q): | 10.91 | Jarque-Bera (JB): | 1.20 |
---|---|---|---|
Prob(Q): | 0.00 | Prob(JB): | 0.55 |
Heteroskedasticity (H): | 2.57 | Skew: | -0.00 |
Prob(H) (two-sided): | 0.03 | Kurtosis: | 2.35 |
Warnings:
[1] Covariance matrix calculated using numerical (complex-step) differentiation.
predict
함수에다가 start
는 0, end
는 100 하면 여기서부터 0부터 100까지 예측을 하게 됩니다.
실제 데이터가 있는 곳까지는 실제 데이터를 바탕으로 에러를 포함해서 평활하게 되고, 그곳을 넘어가면 에러가 없기 때문에 옆으로 주욱 가게 됩니다.
import matplotlib.pyplot as plt
y.plot(label='y')
ets_ann.predict(start=0, end=100).plot(label='ETS(A, N, N)')
plt.legend();
홀트 선형 추세 기법: ETS(A, A, N)
그 다음에 홀트의 선형 추세 기법이라고 하는 기법이 있는데요. 이 기법은 ETS(A, A, N)과 같습니다. 이 모형은 덧셈 오차와 덧셈 추세가 있는 모형입니다.
이 모형은 ETSModel
에서 trend=add
라고만 넣어서 추정할 수 있습니다.
from statsmodels.tsa.api import ETSModel
ets_aan = ETSModel(y, trend='add').fit()
ets_aan.summary()
Dep. Variable: | visitor | No. Observations: | 68 |
---|---|---|---|
Model: | ETS(AAN) | Log Likelihood | -231.928 |
Date: | Sun, 28 May 2023 | AIC | 473.856 |
Time: | 13:13:08 | BIC | 484.954 |
Sample: | 0 | HQIC | 478.254 |
- 68 | Scale | 53.707 | |
Covariance Type: | approx |
coef | std err | z | P>|z| | [0.025 | 0.975] | |
---|---|---|---|---|---|---|
smoothing_level | 0.0097 | nan | nan | nan | nan | nan |
smoothing_trend | 0.0097 | 0.006 | 1.680 | 0.093 | -0.002 | 0.021 |
initial_level | 25.1272 | 1.738 | 14.461 | 0.000 | 21.722 | 28.533 |
initial_trend | 0.1841 | 0.169 | 1.089 | 0.276 | -0.147 | 0.516 |
Ljung-Box (Q): | 11.15 | Jarque-Bera (JB): | 0.85 |
---|---|---|---|
Prob(Q): | 0.00 | Prob(JB): | 0.65 |
Heteroskedasticity (H): | 2.53 | Skew: | 0.01 |
Prob(H) (two-sided): | 0.03 | Kurtosis: | 2.45 |
Warnings:
[1] Covariance matrix calculated using numerical (complex-step) differentiation.
y.plot(label='y')
ets_aan.predict(start=0, end=100).plot(label='ETS(A, A, N)')
plt.legend();
감쇠 추세 기법: ETS(A, Ad, N)
홀트의 선형 기법은 현재 추세가 영원히 계속된다는 가정이 있습니다. 이것을 바꾼 것이 감쇠 추세 기법입니다. 이 기법은 추세가 점점 꺾인다는 가정이 있습니다. 추정을 할 때는 damped_trend=True
라고 설정해주시면 됩니다.
ets_aadn = ETSModel(y, trend='add', damped_trend=True).fit()
ets_aadn.summary()
Dep. Variable: | visitor | No. Observations: | 68 |
---|---|---|---|
Model: | ETS(AAdN) | Log Likelihood | -232.737 |
Date: | Sun, 28 May 2023 | AIC | 477.473 |
Time: | 16:13:15 | BIC | 490.790 |
Sample: | 0 | HQIC | 482.750 |
- 68 | Scale | 54.999 | |
Covariance Type: | approx |
coef | std err | z | P>|z| | [0.025 | 0.975] | |
---|---|---|---|---|---|---|
smoothing_level | 0.0164 | 0.089 | 0.185 | 0.853 | -0.158 | 0.191 |
smoothing_trend | 0.0164 | 0.023 | 0.730 | 0.466 | -0.028 | 0.061 |
damping_trend | 0.9800 | 0.069 | 14.112 | 0.000 | 0.844 | 1.116 |
initial_level | 26.2533 | 3.205 | 8.192 | 0.000 | 19.972 | 32.535 |
initial_trend | 0.1244 | 0.318 | 0.392 | 0.695 | -0.498 | 0.747 |
Ljung-Box (Q): | 10.90 | Jarque-Bera (JB): | 0.91 |
---|---|---|---|
Prob(Q): | 0.00 | Prob(JB): | 0.63 |
Heteroskedasticity (H): | 2.59 | Skew: | 0.02 |
Prob(H) (two-sided): | 0.03 | Kurtosis: | 2.43 |
Warnings:
[1] Covariance matrix calculated using numerical (complex-step) differentiation.
y.plot(label='y')
ets_aadn.predict(start=0, end=100).plot(label='ETS(A, Ad, N)')
plt.legend();
홀트-윈터스 계절성 기법: ETS(A, A, A)
ETS(A,A,A)는 계절성도 덧셈 형태로 추가되는 모형입니다. 추정을 할 때는 seasonal='add'
로 해주고, 계절성의 주기를 입력해줍니다. 4분기 단위의 계절성이 있으므로 seasonal_periods=4
로 설정해줍니다.
from statsmodels.tsa.api import ETSModel
ets_aaa = ETSModel(y, trend='add', seasonal='add',
seasonal_periods=4).fit()
ets_aaa.summary()
Dep. Variable: | visitor | No. Observations: | 68 |
---|---|---|---|
Model: | ETS(AAA) | Log Likelihood | -150.480 |
Date: | Sun, 28 May 2023 | AIC | 320.960 |
Time: | 13:13:52 | BIC | 343.155 |
Sample: | 0 | HQIC | 329.754 |
- 68 | Scale | 4.894 | |
Covariance Type: | approx |
coef | std err | z | P>|z| | [0.025 | 0.975] | |
---|---|---|---|---|---|---|
smoothing_level | 0.3042 | 0.099 | 3.075 | 0.002 | 0.110 | 0.498 |
smoothing_trend | 3.042e-05 | nan | nan | nan | nan | nan |
smoothing_seasonal | 0.4154 | 0.082 | 5.057 | 0.000 | 0.254 | 0.576 |
initial_level | 29.4939 | nan | nan | nan | nan | nan |
initial_trend | 0.5711 | 0.113 | 5.076 | 0.000 | 0.351 | 0.792 |
initial_seasonal.0 | -3.4686 | nan | nan | nan | nan | nan |
initial_seasonal.1 | -5.9855 | nan | nan | nan | nan | nan |
initial_seasonal.2 | -11.4778 | nan | nan | nan | nan | nan |
initial_seasonal.3 | 0 | nan | nan | nan | nan | nan |
Ljung-Box (Q): | 5.11 | Jarque-Bera (JB): | 8.62 |
---|---|---|---|
Prob(Q): | 0.75 | Prob(JB): | 0.01 |
Heteroskedasticity (H): | 0.48 | Skew: | -0.68 |
Prob(H) (two-sided): | 0.08 | Kurtosis: | 4.10 |
Warnings:
[1] Covariance matrix calculated using numerical (complex-step) differentiation.
y.plot(label='y')
ets_aaa.predict(start=0, end=100).plot(label='ETS(A, A, A)')
plt.legend();