ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 삼성 주식 예측(Lstm)
    Machine Learning/Tensorflow 2021. 3. 7. 22:55
    반응형

    주식데이터 다운로드 주소

    finance.yahoo.com/quote/005930.KS/history?p=005930.KS

     

    SamsungElec (005930.KS) Stock Historical Prices & Data - Yahoo Finance

    Discover historical prices for 005930.KS stock on Yahoo Finance. View daily, weekly or monthly format back to when SamsungElec stock was issued.

    finance.yahoo.com

    기본적인 라이브러리 입니다.

    import pandas as pd
    import numpy as np
    import tensorflow as tf
    from tensorflow.keras.callbacks import EarlyStopping
    import matplotlib.pyplot as plt

    Data Load

    samsung_csv = '005930.KS.csv'
    window_size = 7
    batch_size = 32
    shuffle_buffer = 60000
    
    samsung = pd.read_csv(samsung_csv)
    samsung = samsung.dropna(axis=0)
    
    # 컬럼선택을 Low를 하셔도 되고, 다른 데이터로 해도 무방합니다.
    samsung_times = pd.to_datetime(samsung.Date,format='%Y-%m-%d')
    samsung_series = samsung.Low
    samsung_series_copy = samsung.Low
    
    # array 변환
    samsung_series = np.asarray(samsung_series,dtype='float32')

    nomalization 진행

    # normalization 진행
    min_scale = np.min(samsung_series)
    max_scale = np.max(samsung_series)
    samsung_series -= min_scale
    samsung_series /= max_scale

    최소값을 빼주고, 최대값으로 나눠줘서 수치형 데이터를 정규화 해줍니다.

     

    Dataset을 tensor로 변환해서 사용합니다.

    이때 사용되는 함수는 coursera 강의의 tensorflow 자격증 강의에 나왔던 함수입니다.

     

    주석으로 따로 설명을 적어놨습니다. 참고바랍니다.

    # Dataset 구성 함수
    # 1차적으로 차원증가 후 텐서슬라이스에 매개변수로 전달
    # ex)7일 + 1일 = 8일의 데이터 생성 (7일은 학습데이터, 1일은 정답데이터로 사용됨), drop_remainder 파라미터는 예측할 학습데이터가 7개가 안되면 삭제해서 진행
    # flat_map을 이용해서 flat_map을 이용해서 8개로 생성
    # shuffle을 이용해서 무작위로 섞음
    # 마지막으로 7:1 (학습7,정답1)로 매핑진행
    # 마지막으로 배치사이즈만큼 다시한번 매핑진행
    # 참고사이트 : https://teddylee777.github.io/tensorflow/dataset-batch-window
    def windowed_dataset(series, window_size, batch_size, shuffle_buffer):
        series = tf.expand_dims(series, axis=-1)
        ds = tf.data.Dataset.from_tensor_slices(series)
        ds = ds.window(window_size + 1, shift=1, drop_remainder=True)
        ds = ds.flat_map(lambda w: w.batch(window_size + 1))
        ds = ds.shuffle(shuffle_buffer)
        ds = ds.map(lambda w: (w[:-1], w[1:]))
        return ds.batch(batch_size).prefetch(1)
    # 학습용데이터로 변환
    dataset = windowed_dataset(samsung_series, window_size, batch_size, shuffle_buffer)

    layer Create

    # LSTM or GRU
    # input_shape 는 [batch_size,1]만큼 들어갈 예정
    model = tf.keras.Sequential([
        tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(256,input_shape=[None,1],return_sequences=True)),
        tf.keras.layers.BatchNormalization(),
        tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(128,return_sequences=True)),
        tf.keras.layers.BatchNormalization(),
        tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)),
        tf.keras.layers.BatchNormalization(),
        tf.keras.layers.Dense(512,'relu'),
        tf.keras.layers.Dense(256,'relu'),
        tf.keras.layers.Dense(128,'relu'),
        tf.keras.layers.Dense(1)
    ])

    lstm은 기본적으로 정방향으로 계산이 됩니다.

    역방향으로도 계산을 진행시키면 더 정확한 연산이 가능하므로 bidirectional 메서드를 감싸줍니다.

     

    model compile

    # 시계열데이터라서 mse사용, optimizer는 adam으로 통일 metrics 또한 mse로 진행
    model.compile(loss='mse',optimizer='adam',metrics=['mse'])

    Learning rate schedule 과 earlystop을 이용해서

    learning rate는 epoch이 증가함에 따라서 작아지게 설정하고, earlystop을 이용해서 더이상 학습의 진척이 없을 경우

    중지하게 설정을 합니다.

    # learningrate 설정 진행, 점점 더 높아지게 설정
    # earlystopping 설정, 과적합 방지
    lr_schedule = tf.keras.callbacks.LearningRateScheduler(
        lambda epoch: 1e-8 * 10**(epoch / 20))
    earlystop = EarlyStopping(monitor = 'loss',mode='min',patience=10)

    model fit

    history = model.fit(dataset,epochs=150,callbacks=[lr_schedule,earlystop])

     

    model save

    # Calling `save('my_model.h5')` creates a h5 file `my_model.h5`.
    model.save("samsung.h5")
    
    # It can be used to reconstruct the model identically.
    samsung_model = tf.keras.models.load_model("samsung.h5")


    model predict(7일씩 데이터 입력 진행)

    # Window 사이즈 만큼 예측결과를 다시 Array로 반환
    predicts = []
    for time in range(len(samsung_series)-window_size):
        pred = np.array(samsung_series_copy[time : time + window_size])
        pred -= min_scale
        pred /= max_scale
        
        pred = pred.reshape(1,-1,1)
        
        predict = model.predict(pred)
        
        predict *= max_scale
        predict += min_scale
        
        predicts.append(predict[0][0])

    시각화 진행

    plt.figure(figsize=(12,8))
    plt.plot(samsung_times[2500:3000],predicts[2500:3000],color='red',label='Predict')
    plt.plot(samsung_times[2500:3000],samsung_series_copy[2500:3000],color='blue',label='Real')
    plt.legend(loc='center left')
    plt.show()

    plt.figure(figsize=(12,8))
    plt.plot(samsung_times[:len(samsung_series) - window_size],predicts[:len(samsung_series) - window_size],color='red',label='Predict')
    plt.plot(samsung_times[:len(samsung_series) - window_size],samsung_series_copy[:len(samsung_series) - window_size],color='blue',label='Real')
    plt.legend(loc='center left')
    plt.show()

    예측 함수 생성

    # 7일까지만 예측진행
    future_days = 7
    
    future_series = predicts[-window_size:]

    window_size는 위에서 7일로 정해놨고, predicts의 7일치 내용만을 이용하여,

    최근 7일치만 가지고 다시 새로운 7일을 예측하는 부분입니다.

    # 7일 예측씩 지속적으로 예측 진행
    def predict_days(future_days,future_series):
        
        futures = []
        for time in range(future_days):
            pred = np.array(future_series,dtype='float64')
            pred -= min_scale
            pred /= max_scale
    
            pred = pred.reshape(1,-1,1)
    
            predict = model.predict(pred)
    
            predict *= max_scale
            predict += min_scale
    
            future_series.append(predict[0][0])
            futures.append(predict[0][0])
    
            future_series.pop(0)
            
        plt.plot(np.arange(future_days),futures)
        plt.title('{}days'.format(future_days))
        plt.show()
    
    predict_days(future_days,future_series)

     

     

    이상입니다.

     

    모델의 layer를 lstm이 아닌 GRU로 변경을 하셔도 무방합니다.

    GRU는 lstm보다 빠를뿐더러 더 정확한 결과가 나올 수도 있습니다.

    실제 이를 이용해서 주식을 투자하는 방식은 권유하지 않습니다.

    학습 목적으로 이용해주시기 바랍니다.

    감사합니다.

     

    그외 다른 주식 데이터를 이용해도 무방합니다.

    반응형
Designed by Tistory.