반응형

안녕하세요 지누식입니다.

오늘은 여러분께 조금은 어려운 인공지능에 대해서 소개해드리려고 합니다.



현재 많은 분야에서 이용되고 있는 인공지능은, 이미 일반인들에게 많은 정보가 공개되어 있다고 해도 과언이 아닙니다.

구글에서 tensorflow를 공개하면서 많은 부분을 일반인들이 이용할 수 있게 되었고

이를 더 편리하게 keras에서 각종 모듈을 제공하고 있습니다.



오늘은 keras에서 가장 단순한 Dense 레이어와 재무제표, 주가를 이용하여 1년 뒤의 주가를 예측해보는 실험을 진행해보려고 합니다.

우선 두 가지의 데이터셋이 필요합니다.

1. 재무제표 데이터 (이중컬럼을 이용) - total_data

2. 주가 데이터 - total_price



1번과 2번 모두 크롤링을 이용해 구할 수 있지만, 1번의 경우에는 3~4년 치의 데이터밖에 구할 수 없습니다.

따라서 따로 결제하거나 하셔야 하지만, 일단 저는 가지고 있는 데이터가 있음으로 이용하도록 하겠습니다

또한 2번 데이터의 경우는 크롤링으로 쉽게 해결할 수 있기 때문에 나중에 포스팅으로 다룰 예정입니다..

 

for year in range(2000,2019):
    code_data1 = total_data[year]['총자산(평균)(원)'].dropna().index.tolist()
    code_data2 = total_data[year-1]['총자산(평균)(원)'].dropna().index.tolist()
    code_data3 = total_data[total_data[year-1]['매출액(원)'] != 0].index.tolist()
    code_data = list(set(code_data1).intersection(code_data2))
    code_data = list(set(code_data).intersection(code_data3))
    
    
    #가격정보 저장 - T_data
    price_data = total_price['%s-05' % str(year):'%s-05' % str(year+1)][code_data]
    price_data = price_data.dropna(axis=1)
    price_data = (price_data - price_data.loc[price_data.index[0]] )/price_data.loc[price_data.index[0]]
    MachineLearning_T_data = pd.DataFrame(index = price_data.columns)
    MachineLearning_T_data['End'] = price_data.loc[price_data.index[-1]]
    MachineLearning_T_data.to_excel(r'경로\머신러닝 T_data - %d.xlsx' %year)
    
    #실용데이터 저장 X_data
    practical_data = pd.DataFrame(index = code_data)
    data = total_data.loc[code_data][year]
    pre_data = total_data.loc[code_data][year-1]
    
    practical_data['ROA_Absolute'] = data['당기순이익(원)']/data['총자산(평균)(원)']
    practical_data['Cashflow_Asset'] = data['현금흐름(원)']/data['총자산(평균)(원)']
    practical_data['GPA'] = data['매출총이익(원)'] / data['총자산(평균)(원)']
    practical_data['Profit_increase'] = (data['매출액(원)'] - pre_data['매출액(원)']) / pre_data['매출액(원)']

    practical_data[practical_data[practical_data.columns] == float('inf')] = 0
    practical_data = practical_data.fillna(0)
    
    practical_data.to_excel(r'경로\실용데이터 - %d.xlsx' %year)

우선 전체 코드를 먼저 입력해두고 하나씩 파헤치는 식으로 설명해드리겠습니다.

for year in range(2000,2019):
    code_data1 = total_data[year]['총자산(평균)(원)'].dropna().index.tolist()
    code_data2 = total_data[year-1]['총자산(평균)(원)'].dropna().index.tolist()
    code_data3 = total_data[total_data[year-1]['매출액(원)'] != 0].index.tolist()
    code_data = list(set(code_data1).intersection(code_data2))
    code_data = list(set(code_data).intersection(code_data3))

먼저 앞부분입니다.

for 문을 통해서 year값이 2000~2018까지 1씩 증가하도록 설정 해줍니다.

그 후 code_data1 , code_data2, code_data3 을 통해서 nan 값을 선별해 줍니다.



총자산(평균)(원)에 들어있는 값이 nan 이라면 다른 값에도 nan이 많이 들어있었거나 값이 없었기 때문에

총자산(평균)(원) 값이 nan인 index들을 dropna를 통해 없애주었습니다.



또 단순히 1년이 아니라, 전년도의 수치와 비교도 해야 하기 때문에, 전년도 데이터가 없는 것 또한 dropna 해주었습니다.



