본문 바로가기
Python

파이썬 딥러닝을 이용하여 로또 번호 예측하기 - 1부

by 아짱이아빠 2022. 4. 24. 21:22
반응형

 

이번에는 2부에 걸쳐 딥러닝 중 하나인 LSTM을 이용하여 로또 번호를 예측해보는 파이썬 코드에 대해 알아보겠다.

 

이전의 포스트에서 과거 1등 로또 번호들의 합을 바탕으로 기계학습을 하여 다음번 1등 번호들의 합을 예측하고 이 합을 만들어내는 6개의 숫자 조합을 구하는 것에 대해 얘기했었다.

 

 

Python Machine Learning을 이용한 Lotto 번호 생성 프로그램 - (1)

이번에 파이썬을 이용하여 Lotto 번호 6자리를 뽑아내는 프로그램을 만들어 보았다. 많은 사람들이 Lotto 번호를 만드는 프로그램을 만들었으며 대부분은 random() 함수를 이용하여 난수를 생성한다.

superhky.tistory.com

 

 

Python Machine Learning을 이용한 Lotto 번호 생성 프로그램 - (2)(UPDATE )

1부에서 Machine Learning을 통해 다음 차수의 1등 Lotto 번호 총 합 예측을 하였다. 2부에서는 예측된 합에서 6개의 Lotto 번호 조합을 찾아보도록 하겠다. 1부 처음에 얘기했듯이 Lotto 번호의 조합은 과

superhky.tistory.com

 

이번에는 과거의 1등 당첨 번호 각각을 딥러닝 하여 다음번 번호를 예측하는 것에 대해 알아본다. 

 

먼저 간단히 LSTM에 대한 내용은 아래와 같다. 

LSTM은 Long-Short-Term-Memory의 약자이며 RNN(Recurrent Neural Networks)의 한 종류인 인공신경망 네트워크이다.

LSTM은 데이터의 순서가 중요한 요소일 때에 이 시퀀스를 저장하고 학습에 활용한다는 특징이 있다고 한다.

여기서는 LSTM 자체를 알아본다는 것 보다는 이를 이용해서 로또 번호 예측을 할 수 있는 파이썬 코드를 구성하는 것이므로 LSTM이 궁금하신 분들은 다른 포스트 글을 참고하면 되겠다.

사실, 로또 번호는 이전의 당첨번호와 다음의 당첨번호 간에 어떠한 연관관계가 없기 때문에 위에서 얘기한 시퀀스를 저장하고 활용하는 특징인 LSTM을 사용하던 아니면 다른 기계학습을 하던 크게 의미가 없다.

그렇기 때문에 파이썬으로 어떻게 딥러닝을 할 수 있는지 정도만 재미로 읽어주면 좋을 것 같다.

 

[LSTM 모델 훈련]

이 프로그램을 위해서 먼저 아래의 라이브러리들을 import 한다.  

import math
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense, LSTM
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight')

다음은 미리 로또 당첨 번호를 다운로드하여 엑셀 파일로 저장한 데이터를 불러온다.

1부에서는 미리 저정한 데이터를 통해 어떤 식으로 프로그램을 구성하는지 그리고 예측 성능은 어느 정도인지를 알아볼 것이며 2부에서는 실제 로또 사이트에서 당첨 번호 정보를 다운로드하여 활용하는 것에 대해 알아볼 예정이다.  

 

google colab에서는 아래의 코드로 엑셀 파일을 업로드할 수 있다.

from google.colab import files
uploaded = files.upload()

이를 수행하고 '파일선택'을 누르면 내 PC나 다른 저장매체 들어있는 파일을 선택할 수 있는 탐색기가 나온다.

 

이렇게 해서 업로드한 파일은 다음의 코드로 읽을 수 있다.

df = pd.DataFrame()
filename = '/content/excel.xlsx'
df=pd.read_excel('excel.xlsx')

filename에는 업로딩 한 파일이 있는 경로를 넣어준다. 

google colab에서는 업로딩 한 파일에 마우스 오른쪽 버튼을 눌러 ‘경로 복사’를 사용하면 편리하다. 

이렇게 업로딩 한 파일은 아래와 같은 데이터이다.

1회부터 1008회까지의 로또 당첨번호 데이터
(1회부터 1008회까지의 로또 당첨번호 데이터)

1부에서는 이 데이터 중 첫 번째 당첨 번호 데이터만을 사용하여 첫자리 당첨 번호를 예측하고 그 예측 성능은 어떠한지 알아보겠다.

