Meet Our Team
home

Time-series 데이터 분석: Holt-Winters

이정엽 (Jungyup Lee)
이정엽 (Jungyup Lee)
우리는 종종 시계열 데이터에 대한 분석/예측을 하게 됩니다. 예를 들어 다음 시간의 주가를 예측하거나, 며칠 후의 매출을 예측하거나, 내일의 기온을 예측하는 일이 이에 해당합니다. 아래와 같이 시계열 데이터를 분석하는 방법들은 상당히 다양합니다.
•
AR
•
MA
•
ARIMA
•
VAR
•
VARMA
•
Simple Exponential Smoothing
•
Holt-Winters
•
…
오늘은 이 중에서도 이론적으로 복잡하지 않으면서 상당히 효과적으로 예측을 하는 Holt-Winters 방법을 알아보도록 하겠습니다.
xn+hnx_{n+h}^n 을 time n 까지의 관측된 데이터를 가지고 예측한 n + h 시점에 대한 x값이라고 나타내 봅시다.
즉, n 은 실제 데이터를 포함하는 trainset 에 해당하는 마지막 시간을 나타내며, n + h 는 예측하고자 하는 미래 시간을 나타냅니다.
h = 1 이라고 한다면, 우리는 아래와 같은 몇몇 naive 한 방법으로도 예측할 수 있습니다.
•
xn+1n=xnx_{n+1}^n = x_n
•
xn+1n=xn+1−Sx_{n+1}^n = x_{n+1-S} , 예를 들어 S = 7 (weekly seasonal 값)
•
xn+1n=∑i=1nxinx_{n+1}^n = \frac{\sum_{i=1}^{n}x_i}{n}
하지만 늘 그렇듯이 우리는 좀 더 아름다운 방법을 원합니다.
학부 때 배운 geometric series 를 활용하여 좀 더 아름답게 개선해 보겠습니다.
∑k=0∞(1−α)k=1α\sum_{k=0}^{\infty}(1-\alpha)^k = \frac{1}{\alpha}, 0<α<20<\alpha<2
이를 풀어서 다시 써보면,
∑k=0∞(1−α)k=1=α+α(1−α)+α(1−α)2+⋯+α(1−α)k+⋯\sum_{k=0}^{\infty}(1-\alpha)^k = 1 = \alpha + \alpha(1-\alpha)+\alpha(1-\alpha)^2+\cdots+\alpha(1-\alpha)^k+\cdots
가 됩니다.
이처럼 sum 이 1이 되는 decaying series를 가중치로 사용하게 된다면, 시간이 가까운 데이터는 가중치를 높게 할당하고 오래전 데이터는 가중치를 작게 할당하여 미래의 x값을 예측할 수 있게 됩니다. 이를 exponential smoothing 이라고 부릅니다.
xn+1n=αxn+α(1−α)xn−1+α(1−α)2xn−2+⋯+α(1−α)kxn−k+⋯(1)x_{n+1}^n = \alpha x_n + \alpha(1-\alpha) x_{n-1} + \alpha(1-\alpha)^2 x_{n-2}+\cdots+\alpha(1-\alpha)^k x_{n-k}+\cdots \tag{1}
위 수식(1)을 좀 더 간결하고 아름답게 recurrence form으로 표현하기 위해 (1−α)(1-\alpha)를 곱하고 n을 n + 1 로 치환시켜주면 아래와 같은 수식을 얻게 됩니다.
xn+1n=αxn+(1−α)xnn−1x_{n+1}^n = \alpha x_n + (1-\alpha)x_{n}^{n-1}
초기 조건을 x21=x1x_2^1 = x_1 이라고 가정 한 뒤 n을 증가시켜가며 풀어보면 아래와 같습니다.
x21=x1x32=αx2+(1−α)x21x43=αx3+(1−α)x32...\begin{aligned} x_2^1 &= x_1 \\ x_3^2 &= \alpha x_2 + (1-\alpha)x^1_2 \\ x_4^3 &= \alpha x_3 + (1-\alpha)x^2_3 \\ ... \end{aligned}
즉, n + 1 시간의 새로운 예측 값이란 α×(n\alpha \times (n 시간의 실측 값)+(1−α)×(n) + (1-\alpha)\times(n 시간의 예측 값)이 되게 됩니다.
그렇다면, 어떻게 적절한 α\alpha 값을 구할 수 있을까요? 그것은 단순히 예측값들과 실측값들에 대한 sum of squared errors(SSE)를 가지고 구할 수 있습니다.
SSE(α)=∑i=1n(xn−xnn−1)2SSE(\alpha) = \sum_{i=1}^{n}(x_n - x_n^{n-1})^2
αopti=argminαSSE(α)\alpha_{opti} = argmin_{\alpha}SSE(\alpha)
이제 위 알고리듬을 Holt-Winters 방법으로 확장 시켜 보겠습니다.
Holt-Winters 알고리듬은 단순한 exponential smoothing 뿐만 아니라 trend 속성과 seasonality 속성이 추가되게 됩니다.
여기서 trend란 장기적인 데이터의 경향을 나타내며, seasonality란 데이터의 반복되는 주기성을 나타내게 됩니다. 따라서 trend 개념은 n + 1 시간의 값과 n 시간의 값의 차이이며, 이를 나중에 exponential smoothing 하게 됩니다.
일단 trend term을 추가하여 예측을 새롭게 정의해 보겠습니다.
x^n+1=leveln+trendn\hat{x}_{n+1} = level_n + trend_n
여기서 ^를 사용하여 n + 1 시점의 예측값을 나타냈으며, levelnleveln 은 n시점에 예측된 n + 1 시점의 level 값을 나타냅니다.
일단 trend는 무시하고 level을 앞에서 설명했던 exponential smoothing 으로 다음처럼 표현해봅시다.
new level = α×\alpha \times new information +(1−α)×+ (1 - \alpha) \times old level
x^n+1=αxn+(1−α)x^n→x^n+1=levelnleveln=αxn+(1−α)leveln−1\hat{x}_{n+1} = \alpha x_n + (1-\alpha)\hat{x}_n \xrightarrow[ ]{\hat{x}_{n+1}=level_n} level_n = \alpha x_n+(1-\alpha)level_{n-1}
그런 다음 장기적인 데이터의 경향 정보를 포함하는 trend를 고려하여 new level을 예측할 때 old level 값뿐만 아니라 trend 값을 포함시켜 봅시다.
new level = α×\alpha \times new information +(1−α)×(+ (1 - \alpha) \times ( old level + old trend ))
따라서 아래와 같은 수식을 얻게 됩니다.
leveln=αxn+(1−α)(leveln−1+trendn−1)level_n = \alpha x_n+(1-\alpha)(level_{n-1} + trend_{n-1})
trend 또한 β\beta 라는 파라미터를 사용하여 exponential smoothing 하여 나타내 봅니다.
trendn=β×trend_n = \beta \times new trend +(1−β)×+ (1-\beta) \times old trend
→\rightarrow
trendn=β(leveln−leveln−1)+(1−β)trendn−1trend_n = \beta(level_n-level_{n-1})+(1-\beta)trend_{n-1}
또한, 초깃값은 아래와 같습니다.
level1=x1level_1=x_1
trend1=x2−x1trend_1=x_2-x_1
βopti\beta_{opti} 값 또한 αopti\alpha_{opti}처럼 SSE가 최소가 되는 지점을 찾아 구할 수 있습니다.
이제 seasonality term을 추가해 보겠습니다. Seasonality란 앞에서 말했던 것처럼 데이터의 주기성 정보를 포함하게 됩니다. 이 반복되는 short-term 패턴은 보통 아래 그림처럼 multiplicative와 additive 두 가지 타입으로 나눌 수 있습니다.
첫 번째 그림은 multiplicative 특징을 보여주며, 두 번째 그림은 additive 특징을 보여줍니다.
일단 앞에서 trend term을 추가하였던 것처럼, 시간 주기가 m인 seasonality term을 추가해 보면 h시간 후의 예측값 x^n+h\hat{x}_{n+h} 은 아래와 같이 표현됩니다.
•
x^n+h=leveln+h×trendn+seasonaln+h−m\hat{x}_{n+h}=level_n + h \times trend_n + seasonal_{n+h-m}
•
x^n+h=(leveln+h×trendn)×seasonaln+h−m\hat{x}_{n+h}=(level_n + h \times trend_n) \times seasonal_{n+h-m}
m값의 경우 만약 시간 unit이 day이고 weekly seasonal(7 days)을 가정하면 m = 7이 됩니다.
각 term 들을 정리해 보면 아래와 같습니다.
leveln=α(xn−seasonaln−m)+(1−α)(leveln−1+trendn−1)trendn=β(leveln−leveln−1)+(1−β)trendn−1seasonaln=γ(xn−leveln)+(1−γ)seasonaln−m\begin{aligned} level_n &= \alpha(x_n - seasonal_{n-m}) + (1-\alpha)(level_{n-1}+trend_{n-1}) \\ trend_n &= \beta(level_n - level_{n-1}) + (1-\beta)trend_{n-1} \\ seasonal_n &= \gamma(x_n - level_n)+(1-\gamma)seasonal_{n-m} \end{aligned}
마지막으로 αopti,βopti,γopti\alpha_{opti}, \beta_{opti}, \gamma_{opti} 값을 구하려면 SSE가 최소가 되는 지점을 찾아 구하면 됩니다.
이를 Holt-winters 알고리듬이라고 하며 직접 구현해도 괜찮지만, 굳이 그럴 필요없이 statsmodels library를 이용하면 더 쉽게 구현이 가능합니다.
아래는 다음 시간의 CTR을 예측하는 python code example을 보여줍니다.
import pandas as pd from statsmodels.tsa.api import ExponentialSmoothing SELECT_QUERY = '''...read dataset query...''' dataset = pd.read_sql(SELECT_QUERY, db) dataset.index = dataset.local_time dataset = dataset.reindex(pd.DatetimeIndex(start=dataset.index[0], end=last_date, freq='D')) dataset.fillna(0., inplace=True) fit_exp = ExponentialSmoothing(dataset.expose_cnt, seasonal_periods=7, trend=None, seasonal='add').fit(use_boxcox=False) # last_date forecast_exp = fit_exp.forecast(1) fit_click = ExponentialSmoothing(dataset.click_cnt, seasonal_periods=7, trend=None, seasonal='add').fit(use_boxcox=False) # last_date forecast_click = fit_click.forecast(1) forecast_ctr = forecast_click.values[0]/forecast_exp.values[0]
Python
복사
다음 시간에는 time-series 데이터 예측에서 많이 사용되는 ARIMA에 대해서 알아보도록 하겠습니다~
작성자
관련된 글 더 보기