그리고 마지막으로 제가 데이터를 얻은 곳이 fnguide라는 곳인데, 상장 전의 정보도 포함하고 있어서 매출액이 0인 경우가 가끔 있었습니다.

그래서 total_data 중에서 전년도의 매출액이 0이 아닌 것만 code_data3에 저장했습니다.



그 후에 intersection을 통해 3개의 데이터 중에서 중복되는 것만 합쳤습니다.

 

    #가격정보 저장 - T_data
    price_data = total_price['%s-05' % str(year):'%s-05' % str(year+1)][code_data]
    price_data = price_data.dropna(axis=1)
    price_data = (price_data - price_data.loc[price_data.index[0]] )/price_data.loc[price_data.index[0]]
    MachineLearning_T_data = pd.DataFrame(index = price_data.columns)
    MachineLearning_T_data['End'] = price_data.loc[price_data.index[-1]]
    MachineLearning_T_data.to_excel('경로\머신러닝 T_data - %d.xlsx' %year)

그 후에는 가격정보를 정리했습니다.


ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ왜 5월에서 5월까지인가?ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

가격정보의 경우 05~04월을 이용하는 게 일반적입니다. 

2011년의 재무제표의 경우 2012년 4월 초에 공시가 됩니다. 

그래서 2012년 5월쯤부터 이용할 수 있다고 가정하는 것이죠. 

하지만 저의 경우에는 1년 동안 보유한 주식의 수익률을 예측하여, 이 예측값이 잘 맞아떨어진다면 

나중에 LSTM을 이용할 때 하나의 변수로 넣어주려고 했습니다. 

그리하여 LSTM을 이용할 때 06~05월의 데이터를 예측하기 위해, 당해년도의 05월의 예측값을 이용하기 위해 05~05월로 지정하게 되었습니다. 

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ


여기서는 dropna에 axis=1값을 주었습니다.

기간의 초기와 마지막에 가격 데이터가 없는 경우가 있는데, 이를 방지하기 위함입니다.



또 price_data를 정규화해 주었습니다.

price_data의 경우 모든 주식마다 가격이 다 다르기 때문에, 정규화를 해주지 않으면 가격이 비싼 주식이 더 많은 영향을 미치게 됩니다. 따라서 정규화를 통해 각각의 주식들을 비슷한 정도로 모델에 반영되게 만들어 주었습니다.



이후 End값을 주기 위해 MachineLearning_T_data라는 데이터 프레임을 만들고

MachineLearning_T_data의 End 컬럼에 price_data에 있는 마지막 값을 넣어주었습니다.

이렇게 저장한 데이터 프레임을 경로를 지정하여 '머신러닝 T_data.xlsx'로 저장해줍니다.

 

    #실용데이터 저장 X_data
    practical_data = pd.DataFrame(index = code_data)
    data = total_data.loc[code_data][year]
    pre_data = total_data.loc[code_data][year-1]
    
    practical_data['ROA_Absolute'] = data['당기순이익(원)']/data['총자산(평균)(원)']
    practical_data['Cashflow_Asset'] = data['현금흐름(원)']/data['총자산(평균)(원)']
    practical_data['GPA'] = data['매출총이익(원)'] / data['총자산(평균)(원)']
    practical_data['Profit_increase'] = (data['매출액(원)'] - pre_data['매출액(원)']) / pre_data['매출액(원)']

    practical_data[practical_data[practical_data.columns] == float('inf')] = 0
    practical_data = practical_data.fillna(0)
    
    practical_data.to_excel('경로\실용데이터 - %d.xlsx' %year)

제가 사용한 모든 데이터를 여기에 가져오진 않았습니다.

단순하게 이용하기 위해 4개의 지표만 사용하고 이후에 1개를 더 추가하여 볼 예정입니다.



4가지의 지표는 ROA, Cashflow, GPA, Profit_increase입니다.

ROA, GPA, Profit_increase는 수익성을 대변하며

Cashflow는 실제로 돈이 들어오고 있는가를 보여주는 지표입니다.

이것들을 이용하기 위해 각종 계산식을 이용해 주었고, inf값이 들어가는 경우는 제외하고, nan값이 들어가는 경우는 0으로 지정해주었습니다.

nan값이 들어가는 경우를 0으로 지정해준 이유는 nan값의 경우 영향을 미치면 안 되기 때문에 가중치와 x값이 곱해져서 결국 딥러닝을 할 때 0이 더해지기 때문입니다.

 

이렇게 코드를 하고 나면, 이런 데이터들이 나오게 됩니다.

이제 이 데이터들을 이용하여 1년 후의 주가를 예측해보려고 합니다.

 

