머신러닝

증권가격 예측(Stock Proce) RNN 파이선 코드

coding art 2019. 4. 8. 10:54
728x90

 

파이선 코딩을 배우는 초보자도 머신 러닝에 독학으로 한번 도전해 보자.

머신 러닝을 배우려는 파이선 코딩 초보자들이 가지게 될 확률이 높은 의문점들을

하나하나 찾아내어 실제 풀어보고 결과를 확인해볼 수 있는 머신 러닝!

인터넷 교보문고에서 450페이지19900원에 판매중입니다.

 

________________________________________________________________________________________________________________________

 

대단히 불규칙해 보이는 데이터를 바탕으로 앞으로의 증권 가격(Stock Price) 예측을 위한 Many To one RNN 모델을 코딩해 보자. RNN 예측 머신 러닝 모델은 미세먼지 예측이라든지 인구분포 예측과 같은 다양한 응용이 있는 흥미로운 모델이다.

인터넷 검색에서 Scikit-learn 라이브러리를 사용하는 많은 예제 데이터를 찾을 수 있으나 여기서는 TensorFlow Numpy를 사용하는 예제를 다루어 보도록 하겠다. 이 예제에서는 증권가격 학습 및 테스트를 위한 엑셀 데이터 파일을 같은 폴더 안에 두고 사용함에 유의하자.

이 코드에서는 pandas 라이브러리를 사용하지 않고 numpy를 그대로 쓰고 있으므로 읽어 들인 증권 데이터를 거꾸로 재배열 하는 과정을 체크해 보자. 사용하는 np 명령은 간단하게 xy[::-1] 이다.

거꾸로 재배열 후 함수 MiniMaxScaler를 사용하여 데이터를 0.01.0 사이로 normalization 시킨다. 예제코드에서 읽어 들이는 엑셀 csv 데이터는 아래와 같이 5개의 컬럼으로 이루어진다.

함수 내부를 관찰해 보자. np.max(data,0) 명령에서 dataarray이며, 0axis=0을 뜻하며 아래 방향 즉 컬럼 방향으로 최대값을 찾는다는 의미이다. 즉 컬럼 별로 normalization 이 이루어진다.

 

이 증권가격 데이터 구조는 5개의 컬럼으로 이루어지는 각 열(row) 5개 데이터이므로 data_dim = 5 로 두고 7개씩의 열을 sequence로 즉 seq_length = 7 로 둔다. 따라서 이 7개의 데이터 중 종가를 기준으로 8번째에 해당하는 종가를 Many To One 형태로 학습과 테스트를 하도록 한다. row 값을 +1만큼 증가시키면서 데이터가 끝날 때 까지 Loop를 실행하여 Session에서 batch job을 위한 dataX dataY 파일을 구성한다.

학습과 테스트를 위한 데이터 사이즈를 아래와 같이 7:3으로 구성해 보자.

Session에서 사용할 feed_dict placeholdershape 을 설정하자. cell BasicLSTMCell 을 사용하여 dynamic.rnn 에 제공한다. 아울러 이 예제에서는 hidden_dim = 10 으로 설정하여 각 셀에서 10개의 출력 값을 얻을 수 있지만 마지막 7번째 셀의 출력만을 fully connected 에 입력하여 하나의 하나의 출력 값 즉 그 다음 종가를 학습하도록 한다.

Softmax 와 유사한 Fullyconnected를 사용하지만 최종 출력 데이터 값이 하나이기때문에 cost(loss) 함수는 간단한 최소제곱법을 사용하기로 하자. optimizer는 효율적인 AdamOptimizer를 사용한다. 학습이 아닌 테스트 과정에서 사용할 루틴을 대상으로 Computational Graph를 설정하자. 즉 테스트 True targets, 테스트 예측 값 predictions 이며 학습 때와 마찬가지로 최소제곱법을 사용하여 테스트 한다.

Session에서 학습을 진행하고 이어서 테스트를 시행한다. 그 방법은 teㄴㅅㅌ 를 사용하여 Y_pred fully-connected 루틴을 사용하여 test_predict를 계산하는 것이다. 이어서 testY test_predict를 사용하여 최소제곱법에 의해서 cost 함수값 구하듯이 rmse 값을 계산한다.

 

