본문 바로가기
systrader79 칼럼/실전 투자 전략

실전 투자 전략 (28) - 머신러닝 알고리즘(kNN, SVM, Decision tree)을 이용한 절대수익 전략(3)

by systrader79 2016. 12. 11.
728x90
반응형

 이번 포스팅에서는 분류 알고리즘으로 널리 이용되는 Decision tree model을 기반으로 한 Random forest 알고리즘을 이용한 모멘텀 전략에 대해 살펴보겠습니다. 


1. Decision tree? Random forest?

 Decision tree 모델은 어떤 예측을 하기 위해 다양한 변수가 존재하는 경우, 예측력이 높은 변수를 우선적으로 순차적으로 배치한뒤 연속적인 분류 과정을 통해 최종적인 예측을 얻어내는 머신러닝 알고리즘의 일종입니다. 

'야, 그걸 설명이라고 하냐? 좀 알아듣기 쉽게 얘기해봐!' 

쉬운 예를 들어 보겠습니다.


2. Decision tree 알고리즘을 통한 체벌 예측

 제가 고등학교 3학년 때 저의 담임 선생님은 학교에서 가장 악명이 자자한 '폭력 교사' 였습니다. 

 요즘은 시대가 좋아졌지만, 제 학창시절만 해도 소위 '사랑의 매'라는 명목으로 학생에 대한 선생님의 폭력이 정당화되던 시기였습니다. 

 하도 체벌이 일상화되어 있어서, 모의고사를 치고 나면 10점 떨어진 친구는 10점 떨어졌으므로 10대, 5점 떨어진 친구는 5대씩 맞았죠. 

 5점 올랐으면? 5점 밖에 안 올랐다고 또 때리고...

 하지만 가뭄에 콩나듯이 매질 없이 넘어가는 날이 있었는데요, 그럴 때면 모든 친구들이 신기해했습니다. 왜 오늘은 안 때리지?


<사랑의 매.jpg>

 자, 그러면 여기서 우리 담임선생님이 어떤 날 때릴 확률이 높고 어떤 날 안 때릴 확률이 높을지 decision tree 알고리즘을 이용해서 예측해보겠습니다. 


 매일 얻어터지던 우리 반 아이들이 모여서 회의를 합니다. 


 "야, 우리 맨날 맞는 것도 지겨운데 저기압일 걸로 예상되는 날에는 특별히 더 신경 써서 설설 기고, 그렇지 않을 걸로 예상되는 날에는 좀 긴장을 푸는 것이 어떨까?"


 "오케이 좋아. 근데 언제 담임이 우리를 많이 때리는 것 같애?"


 "내가 봤을 땐, 담임이 빨간 넥타이 차고 온 날 많이 때린 것 같애"


 "야...그게 말이 되냐? 그건 우연의 일치일 뿐이야"


 "내가 봤을 땐, 아침 조례 시간의 얼굴 표정이 거의 90%를 좌우하는 것 같음. 아침에 실실 웃으면 그날은 잘 넘어가고, 아침에 굳은 표정인날은 십중 팔구 타작날이었던 것 같음"


 "내 경험에 의하면, 지각한 놈이 있는지의 여부도 중요한 변수였던 것 같음. 아무도 지각을 안 한날은 때린 적이 별로 없었던 것 같고, 지각한 놈이 하나라도 있으면 때린 적이 많았던 것 같음'


 어떻습니까? 나름대로 자신의 경험에 입각해서 담임 선생님이 체벌할지의 여부에 영향을 미치는 다양한 변수를 제시했습니다. 어떤 변수는 타당해보이고, 어떤 것은 그렇지 않아보이고, 어떤 것은 잘 모르겠습니다.

 이처럼 어떤 결과에 영향을 미치는 다양한 변수가 존재할 때, 이 변수들을 어떻게 적절히 순차적으로 조합을 해서 판단을 내려야 최종적으로 가장 정확한 판단을 내릴 수 있을지 결정하는 방법 중 하나가 decision tree 모델입니다. 

 이 체벌 예측 모델에서 독립 변수는 넥타이 색깔, 아침 조례 때의 얼굴 표정, 지각한 학생의 존재 여부 등이 고, 종속 변수는 당일 체별 여부가 되겠지요? 

 변수가 많다고 해서 이것이 다 의미있는 정보는 아닐 겁니다. 예를 들어, 넥타이 색깔은 제 개인적인 경험으로 체별 여부와 상관성이 상당히 낮았던 걸로 기억합니다. 하지만, 상대적으로 아침 조례 시간의 기분 상태는 상당히 체별 여부와 상관성이 높았던 것 같네요. 

 이처럼, 설명력이 다양한 변수가 혼재되어 있는 경우, 어떻게 분류를 해야 정확한 예측을 할 수 있을까요? 너무나 상식적인 얘기지만, 종속 변수와의 상관성과 설명력이 가장 높은 개별 변수를 최우선적으로 이용해서 분류를 한뒤, 순차적으로 높은 중요도를 가진 변수를 배치하여 예측을 하는 것이 바람직하겠지요? 

 그러기 위해서는 우선 데이터를 통해 패턴을 검증할 필요가 있겠습니다. 

 우선, 다음과 같은 방식으로 데이터를 수집합니다. 아래에서는 일부만 예를 든 것입니다. 데이터의 개수는 많으면 많을수록 좋겠지요?

 