그래서 아래와 같이 첫 column 데이터를 추출하여 별도로 저장하고 또한 전체 1008개의 데이터에서 80퍼센트에 해당하는 데이터를 모델 훈련에 사용한다.

data = df.filter(['first'])
dataset = data.values

training_data_len = math.ceil(len(dataset)*.8)

math.ceil 함수는 소수점 첫자리에서 올림을 한다.

그러므로 ‘training_data_len’의 결과는 807개가 된다.

 

다음은 데이터를 0에서 1의 값으로 정규화한다.

scaler = MinMaxScaler(feature_range=(0,1))
scaled_data = scaler.fit_transform(dataset)

기계학습에서 데이터의 단위나 사이즈가 다르면 문제가 발생하기 때문에 일반적으로 모델 훈련을 위해 데이터를 0에서 1의 값으로 정규화해준다. 

train_data = scaled_data[0:training_data_len, :]
x_train=[]
y_train=[]

for i in range(60, len(train_data)):
  x_train.append(train_data[i-60:i,0])
  y_train.append(train_data[i])

위의 코드는 정규화된 데이터에서 앞에서 정의했던 훈련용 데이터 크기만큼 실제 훈련 데이터를 만들어 준다.

‘x_train’은 반복문 내에서 반복 인덱스 ‘i’에서 60을 빼고 ‘i’까지의 데이터를 계속 누적하게 되어있다. 

그렇기 때문에 ‘training_data’의 처음부터 807번까지 60개씩의 데이터 세트가 구성된다.

x_train의 데이터를 좀 더 자세히 살펴보면 다음과 같다.

x_train 데이터 구성
(x_train 데이터 구성)

첫 60개 데이터 세트는 한 데이터씩 이동하면서 다음의 데이터 세트가 된다.

즉, 첫 데이터 세트에서 두 번째 데이터는 다음의 60개 데이터 세트의 첫 번째 데이터가 되는 식이다.

 

개인적으로는 전제 샘플 데이터에서 훈련을 위한 데이터가 어떻게 나뉘는지가 계속 헷갈렸다.

그래서 이를 그림으로 보면 아래와 같이 정리할 수 있다.

traning data 구조
(traning data 구조)

다음은 만들어진 훈련용 데이터를 LSTM 모델에 넣기 위해서 형태를 변형시키는 부분이다.

x_train, y_train = np.array(x_train), np.array(y_train)
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))

x와 y의 훈련용 데이터의 타입을 배열로 바꿔준 후 x 훈련용 데이터는 reshape 함수를 사용하여 형태를 변경한다.

먼저 np.array 함수를 통해 기존의 x_train 데이터는 2차원 배열로 바뀌며 그 형태를 알아보기 위해 x_train.shape을 해보면 (747, 60) 임을 알 수 있다.

이후 reshape 함수를 사용하여 3차원 배열로 바꿔주는 것이다.

 

반응형

 

LSTM 모델에 입력할 훈련용 데이터를 준비했으니 이제 LSTM 모델을 만들고 훈련을 시작한다.

model = Sequential()
model.add(LSTM(50, return_sequences=True, input_shape = (x_train.shape[1], 1)))
model.add(LSTM(50, return_sequences = False))
model.add(Dense(25))
model.add(Dense(1))
model.compile(optimizer='adam', loss = 'mean_squared_error')
model.fit(x_train, y_train, batch_size=1, epochs=100)

사실 이 부분이 로또 번호 예측의 핵심이지만 딥러닝이나 기계학습 등은 상세한 내용을 모르기 때문에 자세한 설명이 불가하다.

그렇기 때문에 이 코드에서 여러 조건들을 바꿔주면 결과가 달라지는데 여기에 대해서는 LSTM에 대해 상세한 설명을 하는 다른 포스트를 참고하는 것이 좋을 것 같다.

다만, 마지막의 batch_size은 전체 훈련용 데이터를 몇 개씩 자를 것인가를 결정하는 것이고 epochs는 훈련의 iteration(반복 횟수)이며 이 두 가지만 조정해도 결과가 달라지고 연산에 걸리는 시간도 달라진다.

 

[예측 결과와 성능]

이제까지 훈련된 모델은 전체 샘플 데이터에서 훈련에 사용되지 않은 데이터를 활용하여 예측과 예측 결과의 성능을 확인한다.

test_data = scaled_data[training_data_len - 60: , :]
x_test = []
y_test = dataset[training_data_len:, :]

for i in range(60, len(test_data)):
  x_test.append(test_data[i-60:i, 0])

예측과 예측 성능을 확인할 때 사용되는 데이터는 test_data이다.

이 test_data는 앞에서와 유사하게 x와 y용으로 만든다.