오늘은 google colab을 이용하여 딥러닝을 할 예정입니다.

google colab은 내 컴퓨터가 아니라, 구글에서 제공하는 컴퓨터를 이용하기 때문에 훨씬 더 빨리 학습시킬 수 있다는 장점이 있습니다.

본인의 컴퓨터의 성능이 엄청나지 않다면 구글 코랩을 이용하시는걸 추천해 드리겠습니다.



이 google colab에 우선 아까 만들었던 data들을 다 집어 넣어주고 시작하겠습니다.

from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
import pandas as pd
import numpy as np

# 데이터셋 생성하기
for num, year in enumerate(range(2000,2018)):
    x_train = pd.read_excel('실용데이터 - %d.xlsx' %year, index_col = 0)
    t_train = pd.read_excel('머신러닝 T_data - %d.xlsx' %year, index_col = 0)
    merged_train = pd.DataFrame(index = t_train.index)
    merged_train[x_train.columns] = x_train[x_train.columns]
    merged_train[t_train.columns] = t_train[t_train.columns]
    if num == 0:
        total_train = merged_train
    else:
        total_train = pd.concat([total_train,merged_train])

# 데이터 나누기
x_train = total_train[total_train.columns[:-1]].values
t_train = total_train[total_train.columns[-1]].values

# validation data 생성
x_val = x_train[ int(len(t_train) * 0.9) : ]
t_val = t_train[ int(len(t_train) * 0.9) : ]
    #array로 변경
t_val = t_val.reshape(len(t_val),1)

# train data 재생성 (validation data를 뺀것)
x_train = x_train[ : int(len(t_train) * 0.9) ]
t_train = t_train[: int(len(t_train) * 0.9) ]
    #array로 변경
t_train = t_train.reshape(len(t_train),1)

x_test = pd.read_excel('실용데이터 - 2018.xlsx', index_col = 0)
t_test = pd.read_excel('머신러닝 T_data - 2018.xlsx', index_col = 0)
x_test = x_test.loc[t_test.index].values
t_test = t_test['End'].values.reshape(len(t_test),1)

# 모델 만들기
Model_End = Sequential()

Model_End.add( Dense(64, input_dim=len(x_train.T), activation = 'relu') )
Model_End.add( Dense(64, activation = 'relu') )
Model_End.add( Dense(1, activation = 'linear') )

Model_End.compile( loss = 'mse', optimizer = 'rmsprop') # mean_squared_error = mse , optimizer는 Adam과 rmsprop 비교해보기

Model_End.summary()

# 모델 학습시키기
Model_End.fit(x_train, t_train, validation_data = (x_val, t_val) , batch_size = 10, epochs = 100)

# 모델 평가하기
loss = Model_End.evaluate(x_test, t_test, batch_size=10)
print('loss : ' + str(loss))

이렇게 코드를 만들고 나니 꽤나 긴 코드가 되었는데요. 차근차근! 설명해드리겠습니다.

from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
import pandas as pd
import numpy as np

# 데이터셋 생성하기
for num, year in enumerate(range(2000,2018)):
    x_train = pd.read_excel('실용데이터 - %d.xlsx' %year, index_col = 0)
    t_train = pd.read_excel('머신러닝 T_data - %d.xlsx' %year, index_col = 0)
    merged_train = pd.DataFrame(index = t_train.index)
    merged_train[x_train.columns] = x_train[x_train.columns]
    merged_train[t_train.columns] = t_train[t_train.columns]
    if num == 0:
        total_train = merged_train
    else:
        total_train = pd.concat([total_train,merged_train])

우선 텐서플로우에서 Sequential과 Dense를 import 해줍니다.

그리고 pandas와 numpy도 import 해주세요



그리고 데이터셋을 생성합니다.

데이터셋의 경우 지금까지 만든 데이터들을 모두 다 포함해야 합니다.

이때 주의할 점은 train 데이터이기 때문에, test데이터인 2018년의 데이터를 놔두고

2000~2017년의 데이터를 이용한다는 점입니다.

read_excel을 통해 x와 t데이터를 불러와 주세요.



그 후에 merged_train = pd.DataFrame(index = t_train.index) 라는 코드가 있는데요

여기서 x_train을 쓰시면 안 됩니다.

아까 데이터를 처리할 때 보시면, 실용데이터의 경우 code_data에서 모두 다 쓴 반면

머신러닝 T_data는 한 번 더 nan을 없애주었기 때문에 x_train보다 t_train이 더 적을 수 있기 때문입니다.



