[회귀] 삼성전자 주가 예측 모델 구현하기 (시계열 데이터)

2023. 11. 19. 22:59ML&DL/Data Analysis

[삼성전자 주가 예측 모델 구현하기]

 

데이터

 

FinanceDataReader 사용자 안내서

FinanceDataReader 사용자 안내서

financedata.github.io

데이터 컬럼

  • Open: 시가
  • High: 고가
  • Low: 저가
  • Close: 종가
  • Volume: 거래량
  • Change: 대비

 

💻 실습

 

* 라이브러리 import

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
import os

%matplotlib inline
warnings.filterwarnings('ignore')

plt.rcParams['font.family'] = 'NanumGothic'

 

* FinanceDataReader는 주가 데이터를 가져올 수 있는 패키지

!pip install finance-datareader
import FinanceDataReader as fdr

 

* 데이터 불러오기

- 기업별로 코드가 다르다.

import FinanceDataReader as fdr

# KRX stock symbol list
stocks = fdr.StockListing('KRX') # 코스피, 코스닥, 코넥스 전체
stocks = fdr.StockListing('KOSPI') # 코스피
stocks = fdr.StockListing('KOSDAQ') # 코스닥
stocks = fdr.StockListing('KONEX') # 코넥스

# NYSE, NASDAQ, AMEX stock symbol list
stocks = fdr.StockListing('NYSE')   # 뉴욕거래소
stocks = fdr.StockListing('NASDAQ') # 나스닥
stocks = fdr.StockListing('AMEX')   # 아멕스

# S&P 500 symbol list
sp500 = fdr.StockListing('S&P500')

# 기타 주요 거래소 상장종목 리스트
stocks = fdr.StockListing('SSE') # 상해 거래소
stocks = fdr.StockListing('SZSE') # 신천 거래소
stocks = fdr.StockListing('HKEX') # 홍콩거래소
stocks = fdr.StockListing('TSE') # 도쿄 증권거래소
stocks = fdr.StockListing('HOSE') # 호치민 증권거래소

=> 거래소 리스트 stocks 으로 확인 가능 

- 자세한 정보

https://github.com/FinanceData/FinanceDataReader

 

GitHub - FinanceData/FinanceDataReader: Financial data reader

Financial data reader. Contribute to FinanceData/FinanceDataReader development by creating an account on GitHub.

github.com

 

 

* 삼성전자 데이터

samsung = fdr.DataReader('005930')
samsung.tail()
samsung.tail()

* Apple 데이터

apple = fdr.DataReader('AAPL')
apple.tail()

 

- 특정 시점 이후 데이터 불러오기

- 2017년 이후

apple = fdr.DataReader('AAPL', '2017')
apple.head()

- 특정 범위 데이터  ex) 1980-01-01 ~ 2019-12-30

ford = fdr.DataReader('F', '1980-01-01', '2019-12-30')
ford.head()

 

* 삼성전자 주가 데이터 분석

stock = fdr.DataReader('005930')
stock.head()

* 년/월/일 분리

stock['Year'] = stock.index.year
stock['Month'] = stock.index.month
stock['Day'] = stock.index.day
stock.head()

* 년도별/ 월별 피봇 테이블

stock.groupby(['Year', 'Month']).mean()
 

* 주식 가격 시각화 

plt.figure(figsize=(16, 9))
sns.lineplot(y=stock['Close'], x=stock.index)
plt.xlabel('time')
plt.ylabel('price')

# 1990~2000, 2000~2010, 2010~2015, 2015~2020
time_steps = [['1990', '2000'], 
              ['2000', '2010'], 
              ['2010', '2015'], 
              ['2015', '2020']]

fig, axes = plt.subplots(2, 2)
fig.set_size_inches(16, 9)
for i in range(4):
    ax = axes[i//2, i%2]
    df = stock.loc[(stock.index > time_steps[i][0]) & (stock.index < time_steps[i][1])]
    sns.lineplot(y=df['Close'], x=df.index, ax=ax)
    ax.set_title(f'{time_steps[i][0]}~{time_steps[i][1]}')
    ax.set_xlabel('time')
    ax.set_ylabel('price')
plt.tight_layout()
plt.show()

 

* 스케일러

- 수치 데이터 정규화해줌

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
scale_cols = ['Open', 'High', 'Low', 'Close', 'Volume']
scaled = scaler.fit_transform(stock[scale_cols])
scaled
df = pd.DataFrame(scaled, columns=scale_cols)

 

* train/ test 데이터 분할 

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(df.drop('Close', 1), df['Close'], test_size=0.2, random_state=0, shuffle=False)

 

* shape 확인

x_train.shape, y_train.shape

((4800, 4), (4800,))

x_test.shape, y_test.shape

 

((1200, 4), (1200,))

 

import tensorflow as tf
def windowed_dataset(series, window_size, batch_size, shuffle):
    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))
    if shuffle:
        ds = ds.shuffle(1000)
    ds = ds.map(lambda w: (w[:-1], w[-1]))
    return ds.batch(batch_size).prefetch(1)
WINDOW_SIZE=20
BATCH_SIZE=32
train_data = windowed_dataset(y_train, WINDOW_SIZE, BATCH_SIZE, True)
test_data = windowed_dataset(y_test, WINDOW_SIZE, BATCH_SIZE, False)

 

 

* 모델 학습

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM, Conv1D, Lambda
from tensorflow.keras.losses import Huber
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint


model = Sequential([
    # 1차원 feature map 생성합니다. filters는 32로, kernel_size는 5로 지정해주세요.
    Conv1D(filters=32, kernel_size=5,
           padding="causal",
           activation="relu",
           input_shape=[WINDOW_SIZE, 1]),
    # LSTM과 Dense 레이러를 사용해주세요. 활성함수는 각각 tanh와 relu로 지정합니다.
    LSTM(16, activation='relu'),
    Dense(16, activation="relu"),
    Dense(1),
])

 

loss = Huber()
optimizer = Adam(0.0005)
model.compile(loss=Huber(), optimizer=optimizer, metrics=['mse'])
earlystopping = EarlyStopping(monitor='val_loss', patience=10)

filename = os.path.join('tmp', 'ckeckpointer.ckpt')
checkpoint = ModelCheckpoint(filename, 
                             save_weights_only=True, 
                             save_best_only=True, 
                             monitor='val_loss', 
                             verbose=1)

 

history = model.fit(train_data, 
                    validation_data=(test_data), 
                    epochs=50, 
                    callbacks=[checkpoint, earlystopping])

 

* 모델 예측

pred = model.predict(test_data)
plt.figure(figsize=(12, 9))
plt.plot(np.asarray(y_test)[20:], label='actual')
plt.plot(pred, label='prediction')
plt.legend()
plt.show()

=> 실제 주가값(actual)과 예측 주가 값(prediction)이 차이가 크지 않은 것을 확인할 수 있음