x_test 데이터는 807에서 60개를 뺀 747번째 데이터부터 샘플 데이터의 끝가지를 사용하여 구성하며 역시 동일하게 60개씩의 데이터 세트로 구성된 전체 261개의 데이터가 된다.

y_test는 훈련에 사용되지 않은 데이터이며 예측 결과와 비교 시에 사용한다.

이러한 예측과 예측 결과를 비교할 때 사용되는 test 데이터 구조를 앞에서의 training 데이터 구조와 같이 비교해서 표현해보면 아래와 같다.

test_data 구조
(test_data 구조)

 

다음은 훈련된 모델에 test 데이터를 넣기 위해서 reshape 함수를 사용하여 3차원 배열로 만드는 것으로 앞에서와 동일하다.

x_test = np.array(x_test)
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))

 

이제 예측을 수행한다.

predictions = model.predict(x_test)
predictions = scaler.inverse_transform(predictions)
predictions = np.around(predictions)

위 코드에서 예측된 값은 ‘predictions’라는 변수에 저장하고 처음에 데이터를 0~1 값으로 정규화한 값은 inverse_transform 함수를 사용하여 다시 원래대로 되돌린다.

그리고 np.round 함수를 사용하여 소수점 첫자리에서 반올림을 하여 정수로 바꾼다.

 

다음은 예측 결과를 RMS(Root Mean Square)를 통해 실제 당첨 번호와 예측 번호 간의 평균적으로 얼마큼 떨어져 있는지를 보는 것인데 사실 여기서는 큰 의미는 없으니 그냥 한번 이런 것도 있다고 알고 넘어가면 될 것 같다.

rmse = np.sqrt(np.mean(predictions - y_test)**2)

 

아래의 코드를 통해 그래프로 예측 결과를 도식해 본다.

train = data[:training_data_len]
valid = data[training_data_len:]
valid['predictions'] = predictions

plt.figure(figsize=(16,8))
plt.title('Model')
plt.plot(train['first'])
plt.plot(valid[['first', 'predictions']])
plt.legend(['Train', 'Val', 'Predictions'], loc='lower right')
plt.show()

훈련에 사용한 데이터를 train에 저장하고 예측의 결과와 훈련에 사용하지 않은 데이터는 valid에 저장하여 그래프로 그린다.

 

LSTM으로 예측한 로또 번호 결과
(LSTM으로 예측한 로또 번호 결과)

파란색은 훈련을 한 데이터이고 주황색은 훈련으로 사용하지 않은 당첨 번호 데이터이며 노란색은 예측 결과이다.

주황색과 노란색을 비교하면 예상했듯이 예측 결과는 실제 데이터와 많이 다르다.  

앞에서도 얘기했듯이 어떤 알고리즘을 사용해도 로또 번호를 정확하게 예측한다는 것은 불가하기 때문이다. 

 

결과를 좀 더 자세히 알아보면, valid에 실제 첫 번째 당첨번호인 ‘first’ column에 있는 데이터와 예측한 ‘predictions’에 있는 데이터를 비교하면 총 261개의 데이터 중에 19개가 일치하여 약 7.2%의 정확도이다. 

test data와 predictions 간에 서로 일치하는 결과
(test data와 predictions 간에 서로 일치하는 결과)

 

 

[다음번 로또 당첨 번호의 첫자리 예측]

예측 결과 성능이 좋지 않아도 이 훈련된 모델로 다음번 로또 당첨 번호의 첫자리를 예측해 본다.

코드는 아래와 같다.

new_df = df.filter(['first'])
last_60_data = new_df[-60:].values
last_60_data_scaled = scaler.transform(last_60_data)

x_test=[]
x_test.append(last_60_data_scaled)
x_test = np.array(x_test)
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1],1))
pred_data = model.predict(x_test)
pred_data = (scaler.inverse_transform(pred_data))
print(np.around(pred_data))

전체 데이터 샘플에서 다시 첫 번째 column을 'new_df'라는 새로운 변수에 저장하고 끝에서 60개의 데이터를 정규화하고 x_test 데이터로 만든다.

그리고 앞에서 훈련시킨 모델에 입력하여 예측 값을 구하면 예측되는 다음번(1009회 차) 로또 당첨 번호 첫자리가 된다. 

여기서의 결과는 2이며 실제 1009회 차 첫 번째 자릿수는 15였다.

 

결과가 정확하지 않더라도 2부에서는 1회부터 최신 회차의 로또 번호를 다운로드하고 위와 동일한 방식으로 6개 자리 번호를 모두 예측하는 것에 대해 알아보겠다.

 

반응형

댓글