순환 신경망 (LSTM) 활용 주가 예측

시계열 데이터 예측에 좋은 성능을 낸다는 순환 신경망을 통해 제가 현재 보유하고 있는 내츄럴엔도텍 주식에 대한 예측을 해보고자 합니다. 내츄럴엔도텍은 한 때 백수오로 알려진 업체이며 최근 홈쇼핑 판매 개시로 많은 관심을 받고 있습니다.

 LSTM이란…

순환 신경망은 보통 RNN(Recurrent Neural Network)라고 하는데 그레디언트 소실(Gradient Vanishing Problem)을 해결하고자 메모리를 도입한 LSTM(Long-Short Term Memory)을 주로 이용합니다.

LSTM은 시계열 데이터 처리에 있어서는 ARIMA 등 기존 알고리즘보다 좋은 성능을 내는 것으로 알려져 있습니다. LSTM에 대한 자세한 내용은 여기를 참조하시기 바랍니다. 순환 신경망의 놀라운 효과 라는 안드레 카파시 블로그 글 (영문)도 참고하시기 바랍니다. 순환 신경망으로 세익스피어 글도 짓고 자바 프로그래밍도 합니다.

LSTM 소개에 대한 이미지 검색결과

기존 MLP 신경망은 은닉층의 노드값을 계산할 때 입력에 가중치를 곱해서 은닉층의 노드값(상태)값을 업데이트 합니다. 그러나 순환 신경망은 그와 달리 은닉층의 노드값을 계산할 때 이전 히든(hidden) 노드에 대한 상태값과 입력을 모두 활용합니다. (아래 수식 참조)

Alt text

 

 

이런 방법으로 은닉층 상태를 업데이트 하기에 시계열 데이터에서의 패턴 변화를 감지할 수 있게 됩니다. 또한 LSTM은 순환신경망에 메모리까지를 가지고 있어 과거 시계열 데이터의 패턴 변화를 더 잘 잡아내는 특징을 가지고 있습니다.

좀 더 자세히 설명을 드리면 LSTM은 메모리가 있으며 메모리 입출력 컨트롤을 위한 소자(논리적인 장치)가 있는데 게이트(gate)라고 합니다. 게이트에는 입력(input), 출력(output) 게이트 그리고 망각(forget) 게이트가 있습니다.

LSTM 게이트에 대한 이미지 검색결과

LSTM을 학습하는 방법은 조금 복잡합니다. 기본적으로는 BPTT (Backpropagation Through Time) 을 사용합니다. 알고리즘은 BP와 유사하지만 순환 신경망에서는 시계열 데이터를 다루다보니 그리고 은닉층이 이전 은닉층 상태값까지 고려하다보니 그로 인해 조금은 복잡합니다. 순환 신경망 그래프 안에 네트워크가 연결된 구조를 펼쳐(unfold) 오차에 준한만큼 역으로 따라가며 전파하여 가중치를 학습합니다. 자세한 내용은 밑바닥부터 시작하는 딥너링이라는 책을 한번 읽어보시면 좋을 듯 합니다. 또는 Graphically Determining Backpropagation Equations 블로그 자료를 참고하시길 바랍니다.

 학습 데이터

LSTM 학습에 사용한 데이터로는 아래와 같은 형태로 저장된 csv 포맷을 읽어서 처리했습니다(다운로드:  A168330) 미리 아래와 같은 포맷으로 데이터를 저장해두고 나서 학습한 것입니다. 그리고 간단히 종가(Close) 데이터만을 이용해서 학습했습니다.

Date Open High Low Close Volume
20170816 27250 32450 27100 31500 3341469
20170814 25700 26800 24400 26750 1384477
20170811 25300 25750 24050 24950 2019038

 케라스 활용 LSTM 구현

LSTM을 파이썬으로 돌리는 방법은 여러 가지가 있지만 많이 사용되는 케라스(Keras) 라이브러리를 이용했습니다. 케라스는 텐서플로우를 기반으로 쉽게 사용할 수 있도록 하기 위한 일종의 래핑(wrapping) 라이브러리 입니다.

import os
import pandas as pd
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
import matplotlib.pyplot as plt
import math
from sklearn.metrics import mean_squared_error

look_back = 1
def create_dataset(dataset, look_back=1):
    dataX, dataY = [], []
    for i in range(len(dataset)-look_back-1):
        a = dataset[i:(i + look_back)]
        dataX.append(a)
        dataY.append(dataset[i + look_back])
    return np.array(dataX), np.array(dataY)

# file loader
sydtpath = "D:sydt"
naturalEndoTekCode = "A168330"
fullpath = sydtpath + os.path.sep + naturalEndoTekCode + '.csv'
pandf = pd.read_csv(fullpath, index_col="Date")