그리고 merged_train에 x_data의 컬럼과 t_data의 컬럼 값들을 추가해 준 후

total_train이라는 값에 저장하고, 2017년까지 반복하며 total_train에 추가해줍니다.

 

여기까지 완료하셨으면 total_train에는 이러한 값이 저장되게 됩니다.

이때 index는 중복이 포함될 수 있습니다.

2010년도에 있던 회사가 2011년에 또 존재하면 2년 치의 데이터가 쌓이기 때문입니다.

# 데이터 나누기
x_train = total_train[total_train.columns[:-1]].values
t_train = total_train[total_train.columns[-1]].values

# validation data 생성
x_val = x_train[ int(len(t_train) * 0.9) : ]
t_val = t_train[ int(len(t_train) * 0.9) : ]
    #array로 변경
t_val = t_val.reshape(len(t_val),1)

# train data 재생성 (validation data를 뺀것)
x_train = x_train[ : int(len(t_train) * 0.9) ]
t_train = t_train[: int(len(t_train) * 0.9) ]
    #array로 변경
t_train = t_train.reshape(len(t_train),1)

x_test = pd.read_excel('실용데이터 - 2018.xlsx', index_col = 0)
t_test = pd.read_excel('머신러닝 T_data - 2018.xlsx', index_col = 0)
x_test = x_test.loc[t_test.index].values
t_test = t_test['End'].values.reshape(len(t_test),1)

이 부분은 train, validation, test 데이터를 각각 다 처리해주는 부분입니다.

하나하나 살펴보시면 대부분 아시겠지만, 모르는 부분을 알려드리자면 바로 validation data 입니다.

validation data의 경우 overfitting을 방지하기 위한 데이터라고 보시면 됩니다.

딥러닝을 하게 되면, 아무래도 주어진 데이터에 적응을 하므로,

너무 많이 돌리게 되면, 주어진 데이터에만 반응을 하게 됩니다.

따라서 주어진 데이터 속에서 자체적으로 검증을 해볼 수 있는 데이터셋을 만드는데 그게 바로 validation data입니다.

이렇게 하게 되면 validation data의 loss값이 증가할 때부터 overfitting이 된 것이기 때문에 epochs(딥러닝 반복 횟수)를 조절하기 쉬워집니다.





또 주의하실 점은!! t data 부분입니다. t 값들은 모두 (none,1) 의 값을 가지는 array가 되어야 합니다.

하지만 데이터를 불러오기만 하면 (none,)인 벡터가 되기 때문에 reshape를 통해 array로 만드는 걸 잊으시면 안됩니다.

 

# 모델 만들기
Model_End = Sequential()

Model_End.add( Dense(64, input_dim=len(x_train.T), activation = 'relu') )
Model_End.add( Dense(64, activation = 'relu') )
Model_End.add( Dense(1, activation = 'linear') )

Model_End.compile( loss = 'mse', optimizer = 'rmsprop') # mean_squared_error = mse , optimizer는 Adam과 rmsprop 비교해보기

Model_End.summary()

# 모델 학습시키기
Model_End.fit(x_train, t_train, validation_data = (x_val, t_val) , batch_size = 10, epochs = 100)

이제 모델을  만들고 학습시키는 과정입니다.

Sequential()을 통해서 먼저 모델을 생성해줍니다.



그 후 add를 통해 레이어를 추가해 주시면 됩니다.

이때 은닉층의 activation은 relu로 설정하고 출력층의 activation은 linear로 설정해줍니다

relu는 예측의 정확도가 높다고 하여 주로 사용되는 activation이고

linear는 수치예측을 할 때 사용되는 activation입니다.



첫 두 add 뒤에 있는 레이어의 노드 개수인 64는 아무렇게나 설정해주셔도 되고

마지막 Dense의 출력값만 1로 설정해주시면 수치 하나만 나오게 됩니다.



input_dim의 경우 (50000, 123) 의 array가 있을 때 뒤에 있는 값, 즉 열의 개수를 가져오시면 됩니다.

이유는 가중치인 w와 행렬 곱을 하는걸 상상해보시면 쉽게 이해하실 수 있을 겁니다.



그 후 compile에서 loss는 mse로 정의해주고 optimizer는 rmsprop을 사용해줍니다.

optimizer에서 adam을 사용하는 게 가장 좋다고 알려져 있는 거로 알지만, 수치예측의 경우 rmsprop을 사용하시는 분들이 더 많아 rmsprop을 사용하게 되었습니다.