날짜

넥타이 색깔

조례때 표정

지각학생 유무

당일체벌여부

5월 1일

빨간색

천진난만

X

5월 2일

파란색

똥씹은 표정

O

5월 3일

파란색

천진난만

X

5월 4일

빨간색

천진난만

O

5월 5일

파란식

똥씹은 표정

O

  

 이렇게 데이터를 수집한 후에는 각각의 변수(넥타이 색깔, 조례 때 표정, 지각학생 유무)가 당일 체벌 유무와 얼마나 높은 정확도를 지니는지 개별적으로 확인을 한 뒤, 정확도가 높은 순으로 결정 모델을 만드는 것입니다. 

 예를 들어, 100일 동안 위와 같은 방식으로 데이터를 100개 수집한 후 분석해봤더니, 다음과 같았다고 가정해보겠습니다. 


 빨간 넥타이 : 체벌 확률 50%, 파란 넥타이 : 체벌 확률 50%

 천진난만 표정 : 체벌 확률 10%, 똥씹은 표정 : 체벌 확률 90%

 지각학생 없음 : 체벌 확률 30%, 지각학생 존재 : 체벌 확률 70%


 이렇게 데이터가 나왔다면, 체벌 여부와 가장 연관성이 높은 변수는 조례 때 표정이고, 다음이 지각 학생의 여부, 마지막으로 넥타이 색깔이므로, 의사 결정 모델도 이 순서에 맞게 짜면 되는 것입니다. 

 체벌 예측 모델 : 조례 때 표정 ---> 지각 학생 여부 ---> 넥타이 색깔


 예를 들어, 조례 때 똥씹은 표정을 한 상태에서 지각학생까지 있었다면, 십중 팔구 그 날은 얻어터질 가능성이 높다고 판단하면 되겠지요? 사실 넥타이 색깔 같은 변수는 설명력이 거의 없기 때문에 배제해도 거의 무방할 정도겠지요. 

 만일 조례 때는 천진난만한 표정을 지었으나, 지각학생은 있었고, 넥타이는 파란색인, 약간은 애매한 상황에는 어떻게 예측해야 할까요? 이런 경우에 대한 정량적인 판단은 Decision tree 알고리즘의 계산수치에 근거해서 내려지게 됩니다. 물론, 앞서 예를 든 '뻔히 보이는 경우'에 대한 판단도 사실은 다 정량적으로 수치 기반으로 판정이 내려집니다. 

 최대한 이해하기 쉬운 설명을 위해 '정확도', '결과와의 상관성' 같은 약간은 부정확한 용어를 이용해서 설명을 했지만, 엄밀하게 표현하자면 분류의 정확도 기준은 데이터 분포의 불순도를 나타내는 '엔트로피'라는 개념을 이용해서 계산을 합니다. 데이터의 불순도가 높을수록 엔트로피 값이 낮아지고, 불순도가 낮을수록 엔트로피 값이 높아지므로, 개별 변수에 대한 엔트로피값을 계산하여, 분류의 순서를 정하는 방식입니다. 

 Decision tree의 수학적 알고리즘에 대한 세부적인 내용은 인터넷 검색을 통해 확인하시기 바랍니다. 

 Decision tree에 대한 다른 예를 몇 개 확인하면 다음과 같습니다. 아마 그림만 보셔도 어떤 개념인지 이해가 가리라 생각합니다. 

 

