랜덤 포레스트(Random Forest)를 활용한 주가 방향 예측

2020. 7. 27. 22:23금융 데이터 분석

반응형

주가를 예측하는데 있어 시계열 분석 방법론이 활발히 적용되나, 의사결정나무, 랜덤 포레스트와 같은 Classification 모형도 주가 방향을 예측하는데 활용되고 있습니다.

이번에는 랜덤 포레스트 모형을 이용하여 주가가 오를지 안오를지 방향성에 대해 예측해 보겠습니다. 이번도 마찬가지로 아주 예측력이 뛰어난 모델을 만들다기 보다는 기본적인 모형을 활용하여 주가를 예측하는데 적용하는데 의의를 두고 있습니다.

코드에 들어가기 앞서 먼저 방향 예측에 대한 구현 아이디어를 먼저 정리해보도록 하겠습니다.

여기서는 앞선 7일치 정보를 이용하여 8일째에 주가가 전일보다 오를지 떨어질지 예측해보도록 하겠습니다.

먼저 필요한 Module을 Import하고 크롤링을 통해 수집했던 주가 데이터를 불러옵니다.

import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics

os.chdir(".../new_stock")
sam = pd.read_csv("samsung.csv")
sam=sam.sort_index(ascending=False)
sam=sam.reset_index()
sam=sam.drop(["index"], axis=1)
sam.rename(columns ={"종가":"Close"}, inplace =True)
sam["return"]=np.nan ## 나중에 값을 채울 Column을 미리 Nan값으로 생성

그 다음 return에 값을 채우겠습니다. 전일보다 가격이 올랐으면 1, 떨어졌으면 0으로 값을 채우겠습니다. 예를 들어 첫날 46500원이고 그 다음날 46050원이면 0이 됩니다.

data=sam[["Close","return"]]

for i in range(len(data)-1):
    #print(i)
    #print(i+4)
    if (data.iloc[i+1]["Close"]/data.iloc[i]["Close"])-1 >=0:
        data.iloc[i+1]["return"] =1
        
    else :
        data.iloc[i+1]["return"]=0
        
        
print(data.head())
print(data.tail())
# Output
     Close  return
0  46500.0     NaN
1  46050.0     0.0
2  45850.0     0.0
3  46550.0     1.0
4  46900.0     1.0
      Close  return
486  55000.0     1.0
487  53400.0     0.0
488  53000.0     0.0
489  52800.0     0.0
490  52700.0     0.0

첫날에는 전일이 없기 때문에 return에 아무 값도 입력되지 않습니다. 또한 우리는 7일치의 데이터를 가지고 8일째를 예측할 것이기 때문에 1일부터 7일까지의 return은 크게 중요하지 않습니다.

그 다음으로 7일치의 데이터를 하나의 Row로 구성하여 Feature 데이터를 구성하고 Return 컬럼을 Label 데이터로 구성합니다.

feature_list =[]
label_list=[]

for i in range(len(data)-7):
    feature_list.append(np.array(data.iloc[i:i+7]["Close"]))
    label_list.append(np.array(data.iloc[i+7]["return"]))
    
data_X = np.array(feature_list)
data_Y = np.array(label_list)

구성한 Feature 데이터와 Label 데이터를 Train set과 Test set으로 구분합니다.

train_data, train_label = data_X[:-100], data_Y[:-100]
test_data, test_label = data_X[-100:], data_Y[-100:]

train_data= pd.DataFrame(train_data)
train_label= pd.DataFrame(train_label)
test_data= pd.DataFrame(test_data)
test_label= pd.DataFrame(test_label)

이제 구성한 데이터 셋을 바탕으로 Random Forest모델을 구현합니다. 먼저 Base 모델로 Estimator(나무의 수)를 3으로 하여 구성하고 정확도를 측정합니다.

## base model
forest = RandomForestClassifier(n_estimators=3)
forest.fit(train_data, train_label.values.ravel())

y_pred = forest.predict(test_data)
print("accuracy: {}".format(metrics.accuracy_score(y_pred, test_label)))

여기서 정확도가 0.49가 나왔습니다.  1/2 확률로 찍는 것보다 더 좋지 않은 결과가 나오게 되었습니다...

GridSearchCV모듈을 이용하여 좀 더 좋은 Random Forest모델을 찾아보도록 하겠습니다. GridSearchCV는 편하게 모델의 Parameter을 실험해볼 수 있는 기능을 제공해줍니다. 저는 estimator수를 2,4,6,8,10를 변경하면서 추정해보고 추가적으로  criterion, min_samles_leaf를 바꾸어 가면서 실험을 해보겠습니다. 최고의 parameter를 찾는 기준은 Accuracy로 설정하였습니다.

from sklearn.model_selection import cross_val_score, GridSearchCV

forest_parameters = [{"n_estimators" : [2,4,6,8,10],

                      "criterion" : ["gini","entropy"],

                      "min_samples_leaf":[2,4,6,8,10],

                      "random_state":[1]}]
                      
                      
forest_grid = GridSearchCV(estimator = RandomForestClassifier(), param_grid = forest_parameters, scoring ="accuracy", cv=10, n_jobs=1, iid=False)
forest_grid_result =forest_grid.fit(train_data, train_label.values.ravel())
best_forest_parameters = forest_grid_result.best_params_
forest_score = forest_grid_result.best_score_

print(forest_grid_result.best_params_) ##{'criterion': 'entropy', 'min_samples_leaf': 10, 'n_estimators': 2, 'random_state': 1}

이제 찾은 Parameter를 활용하여 정확도를 추정해보도록 하겠습니다.

Forest_model = RandomForestClassifier(n_estimators =best_forest_parameters["n_estimators"],

                                     criterion = best_forest_parameters["criterion"],

                                     min_samples_leaf =best_forest_parameters["min_samples_leaf"],

                                     random_state =1).fit(train_data, train_label.values.ravel())

y_pred_best = Forest_model.predict(test_data)
print("accuracy: {}".format(metrics.accuracy_score(y_pred_best, test_label)))

여기선 정확도가 0.53이 나왔습니다. 조금 좋아지긴 했지만 아직도 1/2확률로 찍는 것과 큰 차이가 없는 것 같습니다.

아마 모델을 개선하기 위해서는 단순히 7일치 가격정보만을 활용할 것이 아니라, 수익률이라던가 재무정보라던가 더 다양한 정보를 내포하고 있는 Feature를 추가해야 할 것으로 보입니다.

 

Reference:

https://myjamong.tistory.com/79

https://towardsdatascience.com/how-to-predict-the-success-of-your-marketing-campaign-579fbb153a97

https://towardsdatascience.com/grid-search-for-model-tuning-3319b259367e

https://bkshin.tistory.com/entry/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-4-%EA%B2%B0%EC%A0%95-%ED%8A%B8%EB%A6%ACDecision-Tree

반응형