# convert nparray
nparr = pandf['Close'].values[::-1]
nparr.astype('float32')
print(nparr)

# normalization
scaler = MinMaxScaler(feature_range=(0, 1))
nptf = scaler.fit_transform(nparr)

# split train, test
train_size = int(len(nptf) * 0.9)
test_size = len(nptf) - train_size
train, test = nptf[0:train_size], nptf[train_size:len(nptf)]
print(len(train), len(test))

# create dataset for learning
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)

# reshape input to be [samples, time steps, features]
trainX = np.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1]))

# simple lstm network learning
model = Sequential()
model.add(LSTM(4, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=100, batch_size=1, verbose=2)

# make prediction
testPredict = model.predict(testX)
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform(testY)
testScore = math.sqrt(mean_squared_error(testY, testPredict))
print('Train Score: %.2f RMSE' % testScore)

# predict last value (or tomorrow?)
lastX = nptf[-1]
lastX = np.reshape(lastX, (1, 1, 1))
lastY = model.predict(lastX)
lastY = scaler.inverse_transform(lastY)
print('Predict the Close value of final day: %d' % lastY)  # 데이터 입력 마지막 다음날 종가 예측

# plot
plt.plot(testPredict)
plt.plot(testY)
plt.show()

결과 화면

아래 차트 오른쪽 부분이 내츄럴엔도텍이 최근(2017년 8월) 홈쇼핑 판매 개시로 주가가 오르고 있는 부분입니다. 실제 주가(파란색)와 예측 주가(노란색)로 출력되어 있습니다. 예측은 현재일 (1일)을 이용해서 다음날 (1일)을 예측합니다. 마지막 날 예측이 어긋나는게 아쉽습니다

stocksLSTM2

위 소스에 대해 문의가 있거나 틀린 점, 보완할 점이 있으면 아래 댓글 남겨주시면 감사하겠습니다. 그리고 위 소스 내용은 아래 사이트(Machine Learning Mastery) 자료를 참고해서 개발한 것입니다.
Machine Learning Mastery

참고

순환 신경망 (LSTM) 활용 주가 예측”의 25개의 생각

  1. 안녕하십니까? 좋은 게시글 올려주신점 감사합니다. 궁금한 점이 있어 이렇게 댓글을 남깁니다.
    시계열데이터 학습에는 문제가 없지만,
    저는 가중치를 추출하여 어떤 시뮬레이션을 진행하고 싶습니다.
    가중치 추출 방법에 대해서 댓글달아주시면 정말 감사하겠습니다.

    좋아요

  2. # convert nparray
    nparr = pandf[‘Close’].values[::-1]
    nparr.astype(‘float32’)
    print(nparr)
    이 부분은 왜 하는건가요?
    array로 바꿔주는 것 같은데 저는 close에서 key error가 나는데 어떻게 해결해야하나요
    pandf[‘Close’].values[::-1]이게 무슨뜻인지 잘 모르겠네요

    좋아요

    1. pandas 에서 np array로 변환을 하면서 마지막 -1 은 배열 순서를 역순으로 조정하고자 하는 것입니다. 가령 [1, 2, 3] -> [3, 2, 1] 이런식입니다.

      좋아요

  3. 포스트 잘 봤습니다
    코드에 대해 궁금 하게 있는데요
    내일 치를 예측 한다고 나온 수가 내일 수치가 아니라 전날 수치 아닌가요?
    아무리 코드를 돌려봐도 앞을 예측 하는것이 아니라 예전을 보고 있는거 같아서 여쭈어 봅니다.

    좋아요

    1. 안녕하세요, LSTM 학습에 사용된 X 값과 Y 값을 보시면 잘 분석해보시면 확인 가능합니다. create_dataset 함수 부분
      위 예제에서 사용된 LSTM도 결국 regression 을 위한 코드라 결국 이전 값들과의 연관성은 있습니다. LSTM 회귀는 ARIMA 와 같은 다이나믹한 예측을 만들어 내지는 못합니다.

      좋아요

  4. 높은 분포 편향을 가지면 직전값을 그대로 답습하여 토하는 문제가 있습니다. 그래서 하이퍼 파라미터의 탐색과 과적합, 과소적합여부를 따져보아야 합니다.

    좋아요

    1. 사이트 포팅하면서 날라갔네요. 위 데이터는 거래 정지된 종목이기도 해서 의미도 없어요구. ㅡㅡ 하지만 다행히 대부분 다른 곳에서 구할 수 종목 데이터 포맷하고 유사합니다…

      좋아요

      1. file loader 부분에 D:sydt 코드는 무슨 뜻인지 알 수 있을까요? 그리고 A168330은 종목 코드인가요,,?
        제가 1학년인데 참고해보면서 공부하고 싶어 간단한 내용인데도 염치 없지만 여쭤봅니다 죄송합니다 ㅠㅠ

        좋아요

      2. 네 이해했습니다 감사합니다!! 그럼 이 코드는
        1).현재일의 종가를 기반으로 내일의 종가를 예측하게 되는건가요?
        2). 외국 논문을 보면 보통 등/락으로 이분해서 등락을 맞추는 분류기가 많던데, 회귀로 하면 모델 평가에 있어서 어려움은 없나요?
        3). 내일에 대한 데이터는 아무것도 없는데 (제가 이해한 바로는요) 예측이 가능한 건가요? 제가 현재 XGBoosting정도까지 배운 상태인데, 학습 데이터를 통해 X들과 Y의 관계를 학습하고 테스트 데이터 (X들에 대한 정보)가 주어지면 Y를 예측하는 상황만 봐서요. 내일에 대한 정보는 아무것도 주어지지 않을텐데 예측을 할 수 있는 것은 LSTM이 속하는 NN의 장점인건가요?
        다짜고짜 말도 안되는 질문 여쭤봐서 정말 죄송합니다. 데이터사이언스학과 학생인데 최근 금융공학에 너무 관심이 생겨서 접점을 알아보다가 이런 흥미로운 정보를 보고 궁금한게 너무 많이 생긴 바람에 ㅠㅠㅠ 염치 불구하고 여쭤봅니다!

        좋아요

      3. 1) 현재 포함 과거 몇일 데이터로 내일 종가를 예측하는거죠
        2) 주식은 랜덤 패턴과 가까워서 회귀로 하면 평균값으로 예측 수렴하는 경향이 있습니다
        3) LSTM이 시계열 예측하는데 사용됩니다 잘되는건 아닙니다 아직은 랜덤과 같은 패턴을 예측하긴 어려워요 사실상 거의 55프로 정도이며 실제 거래 적용하긴 수수료나 체결 문제도 있고 해서 한계가 있습니다
        그래도 화이팅입니다 ㅎ

        좋아요

  5. 답변 너무너무 감사합니다! 그렇다면 모델의 features는 그냥 일반적인 close open low high 정도가 되는 것인가요? close가 target variable 이구요! 만약 그렇다면 또 궁금한게 하나 더 있긴 한데,, 이건 제 이해 부족 문제같아서 일단 조금 더 공부해보고 오겠습니다 ㅎㅎ ㅠㅠ

    좋아요

    1. 아 이번에 tbacking님 코드를 시작으로 금융쪽 공부 시작한거라서요 ㅎㅎ 코드 보니까 tbacking님은 그 네 개 일반적인 features 중 close만 이용해서 패턴형성? 식으로 LSTM 이용하신거죠??!

      좋아요

  6. 안녕하세요! 제가 갖고있는 데이터에 적용해서 코드를 실행해보았는데 그래프가 이상하게 그려져서요 ㅠㅠ 그냥 하루씩 예측하는게 아니라 true value가 하루씩 밀려서 나오는 꼴로 그려집니다. 염치 불구하고 개인적으로 코드 한 번만 봐주실 수 없을까요? 정말 바쁘실텐데 부탁이라도 죄송합니다.

    좋아요

    1. 신경망이 원래 좀 학습이 안되긴 합니다…( 너무 많은 데이터로 학습하고 그 데이터를 담을 파라미터가 충분치 않으면 거의 그대로 리턴할 수 있습니다)

      우선 간단한 신경망으로 해보세요
      데이터도 줄이면서..

      원인 분석을 해보심이 좋을 듯… lifegear.gg@g메일

      좋아요

  7. 전 데이터 엔지니어입니다. 지금까진 주로 전처리를 해왔는데, 머신러닝과 딥러닝을 배우고 있습니다. 회사와 달리 주식데이터는 오픈 데이타이어서 직접 종목추천 시스템을 만들려구 준비하는 단계입니다. 많은 경험을 공유해 주셔서 감사드립니다. 지금은 강화학습 매매 모듈을 살펴보고 있는데, 말씀하시데로 게임의 강화와 좀 다르고 결국 전통적인 트렌트 분석이 자동매매에는 맞는것이 아니가 싶습니다. 앞으로도 같은 관심사에 의견을 같이 공유할수 있으면 좋겠습니다.

    좋아요

    1. 감사합니다. 머신러닝 기반이나 강화학습을 이용한다 하더라도 50프로 확률 이상이면 해볼만하지 않을까 합니다만 수수료 등을 고려하니 결론부터 이야기하면 전통적인 방법이든 머신러닝 기반이든 쉽지 않았습니다. 그래도 좋은 결과 있으시길 바랍니다 어쩌면 시스템 트레이딩을 하고자 하는 모든 이의 희망 아닐까 생각합니다

      좋아요

피승현 에 답글 남기기 응답 취소

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중