계산 결과가 구분이 안갈 정도로 정확하다. 이 예제에서 관심을 가져야 할 점은 train_size를 어느 정도로 가져가야 하는 문제인데 0.7에서 단계 별로 0.1 수준까지 각자 조정해 보기 바란다. 학습 크기 비율이 너무 작아지면 예측 결과가 무너지는 결과를 낳게 된다. 다음 그래프를 참조하자.


이 예제를 돌려 보기 위한 코드는 아래 에서 다운받아 사용하기 바란다. 단 엑셀 데이터 파일과 파이선 코드를 같은 폴더에 두도록 한다. 아울러 파이선 코드 다운 로드 시에 indentation 훼손 여부를 반드시 확인해 보기 바란다.

 

증권가격 예측을 위한 엑셀 csv 데이타

 

 

data-02-stock_daily.csv
0.04MB

증권가격 예측 파이선 코드: 복사 후 반드시 indentation 체크하세요

#lab-12-5-rnn_stock_prediction.py from Sung Kim, YouTube

'''
This script shows how to predict stock prices using a basic RNN
'''
import tensorflow as tf
import numpy as np
import matplotlib
import os

tf.reset_default_graph()
tf.set_random_seed(777)  # reproducibility

if "DISPLAY" not in os.environ:
    # remove Travis CI Error
    matplotlib.use('Agg')

import matplotlib.pyplot as plt


def MinMaxScaler(data):
    ''' Min Max Normalization

    Parameters
    ----------
    data : numpy.ndarray
        input data to be normalized
        shape: [Batch size, dimension]

    Returns
    ----------
    data : numpy.ndarry
        normalized data
        shape: [Batch size, dimension]

    References
    ----------
    .. [1] http://sebastianraschka.com/Articles/2014_about_feature_scaling.html

    '''
    numerator = data - np.min(data, 0)
    denominator = np.max(data, 0) - np.min(data, 0)
    # noise term prevents the zero division
    return numerator / (denominator + 1e-7)


# train Parameters
seq_length = 7
data_dim = 5
hidden_dim = 10
output_dim = 1
learning_rate = 0.01
iterations = 500

# Open, High, Low, Volume, Close
xy = np.loadtxt('data-02-stock_daily.csv', delimiter=',')
xy = xy[::-1]  # reverse order (chronically ordered)
xy = MinMaxScaler(xy)
x = xy
y = xy[:, [-1]]  # Close as label

# build a dataset
dataX = []
dataY = []
for i in range(0, len(y) - seq_length):
    _x = x[i:i + seq_length]
    _y = y[i + seq_length]  # Next close price
    print(_x, "->", _y)
    dataX.append(_x)
    dataY.append(_y)

# train/test split
train_size = int(len(dataY) * 0.7)
test_size = len(dataY) - train_size
trainX, testX = np.array(dataX[0:train_size]), np.array(
    dataX[train_size:len(dataX)])
trainY, testY = np.array(dataY[0:train_size]), np.array(
    dataY[train_size:len(dataY)])

# input place holders
X = tf.placeholder(tf.float32, [None, seq_length, data_dim])
Y = tf.placeholder(tf.float32, [None, 1])

# build a LSTM network
cell = tf.contrib.rnn.BasicLSTMCell(
    num_units=hidden_dim, state_is_tuple=True, activation=tf.tanh)
outputs, _states = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)
Y_pred = tf.contrib.layers.fully_connected(
    outputs[:, -1], output_dim, activation_fn=None)  # We use the last cell's output

# cost/loss
loss = tf.reduce_sum(tf.square(Y_pred - Y))  # sum of the squares
# optimizer
optimizer = tf.train.AdamOptimizer(learning_rate)
train = optimizer.minimize(loss)

# RMSE
targets = tf.placeholder(tf.float32, [None, 1])
predictions = tf.placeholder(tf.float32, [None, 1])
rmse = tf.sqrt(tf.reduce_mean(tf.square(targets - predictions)))

with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)

    # Training step
    for i in range(iterations):
        _, step_loss = sess.run([train, loss], feed_dict={
                                X: trainX, Y: trainY})
        print("[step: {}] loss: {}".format(i, step_loss))

    # Test step
    test_predict = sess.run(Y_pred, feed_dict={X: testX})
    rmse_val = sess.run(rmse, feed_dict={
                    targets: testY, predictions: test_predict})
    print("RMSE: {}".format(rmse_val))

    # Plot predictions
    plt.plot(testY)
    plt.plot(test_predict)
    plt.xlabel("Time Period")
    plt.ylabel("Stock Price")
    plt.show()