그리고 summary를 통해 대략적인 모델의 모습을 본 뒤 fit으로 train 시켜 주시면 됩니다.

이때 아까 만든 x_val과 t_val의 경우 validation_data를 이용하여 넣어주시면 됩니다.



batch_size는 한 번에 얼마나 많은 데이터를 검사할 것인가인데, 정확한 개념은 모르겠으나

batch_size가 클수록 딥러닝 속도는 빨라졌고, 오차는 큰 편이었습니다.



epochs는 몇 번을 반복할지 설정해주는 것을 말합니다.

 

loss = Model_End.evaluate(x_test, t_test, batch_size=10)
print('loss : ' + str(loss))

이후에 evaluate를 통해서 모델을 평가해주시면 끝이 납니다.

이렇게 다 하고 나면!! 로스 값이 나오게 됩니다.

그런데 저걸?? 보면... 무슨 생각이 들까요..

내가 잘 한 건가? 하는 생각이 듭니다...

우선 loss 값과 val_loss 값이 전혀 수렴하지 않고 계속 0.8 근방을 맴돌고 있다는 것은 제대로 된 데이터가 없다는 뜻일 것 같았습니다.

그리하여! 이 데이터를 그래프로 나타내 보았습니다.

x축을 실제값, y축을 예측값으로 하는 그래프입니다.

실제값과 예측값이 같을수록 잘 예측한 그래프일 테니.. 당연히 y=x에 수렴할수록 좋겠죠?

그런데 이건 무슨 ㅋㅋㅋㅋㅋㅋ 하나도 예측하지 못한 모습을 보실 수 있습니다.



자 그래서 제가!! 아까 추가했던 4가지 수치에 더불어서 BM이라는 또 다른 수치를 추가하려고 합니다.

 

    #실용데이터 저장 X_data
    practical_data = pd.DataFrame(index = code_data)
    data = total_data.loc[code_data][year]
    pre_data = total_data.loc[code_data][year-1]
    
    practical_data['ROA_Absolute'] = data['당기순이익(원)']/data['총자산(평균)(원)']
    practical_data['Cashflow_Asset'] = data['현금흐름(원)']/data['총자산(평균)(원)']
    practical_data['GPA'] = data['매출총이익(원)'] / data['총자산(평균)(원)']
    practical_data['Profit_increase'] = (data['매출액(원)'] - pre_data['매출액(원)']) / pre_data['매출액(원)']
    #추가
    practical_data['BM'] = data['수정BPS(원)'] / total_price.loc[price_data.index[0]][data.index]

    practical_data[practical_data[practical_data.columns] == float('inf')] = 0
    practical_data = practical_data.fillna(0)
    
    practical_data.to_excel('경로\실용데이터 - %d.xlsx' %year)

BM은 PBR의 역수로, 다른 4가지 지표와는 다른 점이 있습니다.

바로!!! 가격이라는 지표가 포함된다는 것입니다.

다른 녀석들은 단순히 기업이 우량한가, 좋은 수익을 내고 있는가만 보고 있지만

BM은 가격과 함께 기업의 자산을 고려하기 때문에 이를 이용한다면 더 좋은 예측값이 나오지 않을까 하고 이렇게 돌려보게 되었습니다.

새로 추가한 지표를 가지고 다시 실용데이터를 google colab에 넣어주신 다음 모델링을 시켜주세요!!

흠.. 이번에도 역시나 loss와 val_loss가 줄어들지 않고 어느 부분에 머물러 있는데요..

하지만 고무적인 점은 loss 값이 아까보다 줄어들었다는 점입니다!!!

그렇다면 이걸 또 그래프로 한번 봐야겠죠?

왼쪽이 처음 BM없이 예측한 값, 오른쪽이 BM을 넣은 값.

흠.. 별반 차이가 없어 보이지만, 오른쪽을 보시면 살짝 y = x 그래프 쪽으로 기울어진 게 보이실 겁니다.

즉 BM이라는 지표를 넣은 게 어느 정도 효과는 있었다는 말이죠



하지만 이를 통해서 얻은 더 큰 교훈이 있습니다

단순히 재무제표만 이용해서는 컴퓨터도 주가를 예측할 수 없다!! 라는 점이죠

그래서 다음에는 LSTM을 이용하여 주가 데이터를 이용하여 예측해보려고 합니다.



제 마지막 결과물은 인공지능과 일전에 해둔 기초들을 합하여 성과를 내는 것이기 때문에, 앞으로도 포스팅 지켜봐 주시면 감사하겠습니다.!

반응형
Posted by 진우식
,