<타이타닉호 승객의 생존 여부 예측 모델>

 


<스팸 메일 분류 알고리즘>

 


3. Decision tree 모델의 확장판 - Random forest 알고리즘

 앞서 살펴본 바와 같이 decision tree 모델은 직관적이고 이해하기 쉬운 장점이 있지만, 치명적인 단점이 하나 있는데, 그것은 과거 데이터에 최적화된 구조이기 때문에, 새로운 데이터가 들어오거나 약간 변화가 생기는 경우 오히려 정확도가 떨어질 수 있다는 것입니다. 

 전형적인 과최적화 문제라고 보시면 되겠지요.

 이런 문제를 극복하기 위한 모델이 random forest 모델입니다.

 Random forest 모델에서는, decision tree 모델의 학습 데이터 전체를 그대로 이용하는 것이 아니라, 우선 데이터 중 일부만 랜덤하게 선택하여 여러 개의 학습 데이터 셋을 만든 뒤 결과를 검증합니다. 이후, 각각의 데이터 셋의 결과를 다수결 투표 하듯 표결한 뒤 (투표, 확률, 평균 등) 가장 높은 가능성을 보이는 쪽으로 분류하는 방식입니다. 

 Random forest 모델에서는 각 트리들의 편향은 그대로 유지가 되면서, 분산은 감소하기 때문에 보다 안정적이면서도 전반적인 정확도 성능도 높아지게 됩니다. 

 본 블로그에서도 지속적으로 언급한 평균 모멘텀 분산 투자 전략의 개념 (1개의 모멘텀 값만 선정해서 투자하지 않고 1~12개월의 12개 구간에 분산한 뒤 상대적 비중을 부여하는 방식) 도 random forest 알고리즘의 철학과 일부 통하는 면이 있다고 볼 수 있습니다. 


4. Random forest 모델을 이용한 월간 모멘텀 투자 전략

 본 블로그에서는 월간 모멘텀이라는 지극히 단순한 지표 하나만 가지고 다양한 변종 투자 전략을 소개하고 있습니다. 이번 포스팅에서는 Random forest 알고리즘을 월간 모멘텀 전략에 적용한 결과를 소개하려 합니다. 

 모멘텀 기간값을 어떤 것을 쓸 것이냐를 결정하는 방법은 크게 3가지로 구분할 수 있겠습니다. 

 첫 번째 방법은, 6개월이나 12개월 같이 고정된 값을 쓰는 방법인데, 이렇게 고정된 값을 써도 큰 무리는 없지만, 왜 하필 7개월이나 11개월은 아니냐라는 질문에 대한 명쾌한 답을 주지는 못합니다. 그저 장기간 백테스트해보니 이게 제일 잘 나와서라는 경험적인 대답 밖에는 할 수가 없는 것이 단점입니다. 

 두 번째 방법은, 1~12개월 타임 프레임 전체에 분산투자하는 방법으로, 블로그에서 지속적으로 소개한 바 있습니다. 최적화라는 과정을 아예 제거해버렸기 때문에 과최적화의 위험성이 없다는 장점이 있습니다. 

 세 번째 방법은, adaptive time frame 같이 시장의 변동성에 맞게 실시간으로 최적 주기를 조절하는 방법인데, 단순히 고정된 모멘텀 값을 쓰는 방법보다는 진일보한 방식이라고 볼 수 있겠습니다. 


 Random forest 모델을 이용한 월간 모멘텀 투자 전략에서는, 1개월 모멘텀, 2개월 모멘텀, 3개월 모멘텀 .......12개월 모멘텀의 12개의 변수를 독립 변수로 하고, 다음달 주가 상승 여부를 종속 변수로 지정한 뒤 random forest 알고리즘을 돌립니다. 

 12개의 변수를 통해 생성된 여러개의 decision tree 들을 기반으로, 매월 다수결 투표를 해서 다음달 상승으로 예측되면 종목 보유, 하락으로 예측되면 현금을 보유하는 방식입니다. 시장은 끊임없이 변하므로 학습 데이터는 최근 12개월 간의 데이터를 이용해서 매달 최신 데이터에 맞게 업데이트 하는 방식입니다. 

 KOSPI 지수를 대상으로 시뮬레이션 한 결과는 아래와 같습니다. 

 (모든 머신 러닝 알고리즘이 마찬가지이지만, 알고리즘의 개념은 이해할 수 있어도, 실제 데이터에 알고리즘이 적용되어 산출된 수학적인 결과 값은 직관적으로 이해하기는 어렵습니다. 따라서, 수익 곡선이 상대적으로 양호하게 나타나는 구간과 상대적으로 언더퍼폼하는 구간을 이해하고, 실제 투자 과정에서 직관적이지 못한 것과의 괴리감을 줄이기 위해서는 전통적인 트레이딩 모델을 접목하는 것이 중요한 과제라고 생각합니다.)



