반응형
##########################################주가 예측 ##################################################
# 예제의 목적 : "상관 자산" + "과거 데이터" => "MS 주가 예측"
""" ############################################################################################ 1번 문제 정의 ############################################################################################"""
# MS 과거데이터 + 독립변수로 사용되는 상관 자산 : (주식 + 환율 + 인덱스)
""" ############################################################################################2번 문제 데이터 불러오기############################################################################################"""
import numpy as np
import pandas as pd
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
#################################################
###############데이터 불러오기####################
'''
stk_tickers = ['MSFT','IBM','GOOGL'] # 주식 데이터 (MSFT,IBM,GOOGL)
ccy_tickers = ['DEXJPUS','DEXUSUK'] # 환율 데이터 (DEXJP US, DEXUS UK)
idx_tickers = ['SP500','DJIA','VIXCLS'] # 인덱스 지수 데이터 (SP500,DJIA,VIXCLS 받아옴.)
stk_data = web.DataReader(stk_tickers,'yahoo')
ccy_data = web.DataReader(ccy_tickers, 'fred')
idx_data = web.DataReader(idx_tickers,'fred')
'''
#################################################
############CSV파일에서 불러오기##################
stk_data = pd.read_csv("./data_collection/datasets/orelly_MSFT IBM GOOGL.csv",index_col=[0],header=[0,1]) # index_col -> default (None) // 0열을 인덱스로 불러온다. // header -> default (첫번째 행) // 0~1행을 열이름으로 지정해서 불러온다.
ccy_data = pd.read_csv("./data_collection/datasets/orelly_DEXJPUS DEXUSUK.csv",index_col=[0]) # index_col -> default (None) // 0열을 인덱스로 불러온다.
idx_data = pd.read_csv("./data_collection/datasets/orelly_SP500 dJIA VIXCLS.csv",index_col=[0]) # index_col -> default (None) // 0열을 인덱스로 불러온다.
##################################################
##################################################
"""
##################stk_data###########
GOOGL IBM DEXJPUS DEXUSUK SP500 dJIA VIXCLS MSFT_DT MSFT_3DT MSFT_6DT MSFT_12DT
2017-04-11 -0.014996 -0.022835 -0.009071 0.003772 -0.002707 -0.001835 0.245454 -0.003810 0.019586 0.023174 0.049428
2017-04-19 0.019607 -0.053524 -0.004392 0.022857 -0.002887 -0.009141 -0.054737 -0.006743 -0.003836 0.009889 0.038547
... ... ... ... ... ... ... ... ... ... ... ...
"""
"""
"""
return_period = 5 # 5일 지연 변수를 사용하기 위해
Y = np.log(stk_data.loc[:,('Adj Close','MSFT')]).diff(return_period).shift(-return_period)
"""
Adj Close 멀티 인덱스에서 MSFT 주가 column만을 긁어 온다. (loc[:,('Adj Close','MSFT)])
diff(return_period)이므로 5일기준으로 이산(차이)을 구한다.
shift(-return_period)이므로 Date 인덱스기준으로2009-12-31 위의 튜플로 주가 값을 올린다.
Date
2009-12-31 0.005888
2010-01-04 -0.022216
2010-01-05 -0.029168
2010-01-06 -0.013744
2010-01-07 0.016610
...
2019-12-24 NaN
2019-12-26 NaN
2019-12-27 NaN
2019-12-30 NaN
2019-12-31 NaN
"""
Y.name = Y.name[-1] + '_pred' ### Y.name = MSFT
# Y와 동일하게 진행
X1 = np.log(stk_data.loc[:, ('Adj Close', ('GOOGL','IBM'))]).diff(return_period)
"""
Adj close 멀티 인덱스에서 GOOGL,IBM 주가 column만을 긁어온다.
diff(return_period)이므로 5일 기준으로 이산(차이)를 구한다.
Attributes Adj Close
Symbols GOOGL IBM
Date
2009-12-31 NaN NaN
2010-01-04 NaN NaN
2010-01-05 NaN NaN
2010-01-06 NaN NaN
2010-01-07 NaN NaN
... ... ...
2019-12-24 -0.007750 0.005646
2019-12-26 0.007781 0.003713
2019-12-27 -0.001328 0.005263
2019-12-30 -0.008555 -0.020716
2019-12-31 -0.008357 -0.011202
"""
X1.columns = X1.columns.droplevel() # 코드상에서는 Attributes Adj Close 삭제됨 // droplevel이란 특정 레벨의 attribute를 삭제.
X2 = np.log(ccy_data).diff(return_period)
"""
##################X2 결과###########################
DEXJPUS DEXUSUK
DATE
2017-04-04 NaN NaN
2017-04-05 NaN NaN
2017-04-06 NaN NaN
2017-04-07 NaN NaN
2017-04-10 NaN NaN
... ... ...
2022-03-21 0.009699 0.011964
2022-03-22 0.020683 0.014664
2022-03-23 0.021212 0.008819
2022-03-24 0.030186 0.001822
2022-03-25 0.023306 0.001821
"""
X3 = np.log(idx_data).diff(return_period)
"""
##################X3 결과###########################
SP500 dJIA VIXCLS
DATE
2017-04-04 NaN NaN NaN
2017-04-05 NaN NaN NaN
2017-04-06 NaN NaN NaN
2017-04-07 NaN NaN NaN
2017-04-10 NaN NaN NaN
... ... ... ...
2022-03-28 0.025307 0.011593 -0.181217
2022-03-29 0.026248 0.013887 -0.193720
2022-03-30 0.032283 0.025015 -0.198316
2022-03-31 0.002265 -0.000853 -0.052581
2022-04-01 0.000616 -0.001233 NaN
"""
### concat 함수는 사용법에 따라 튜플을 추가하거나, attribute를 추가하는 형식으로 사용이 가능하다.
### 아래 X4의 경우, MSFR_DT 기준으로, 5일 지연 변수, 30일, 60일 기준 행렬 생성 ###
X4 = pd.concat([np.log(stk_data.loc[:,('Adj Close','MSFT')]).diff(i)\
for i in [return_period, return_period*3,\
return_period*6,return_period*12]],axis=1).dropna()
X4.columns = ['MSFT_DT','MSFT_3DT','MSFT_6DT','MSFT_12DT'] # multi column -> single column(['MSFT_DT','MSFT_3DT','MSFT_6DT','MSFT_12DT']) 됨 (X기준으로 설명한 내용)
"""
##################X4 결과###########################
MSFT_DT MSFT_3DT MSFT_6DT MSFT_12DT
Date
2010-03-30 -0.003688 0.033126 0.048874 -0.018904
2010-03-31 -0.012216 0.010986 0.024190 -0.050461
2010-04-01 -0.028733 -0.000685 0.006537 -0.055233
2010-04-05 -0.013236 0.000000 0.017230 -0.045312
2010-04-06 -0.009166 0.001024 0.020328 -0.033151
... ... ... ... ...
2019-12-24 0.017240 0.052639 0.077701 0.127371
2019-12-26 0.027475 0.057192 0.079315 0.149732
2019-12-27 0.020657 0.058484 0.079510 0.169371
2019-12-30 0.001143 0.037762 0.065776 0.148682
2019-12-31 0.001841 0.041033 0.053656 0.135968
"""
X = pd.concat([X1,X2,X3,X4],axis=1) # axis=1인 경우 오른쪽에 추가 한다고 생각하면 된다.
dataset = pd.concat([Y,X],axis=1).dropna().iloc[::return_period,:] # dropna란 NA(NULL 정해지지 않은 값)을 삭제 // iloc[::return_period,:]????????????????????
Y=dataset.loc[:,Y.name] ### Y의 shape (129,)
X=dataset.loc[:,X.columns] ### X의 shape (129,11)
""" ############################################################################################ 3.2 탐색적 데이터 분석 (데이터 시각화) ############################################################################################"""
""" ############################################################################################ 5. 모델 평가 ##########################################################################################"""
from statsmodels.tsa.arima.model import ARIMA
validation_size = 0.2 ###### 80%를 (train_set)/// 20%를 (train_set)
train_size = int(len(X) * (1-validation_size)) ## len(X)는 129 // train_size 103
X_train, X_test = X[0:train_size],X[train_size:len(X)]
Y_train, Y_test = Y[0:train_size],Y[train_size:len(Y)]
"""
########## X ###########
GOOGL IBM DEXJPUS DEXUSUK SP500 dJIA VIXCLS MSFT_DT MSFT_3DT MSFT_6DT MSFT_12DT
2017-04-11 -0.014996 -0.022835 -0.009071 0.003772 -0.002707 -0.001835 0.245454 -0.003810 0.019586 0.023174 0.049428
2017-04-19 0.019607 -0.053524 -0.004392 0.022857 -0.002887 -0.009141 -0.054737 -0.006743 -0.003836 0.009889 0.038547
... ... ... ... ... ... ... ... ... ... ... ...
[129 rows x 11 columns] 예시
########## Y ###########
2017-04-19 0.042002
2017-04-27 0.007879
...
Name: MSFT_pred, Length: 129, dtype: float64
"""
### 테스트 옵션 및 평가 메트릭.(4장 참고)
num_folds = 10 #K-fold(10겹) N 겹 진행 초기 변수 설정
scoring = 'neg_mean_squared_error' # sklearn은 MSE에 음수를 취해서 오차를 점수로 바꾼다. 즉, MSE와 같은 개념 점수가 클수록 좋은 결과값.
X_train_ARIMA = X_train.loc[:,['GOOGL','IBM','DEXJPUS','SP500','dJIA','VIXCLS']] ###교재는 DJIA -> dJIA
X_test_ARIMA = X_test.loc[:,['GOOGL','IBM','DEXJPUS','SP500','dJIA','VIXCLS']] ### 교재는 DJIA -> dJIA
#print("길이: {}".format(len(X_test_ARIMA))) # (103,6)
tr_len= len(X_train_ARIMA) # 103
te_len = len(X_test_ARIMA) # 26
to_len = len(X) # 129 (103+26)
####### ARIMA(Autoregressive integrated moving average) #########
modelARIMA=ARIMA(endog=Y_train,exog=X_train_ARIMA,order=[1,0,0]) # endog = 내생 변수 / order : 사용할 AR 매겨변수 ( p,d,q) / exog 외생 변수
## p는 자기 회귀의 차수, d는 첫 디퍼런싱의 정도, q는 이동평균 부분의 차수이다.
model_fit = modelARIMA.fit() # 해당 학습 데이터로 학습
error_Training_ARIMA = mean_squared_error(Y_train,model_fit.fittedvalues) # MSE 도출 => sigma(Y_train-model_fit.fittedvalues)^2 값 // fittedvalues : ## 추정값 (skit-learn 라이브러리에서만 가능한것으로 보임)
predicted = model_fit.predict(start = tr_len - 1, end = to_len -1,exog= X_test_ARIMA)[1:] # ## 예측값 도출 (자세한 사용법 확인 필요.)
error_Test_ARIMA = mean_squared_error(Y_test,predicted) # MSE 도출
print(error_Test_ARIMA) ## 0.00030985051584437283
seq_len = 2 # LSTM에 대한 시퀸스 길이 (자세한 역할 확인 필요!!!!!!!!!!!!!!!!!)
Y_train_LSTM, Y_test_LSTM = np.array(Y_train)[seq_len-1:], np.array(Y_test) #Y_train의 [swq_len-1:] 인덱스만 Y_train_LSTM에 포함 , 나머지는 test_LSTM으로 만듬.
X_train_LSTM = np.zeros((X_train.shape[0]+1-seq_len,seq_len, X_train.shape[1])) # np.zeros로 0으로만 이루어진 행렬 생성
X_test_LSTM = np.zeros((X_test.shape[0],seq_len,X.shape[1])) # 동일
#print(X_train.shape) (103,11)
for i in range(seq_len): # iter문을 사용해서 2차원 -> 3차원으로 변경하는 작업
X_train_LSTM[:,i,:] = np.array(X_train)[i:X_train.shape[0]+i+1-seq_len,:]
X_test_LSTM[:,i,:] = np.array(X)[X_train.shape[0]+i-1:X.shape[0]+i+1-seq_len,:]
#(X_test_LSTM.shape) (102,2,11)
#(X_train_LSTM.shape) (26, 2, 11)
#LSTM 망
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizer_v1 import SGD ### instead of optimizers import SGD
from keras.layers import LSTM
names = []
test_results = []
train_results = []
##### model -> model.add() -> ... -> model.compile ->
#### 큰틀의 학습 방범 model 구축 -> fit 함수로 모델 학습-> predict로 학습된 모델에 예측값을 넣어 예측값 반환
def create_LSTMmodel(learn_rate = 0.1,momentum=0):
#모델 생성
model = Sequential()
model.add(LSTM(50,input_shape=(X_train_LSTM.shape[1],X_train_LSTM.shape[2])))
#필요시 더 많은 셀 추가
model.add(Dense(1)) # 출력 뉴런(노드)의 수 결정(마지막 레이어의 노드의 갯수는 출력 데이터 y의 갯수와 동일하게 1개로 지정.) // (additional argument는 ) ### https://ebbnflow.tistory.com/120
optimizer = SGD(lr=learn_rate,momentum=momentum) #많이 쓰는 otpimizer 함수 : SGD(스토캐스틱 graident 함수) // 파아미터는 : lr(학습률), momentum : 모멘텀 /// 교재에서는 써놓고 사용을 안하는 변수
model.compile(loss='mse',optimizer='adam') #옵티마이저는 adam 사용 // 손실함수는 mse
return model # model 값을 리턴
LSTMModel = create_LSTMmodel(learn_rate=0.01,momentum=0) # 함수 실행
LSTMModel_fit = LSTMModel.fit(X_train_LSTM,Y_train_LSTM,validation_data=(X_test_LSTM,Y_test_LSTM),epochs=330,batch_size=72,verbose=0,shuffle=False) # fit함수로 학습데이터 학습
plt.plot(LSTMModel_fit.history['loss'],label='train',) # 오차율 기록
plt.plot(LSTMModel_fit.history['val_loss'],'--',label='test',) # val_loss // test함수에서 정확도 측정
plt.legend() #범례설정(위에서 선언한 label들 보이게 호출)
plt.show()
error_Training_LSTM = mean_squared_error(Y_train_LSTM,LSTMModel.predict(X_train_LSTM)) # predict함수로 train에서의 MSE의 예측값을 error_training_LSTm 변수에 저장.
predicted = LSTMModel.predict(X_test_LSTM) # 주가 예측 데이터에서 예측값 변수에 저장.
error_Test_LSTM = mean_squared_error(Y_test,predicted) # 실제 주가와 predicted과의 괴리율을 저장??
test_results.append(error_Test_ARIMA)
test_results.append(error_Test_LSTM)
train_results.append(error_Training_ARIMA)
train_results.append(error_Training_LSTM)
names.append("ARIMA")
names.append("LSTM")
def evaluate_arima_model(arima_order):
#predicted = list
modelARIMA = ARIMA(endog=Y_train,exog=X_train_ARIMA,order=arima_order)
model_fit = modelARIMA.fit()
error = mean_squared_error(Y_train, model_fit.fittedvalues) # fittedvalues : ## 추정값
return error
# ARIMA 모델에 대한 p,d,q 값 조합 평가
## 아래 evaluate 모델은 약식 함수임(세개의 변수만으로는 평가가 완벽하지 않음.)
def evaluate_models(p_values,d_values,q_values):
best_score,best_cfg = float("inf"), None
for p in p_values:
for d in d_values:
for q in q_values:
order = (p,d,q)
try:
mse = evaluate_arima_model(order)
if mse < best_score: # best_score보다 MSE(오차)가 낮을 경우 더 좋은 값이므로
best_score, best_cfg = mse, order # 변수를 업데이트한다.
print('ARIMA%s MSE=%.7f' % (order,mse))
except:
continue
print('Best ARIMA%s MSE=%.7f' % (best_cfg, best_score))
#매개변수 평가
import warnings
p_values = [0,1,2]
d_values = range(0,2)
q_values = range(0,2)
warnings.filterwarnings("ignore") #경고 메시지 숨기기
evaluate_models(p_values, d_values,q_values) # p,d,q 주어진 범위내에서 BEST값 추출.
##7.모델 확정
#모델 준비
modelARIMA_tuned = ARIMA(endog=Y_train,exog=X_train_ARIMA,order=[2,0,1]) # 가장 좋은 ARIMA 파라미터로 학습 진행.
model_fit_tuned = modelARIMA_tuned.fit()
#검증셋에 대한 정확도 추정
#estimate accuracy on validation set
predicted_tuned = model_fit.predict(start=tr_len-1,end=to_len-1,exog=X_test_ARIMA)[1:]
print(mean_squared_error(Y_test,predicted_tuned))
# 실제 데이터와 예측 데이터 그래프
predicted_tuned.index = Y_test.index # 실제 데이터와 예측 데이터 그래프의 index를 맞춘다.
plt.plot(np.exp(Y_test).cumprod(), 'r',label='actual',) # exp(지수함수화.) # cumprod는 배열에서 주어진 축에 따라 누적되는 원소들의 누적 값을 계산하는 함수 ex) [1,2,3] => [1, 1*2, 1*2*3]
# t와 a 분리하여 그리기
plt.plot(np.exp(predicted_tuned).cumprod(),'b--',label='predicted')
plt.legend()
plt.rcParams["figure.figsize"] = (8,5) ## mlpt 전역 변수
plt.show()
반응형
'IT 인터넷 > 머신러닝' 카테고리의 다른 글
파생 상품(옵션) - KFold (0) | 2022.05.17 |
---|---|
주가예측 - KFOLD(교차검증-) (0) | 2022.05.16 |
아나콘다 dlib 설치 오류 해결방법 (0) | 2022.01.15 |