ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 머신 러닝으로 금 시세를 예측 해보자 feat. ARIMA
    모델 구축 2020. 3. 31. 10:34

    0 - 1. 시계열 데이터란 무엇인가?

    0 -2. Time series model 이란 무엇인가?

    1. ARIMA에 대한 간단한 설명

    2. 금 값 데이터의 분석

    3. ARIMA모델의 구축

    4. 모델의 평가

    5. 모델의 활용

    0-1. 시계열 데이터란 무엇인가?

    시계열 데이터는 일정한 시간 간격으로 출력된 데이터이다. 우리가 돈을 벌기 위해 관심을 가지는 주식, 유가, 채권 금리, 집 값 등 모든 것이 시계열 데이터이다.

    시계열 데이터는 추세-주기, 계절성, 잔차의 합 혹은 곱으로 볼 수가 있다. 추세(trend)는 장기적으로 증가 혹은 감소를 설명하는 부분이며, 계절성(seasonality)은 특정 기간(일별, 분기별, 10년 별 등) 마다 나타나는 패턴을 설명하는 부분이다. 주기(cycle)는 계절성과 비슷하게 비슷한 패턴을 보이는 것을 설명하는 부분이나, 계절성과는 다르게 고정된 빈도가 아니다. 밑의 그림은 호주의 월 별 당뇨약 판매량과 STL을 이용하여 원데이터를 추세와 계절성, 잔차로 분리한 예시다.

    호주의 월별 당뇨약 판매량
    당뇨병 치료약 판매량(Observed)의 추세(Trend)와 계절성(Seasonal)과 잔차(Residual)로의 분리

    위의 예시는 추세와 계절성이 명확히 나타난다. 우리는 위의 분해만을 통해서도 2009년의 당뇨병 약의 판매량을 예측을 할 수 있을 것이다.

     하지만 명확한 추세와 계절성을 가지지 않는 주식이나 금값, 유가 등은 어떻게 예측할 수 있을까? 이러한 문제를 해결하기 위한 하나의 접근법이 Time Seires Model이다.

    0-2. 시계열 모델(Time series model)이란 무엇인가?

     시계열 데이터를 분석하는 방법은 크게 두 가지 접근법을 생각할 수 있다. Explanatory models ( 혹은 Associative Model)과 Time Series Model이다(물론 두 가지를 혼합해서 사용하는 모델도 있다).

    "호주의 월별 당뇨병약의 판매량"을 예로 들어 보자. 우리는 약의 월 판매량(독립변수)을 예측하고 분석하기 위해서 약의 판매량과 상관관계가 있다고 추정되는 '총인구수', '연령 구성', '달 평균 기온' 등을 종속 변수로 하는 모델을 구축할 수 있을 것이다. 이러한 모델을 Explanatory Model이라고 부른다.

    이에 비해 Time Series Model 은 시간을 종속 변수로 독립 변수를 설명하는 모델이다. 예를 들어 각 년도의 판매량이 2001년: 10개, 2002년: 12개, 2003년:15개, 2004년:17개 일 경우 2005년의 판매량은 일정 확률로 19~22개이다는 추론을 내리는 모델이다.

     대표적인 시계열 모델인 ARIMA, Prophet, LSTM이 있고 이 모델들의 간단한 설명과 금 시세를 예시로 모델 구축과 예측을 해보도록 하겠다.

    1. ARIMA에 대한 간단한 설명

    ARIMA(AutoRegressive Integrated Moving Average)는 자기 회귀 모델(AR)과 이동 평균 모델(MA)과 데이터의 정상성을 확보하기 위한 차분(I)을 합친 모델이다. ARIMA모델은 AR , I, MA의 차수를 정해야 하는데 이는 ARIMA(p, d, q)로 나타낸다. AR의 차수는 p, I의 차수는 d, MA의 차수는 q로 표시한다. ARIMA(1,1,0) 일 경우 AR(1)와 I(1)를 합친 모델이라는 의미이다.

     ARIMA모델은 시계열 데이터의 정상성(stationary)을 전제 조건으로 하고 있다. 시계열 데이터에서 불리는 정상성이란 시계열 데이터의 특성이 시간에 의존하지 않는다는 것이다. 그 조건을 만족하기 위해서는 시간에 따른 평균과 분산, 특정 시차 간의 공분산이 시간에 따라 변하지 않는 것이다.

    • 자기 회귀 모델 (AR)
      현재의 데이터를 과거의 데이터의 선형 결합으로 설명한다. 오늘의 값은 어제의 값 자체에 영향을 받는다. 만약 계수가 양수이면 어제의 값이 큰 값이면 오늘의 값도 큰 값을 가지며, 음수이면 어제의 값이 큰 값이면 오늘의 값은 작은 값이 된다. AR모델의 식의 하기와 같다.
      자기 회기 모델

      yt: t시점에서의 관측값

      yt-1 : t-1 시점에서의 관측값

      c : 상수항

      φ : 자기 회귀 모델 계수

      εt: 에러항, 백색 잡음



      자기 회귀 모델은 AR(p)로 표현하며, p는 차수를 나타낸다.

      AR(1) 모델의 경우:

      yt = c + φ 1yt-1 + εt

      −1 <ϕ1 <1

      AR(2) 모델의 경우:

      yt = c + φ 1yt-1 + φ 2yt-2 + εt

      −1 <ϕ2 <1

      ϕ1+ϕ2 <1, ϕ2−ϕ1 <1.


      예시로 상수항이 있는 AR(1)을 그려 보자.

      import numpy as np
      import matplotlib.pyplot as plt
      ar_process = []
      y = 140
      coff = 0.3
      const = 100
      for i in range(300):
       error = np.random.randn()
       y = const + y * coff + error
       ar_process.append(y)
      print(const / (1 - coff))
      plt.plot(ar_process)
      AR(1) yt = 100 + 0.3yt-1 + e의 그래프

      그래프에서 볼 수 있듯이 일정한 평균(c/(1-φ1)) 과 일정한 크기의 분산(화이트 노이즈의 분산)의 값을 가진 정상 시계열임을 알 수 있다.

    • 이동 평균 모델(MA)
      현재의 데이터를 과거의 데이터의 오차 항의 선형 결합으로 설명한다. 오늘의 값은 어제의 값의 오 차 항에 영향을 받는다. 계수가 양수이면, 어제의 값이 상승하는 추세이면, 오늘의 값도 상승하는 추세이다. 반대로 음수이면, 어제의 값이 상승하는 추세이면, 오늘의 값은 하강한다. MA모델의 식은 하기와 같다.
      이동 평균 모델

      yt : t시점에서의 관측값

      c : 상수항

      θ : 자기 회귀 모델 계수

      εt : t시점에서의 에러항, 백색 잡음

      εt-1 : t-1 시점에서의 에러항, 백색 잡음

      이동평균 모델은 MA(q)로 표현하며, 자기 회귀 모델과 같이 q는 차수를 이야기한다.

      간단한 MA(1)을 그려 보자.

      ma_process = []
      coff = 0.3
      const = 100
      error = np.random.randn()
      for i in range(300):
       ex_error = error
       error = np.random.randn()
       y = const + coff * ex_error + error
       ma_process.append(y)
      plt.plot(ma_process)
      MA(1) yt = 100 + 0.3et-1 + et의 그래프

      일정한 값(c)을 중심으로 진동하는 정상 시계열 임을 확인할 수 있다.

    • 차분(I)
      그래프를 그려 확인해 본 바와 같이 AR과 MA 모델은 정상 시계열을 전제로 한 모델이다. 차분은 정상 시계열이 아닌 정상화시키는 방법 중 하나이다. 1차 차분은 단순히 현재시간과 그 전 시간의 차이다. 즉 속도이다. 예를 들어 추세가 있어 증가 혹은 감소가 있는 시계열은 정상성이지 않지만 그 증가 속도, 감소 속도가 일정하다면 1차 차분을 통해서 정상화시킬 수 있다. 2차 차분은 속도와 속도의 차이이므로 가속도로 생각해도 좋다.
      1 차 차분
      2차 차분

     

    2. 금 시세 데이터의 분석

     2000년부터의 금 시세를 살펴보자.

    2000년 부터 2020년 3월말 까지의 금 시세프 그래프 - 표

    대체적으로 상승하는 추세가 있는 것을 확인할 수 있다(2000년부터 금을 사서 2020년까지 가지고 있었으면 무려 7배로!... 대략 연 10%의 이율이다!).

    def plot_rolling(data, interval):
     rolmean = data.rolling(interval).mean()
     rolstd = data.rolling(interval).std()
     #Plot rolling statistics:
     plt.figure(figsize=(10, 6))
     plt.xlabel('Date')
     orig = plt.plot(data, color='blue',label='Original')
     mean = plt.plot(rolmean, color='red', label='Rolling Mean')
     std = plt.plot(rolstd, color='black', label = 'Rolling Std')
     plt.legend(loc='best')
     plt.show()
    plot_rolling(gold_price_series, 180)

     위에서 설명했듯이 ARIMA모델은 정상성을 전제로 하는 모델이므로 정상성을 확인해야 한다. 추세가 있다는 것은 평균이 시간에 따라 변한다는 것이므로 정상 시계열로 볼 수 없다. 그러면 정상 시계 열화 하기 위해 1차 차분을 해보자.

    금 시세 이동 평균, 이동 표준편차 그래프
    1차 차분 시계열 그래프

    일단 0을 중심으로 진동 운동을 하는 모습을 보이고 있지만 진폭(분산)은 일정해 보이지 않는다. 정량적으로 정상성을 알 수 있는 방법은 없을까? 이럴 때 사용되는 몇 가지 통계적 방법이 있으나, 그중 가장 널리 사용되는 방법인 Augmented Dickey-Fuller (ADF) 검정법으로 테스트해 보자. (ADF검정에 대한 자세한 내용은 「데이터 사이언스 스쿨」를 참고)

     

    파이썬으로 ADF검정을 해 보자.

    from statsmodels.tsa.stattools import adfuller
    y = gold_price_series['price(USD)']
    y_1diff = gold_price_series.diff().dropna()['price(USD)']
    result = adfuller(y)
    print(f'원 데이터 ADF Statistic: {result[0]:.3f}')
    print(f'원 데이터 p-value: {result[1]:.3f}')
    result = adfuller(y_1diff)
    print(f'1차 차분 ADF Statistic: {result[0]:.3f}')
    print(f'1차 차분 p-value: {result[1]:.3f}')
    

    차분을 하지 않은 원 데이터는 p-value가 유의 수준인 0.05보다 크므로 정상 시계열로 볼 수 없다.

    ADF 검정 결과

    이에 비해 1차 차분의 데이터는 p-value가 유의 수준보다 작으므로 정상 시계열로 볼 수 있다.

    이로서 차분(d)의 차수는 1인 ARIMA(p, 1, q)의 모델 구축이 필요하다는 것을 알 수 있다.

    3.ARIMA모델의 구축

    이제 적절한 AR(p)와 MA(q)를 정해야 하는데, 일반적으로는 ACF (AutoCorrelation Function)와 PACF (Partial AutoCorrelation Function) 그래프를 이용해서 정한다. 이 포스팅에서는 AIC를 기준으로 최적의 차수를 정하도록 하겠다.

    def my_auto_arima(data, order,sort = 'AIC'):
     order_list = []
     aic_list = []
     bic_lsit = []
     for p in range(order[0]):
     for d in range(order[1]):
     for q in range(order[2]):
     model = ARIMA(data, order=(p,d,q))
     try:
     model_fit = model.fit()
     c_order = f'p{p} d{d} q{q}'
     aic = model_fit.aic
     bic = model_fit.bic
     order_list.append(c_order)
     aic_list.append(aic)
     bic_list.append(bic)
     except:
     pass
     result_df = pd.DataFrame(list(zip(order_list, aic_list)),columns=['order','AIC'])
     result_df.sort_values(sort, inplace=True)
     return result_df
    my_auto_arima(gold_price_series,[3,3,3])

    ARIMA모델 fitting 결과

    ARIMA(2,1,2)가 최적의 모델임을 확인할 수 있다. 실제로 모델의 fitting결과를 확인해 보자. 일단, 금 시세는

    y't = 0.2620(1-0.7617+0.9486) + 0.7617 y't-1 - 0.9486 y't-2 + et - 0.7777et-1 +0.9608et-2를 따르는 ARIMA모델임을 확인할 수 있다.

    모델의 Fitting 결과를 시계열 그래프로 확인해 보자.

    model = ARIMA(gold_price_series, (2,1,2))
    model_fit = model.fit()
    print(model_fit.summary())
    model_fit.plot_predict()
    plt.show()

    금시세 실측값과 ARIMA모델의 예측값

    얼핏 예측과 실측값이 완전히 겹치는 것으로 보인다. 그래프를 확대하여 자세히 알아보자.

    model_fit.plot_predict(start=datetime.datetime(2020,1,3))
    plt.show()

    금시세 실측값과 ARIMA모델의 예측값(확대)

    모델의 예측값이 단순히 실제값을 shifting 해 놓은 것과 거의 같은 모양을 나타내는 것을 알 수 있다. 이는 모델이 실제의 값(과거)을 바탕으로 바로 다음의 값(현재)을 예측하는데, 거의 전의 값을 그대로 사용하는 게 그나마 실측치와 비슷한 결과를 만든다고 모델이 추론한 것이다.


     그럼 미지의 데이터에 대해서는 어떻게 예측하는지 알아보자.

     2019년까지의 데이터로 모델을 fitting 하고 2020년 3월까지의 값을 예측해 보도록 하자.

    train, test = gold_price_series.loc[:datetime.datetime(2019,12,31),:], gold_price_series.loc[datetime.datetime(2019,12,31):,:]
    model = ARIMA(train,(2,1,2))
    model_fit = model.fit()
    full_forecast = model_fit.forecast(steps=test.shape[0])
    forecast = pd.DataFrame(full_forecast[0], index=test.index, columns=test.columns)
    plt.plot(train.loc[datetime.datetime(2018,12,31):,:])
    plt.plot(test)
    plt.plot(forecast)

    ARIMA의 금 시세 전망

    초록색의 예측선을 보면 알 수 있듯이 마지막 값을 거의 그대로 사용하고 있는 것을 알 수 있다. 얼핏 봐서는 금 시세 예측에는 사용이 어려운 모델로 보인다. 

    4. 모델의 평가

    5. 모델의 활용

     모델의 정량적인 성능이 어떤지, 시세 예측에 활용이 가능한지는 추후 Prophet, LSTM 모델 포스팅 후 같은 기준으로 비교 평가를 하도록 하겠다.

     

     

    참고 문헌

    https://otexts.com/fppkr/index.html

    https://www.machinelearningplus.com/time-series/arima-model-time-series-forecasting-python/

    댓글

Designed by Tistory.