Multiple Perception Lyers: Regression
tensorflow.keras를 적용하여 kospi 주가의 회귀모형을 구축합니다.
>colab 에서 실행한 코드로 주식자료를 호출하기 위해 다음 패키지 설치가 필요합니다.
!pip install -U finance-datareader
import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.preprocessing import StandardScaler from sklearn import metrics from sklearn.model_selection import train_test_split from sklearn.model_selection import KFold import tensorflow as tf from tensorflow.keras import models, layers import FinanceDataReader as fdr
주가 데이터의 이동평균을 계산하고 원시데이터에 연결하기 위한 함수를 작성합니다.
#이동평균을 원시데이터에 연결 def addMa(data, window=[3,5]): for i in window: y=data.rolling(i).mean() y.columns=[f"{j}_{i}" for j in y.columns] data=pd.concat([data, y], axis=1).dropna() return(data) def maDataMake(da, window=[3, 5]): x=addMa(da, window) x1=x.replace(0, method='ffill') x1=x1.replace(np.inf, method='ffill') x1=x1.dropna() return(x1)
주가 자료를 호출합니다.
st=pd.Timestamp(2010,8, 26) et=pd.Timestamp(2022, 3, 16) kos=fdr.DataReader('KS11', st, et) kos.tail()
Close | Open | High | Low | Volume | Change | |
---|---|---|---|---|---|---|
Date | ||||||
2022-03-10 | 2680.32 | 2660.86 | 2682.79 | 2660.86 | 613810000.0 | 0.0221 |
2022-03-11 | 2661.28 | 2665.95 | 2672.62 | 2647.28 | 797030000.0 | -0.0071 |
2022-03-14 | 2645.65 | 2654.93 | 2661.76 | 2633.31 | 636320000.0 | -0.0059 |
2022-03-15 | 2621.53 | 2630.31 | 2641.97 | 2615.08 | 604180000.0 | -0.0091 |
2022-03-16 | 2659.23 | 2649.85 | 2659.90 | 2630.03 | 727290.0 | 0.0144 |
3일, 5일 이동평균을 계산하여 호출한 자료와 결합합니다.
k=maDataMake(kos, [3, 5]) k.columns
Index(['Close', 'Open', 'High', 'Low', 'Volume', 'Change', 'Close_3', 'Open_3', 'High_3', 'Low_3', 'Volume_3', 'Change_3', 'Close_5', 'Open_5', 'High_5', 'Low_5', 'Volume_5', 'Change_5', 'Close_3_5', 'Open_3_5', 'High_3_5', 'Low_3_5', 'Volume_3_5', 'Change_3_5'], dtype='object')
k.shape
(2842, 24)
feature(특성)과 label을 분리하고 특성 중 마지막 행의 자료(new)는 최종 추정을 위해 별도로 보관합니다. 그 외의 특성은 독립변수(ind), 독립변수보다 1행의 시차를 보이는 label의 부분(de)을 반응변수로 합니다.
#특성과 라벨의 분리, close를 label feat=k.drop('Close', axis=1) lab=k['Close'] ind=feat.values[:-1, :] de=lab.values[1:].reshape(-1,1) new=feat.values[-1, :].reshape(1,-1) new
array([[ 2.64985000e+03, 2.65990000e+03, 2.63003000e+03, 7.27290000e+05, 1.44000000e-02, 2.64213667e+03, 2.64503000e+03, 2.65454333e+03, 2.62614000e+03, 4.13742430e+08, -2.00000000e-04, 2.65360200e+03, 2.65238000e+03, 2.66380800e+03, 2.63731200e+03, 5.30413458e+08, 2.88000000e-03, 2.65067667e+03, 2.65136800e+03, 2.66465867e+03, 2.63601733e+03, 6.00191153e+08, -1.41333333e-03]])
각 변수를 표준화합니다.
#독립, 반응변수의 표준화 indScale=StandardScaler().fit(ind) indN=indScale.transform(ind) newN=indScale.transform(new) deScale=StandardScaler().fit(de) deN=deScale.transform(de) indN.shape, deN.shape
((2841, 23), (2841, 1))
tensorflow의 입력데이터는 특정한 경우를 제외하고 'float32'형 입니다. 그러나 다음의 코드 결과와 같이 'float64'형이므로 변환이 필요합니다. 이 변환은 모델 학습을 위해 구분하는 학습군(teain)과 검정군(test)으로 분리후에 실행합니다.
indN.dtype, deN.dtype
(dtype('float64'), dtype('float64'))
#train, test 분리 testSize=0.2 xtr,xte, ytr, yte=train_test_split(indN, deN, test_size=testSize)
#float32 형으로 변환 xtr, xte, ytr, yte, newN=map(np.float32, [xtr, xte, ytr, yte, newN]) xtr.dtype
dtype('float32')
모델을 위해 layer을 구축합니다. 이 경우 입력 데이터의 차원을 지정해야 하는데 데이터의 열(column)의 크기가 됩니다.
inShape=xtr.shape[1] inShape
23
3개의 층으로 구성하며 활성함수(비선형함수)는 ReLU를 적용하였습니다. 또한 비용함수는 MSE, 최적화알고리즘은 Adam를 사용하였습니다.
추정와 실측의 비교 평가를 위해 .mean_absolute_percentage_error'를 지정합니다.
model=models.Sequential() model.add(layers.Dense(64, activation='relu', input_shape=(inShape,))) model.add(layers.Dense(32, activation='relu')) model.add(layers.Dense(1, activation='linear')) model.compile(loss='mse', optimizer='adam', metrics=['mean_absolute_percentage_error']) ep=30 hist=model.fit(xtr, ytr, epochs=ep, batch_size=64)
Epoch 1/30 36/36 [==============================] - 1s 2ms/step - loss: 0.0987 - mean_absolute_percentage_error: 63.7394 Epoch 2/30 36/36 [==============================] - 0s 2ms/step - loss: 0.0115 - mean_absolute_percentage_error: 41.5226 … Epoch 30/30 36/36 [==============================] - 0s 2ms/step - loss: 0.0036 - mean_absolute_percentage_error: 23.1007
학습의 결과를 그래프로 나타내기 위해 hist 객체에 저장합니다. 이 결과는 dictionary 형식으로 다음으로 구성됩니다.
hist.history.keys()
dict_keys(['loss', 'mean_absolute_percentage_error'])
plt.subplot(1,2,1) plt.plot(range(1, ep+1), hist.history['loss']) plt.subplot(1,2,2) plt.plot(range(1, ep+1), hist.history['mean_absolute_percentage_error']) plt.show()
위 결과에 의하면 에폭크 21 이후에 mean_absolute_percentage_error의 상승이 보이므로 ep=21로 다시 모형을 구축합니다.
model=models.Sequential() model.add(layers.Dense(64, activation='relu', input_shape=(inShape,))) model.add(layers.Dense(32, activation='relu')) model.add(layers.Dense(1, activation='linear')) model.compile(loss='mse', optimizer='adam', metrics=['mean_absolute_percentage_error']) ep=21 hist=model.fit(xtr, ytr, epochs=ep, batch_size=64)
생성된 모형을 검정군에 적용합니다.
model.evaluate(xte, yte)
18/18 [==============================] - 0s 1ms/step - loss: 0.0055 - mean_absolute_percentage_error: 50.8509 [0.005474965088069439, 50.85094451904297]
위 결과는 여전히 학습군에 비해 높은 mse와 mean_absolute_percentage_error가 관찰 됩니다. 그러므로 데이터의 정규화와 epoch와 최적화방법의 변경을 통한 모델의 튜닝이 필요합니다.
위에서 별도 보관된 특성 new1을 생성된 모형으로 추정합니다.
pre=model.predict(newN) pre
array([[1.4557662]], dtype=float32)
위의 결과는 표준화된 값으로 원시 스케일로 환원이 필요합니다.
deScale.inverse_transform(pre)
array([[2693.7332]], dtype=float32)
댓글
댓글 쓰기