5. Random forest 알고리즘 파이썬 코드

import pandas as pd

import matplotlib.pyplot as plt

import numpy as np

import pandas_datareader.data as web

from sklearn import neighbors, svm

from sklearn.ensemble import RandomForestClassifier

from sklearn.linear_model import LogisticRegression

           

def price(stock, start):

    price = web.DataReader(name=stock, data_source='yahoo', start=start)['Adj Close']

    return price.div(price.iat[0]).resample('M').last().to_frame('price')


a = price('^KS11','2000-01-01')

a['cash'] = [(1.03**(1/12))**x for x in range(len(a.index))]

a['R1'] = a.price.shift(1)/a.price.shift(2)

a['R2'] = a.price.shift(2)/a.price.shift(3)

a['R3'] = a.price.shift(3)/a.price.shift(4)

a['R4'] = a.price.shift(4)/a.price.shift(5)

a['R5'] = a.price.shift(5)/a.price.shift(6)

a['R6'] = a.price.shift(6)/a.price.shift(7)

a['R7'] = a.price.shift(7)/a.price.shift(8)

a['R8'] = a.price.shift(8)/a.price.shift(9)

a['R9'] = a.price.shift(9)/a.price.shift(10)

a['R10'] = a.price.shift(10)/a.price.shift(11)

a['R11'] = a.price.shift(11)/a.price.shift(12)    

a['R12'] = a.price.shift(12)/a.price.shift(13)    

a['rollingstd'] = a.price.pct_change().shift(1).rolling(12).std()

a['result'] = np.where(a.price > a.price.shift(1), 1,0)     

a = a.dropna()


clf1 = neighbors.KNeighborsClassifier(n_neighbors=3)

clf2 = svm.SVC()

clf3 = RandomForestClassifier(10)

clf4 = LogisticRegression()


a['predicted']= pd.Series()

for i in range(12,len(a.index)):

    x  =  a.iloc[i-12:i,2:15]    

    y  =  a['result'][i-12:i] 

    clf3.fit(x, y)

    a['predicted'][i]= clf3.predict(x)[-1] 


a = a.dropna()

a.price = a.price.div(a.price.ix[0])

print(a)

accuracy=clf3.score(a.iloc[:,2:15],a['result'])


a['Random forest'] = np.where(a.predicted.shift(1)==1,a.price/a.price.shift(1),1.0026).cumprod()

a[['Random forest','price']].plot()

plt.show()

print ("Predicted model accuracy: "+ str(accuracy))


나가시기 전에 블로그 글 맨 하단의 배너 광고를 한 번만 클릭해주시면 더 좋은 콘텐츠를 만드는데 큰 도움이 됩니다~ 감사합니다! >

1. 네이버 카페 '실전주식투자 연구소' (클릭) 으로 오시면, 본 블로그의 모든 내용을 순서대로 확인하실 수 있고, 다양한 실전 투자 정보도 얻을 수 있습니다~


2. 'systrader79의 주식 단기 매매 전략 온라인 강좌'가 뉴지스탁에서 진행 중입니다!

   개별 주식을 이용한 단기 매매 기법, 뉴지스탁을 통한 완전 자동 투자 매매 구현에 관한 폭넓         은 노하우를 다루고 있으니, 많은 성원 부탁드립니다~

   첫 번째 강의는 수강 신청없이 무료로 시청 가능합니다 (아래 링크 클릭 --> 1번 방송 클릭)

     강의 소개 (클릭)

     * 강의 바로가기 (클릭)



3. 여러분의 인생이 걸린 너무나도 중요한 소식! --- > 여기를 클릭하세요!


728x90
반응형

댓글