data analysis & visualization

딥로또 R 버전

R2020. 2. 10. 00:44

 

얼마전에 로또분석에 관해 김태영님께서 포스팅한 딥러닝 글을 보게되었습니다. 평소에 로또나 주식에 관심이 많았기에 기존 분석방법을 고도화 하고 싶어 김태영님의 코드를 참고하였고, 이를 R버전으로 포스팅해보겠다. 물론 현재 이 외에 다양한 시도를 해보는 중이다. 

참고 : 김태영님의 블로그

 

딥로또 895회

딥러닝 세미나를 하다보면 (특히 RNN이나 LSTM 등 시계열 예측 모델을 설명하다보면) 로또나 주식에 관해 질문을 많이 하십니다. 이와 관련된 질문에는 나름 원칙이 있거나 시계열적 특성이나 인과관계가 있는 데이터에만 예측이 잘될꺼라도 말씀은 드리긴 하지만 신통치 않은 답변인지 만족하시질 못 합니다. 그래서 먼저 딥러닝으로 로또를 하면 안된다는 것을 몸소 보여드리기 위해 매주 테스트를 해볼 예정입니다. 들어가기에 앞서 몇가지 말씀드리겠습니다. 로또 같은

tykimos.github.io

로또 자료 생성

로또 자료 생성의 경우 멀티 코어를 활용하였다. 또한 패키지 로드가 귀찮아 만들었던 개인 패키지를 활용하였다.

 

library(devtools)
if(!require(lotto))install_github('qkdrk777777/lotto')
if(!require(DUcj))install_github('qkdrk777777/DUcj')
# 개인 패키지
library(DUcj)
# DUcj::package 는 if(!require(패키지))install.packages('패키지')를 동시에 진행해주는 함수
package('progress')
package('XML')
package('stringr')
package('rvest')
package(parallel)
package(foreach)
package(rvest)
package(xml2)

url<-'https://search.naver.com/search.naver?sm=tab_hty.top&where=nexearch&query=%EB%A1%9C%EB%98%90&oquery=%EB%A1%9C%EB%98%90&tqi=TmrKidpVuFdsssc0EvVssssssUd-075322'
line<-read_html(url,encoding="UTF-8")
p1<-html_nodes(line,css='._lotto-btn-current em')%>%html_text()
last=as.numeric(substr(p1,1,3))
last

spec=detectCores()
spec
cl=makeCluster(spec)
data=NULL
try({url<-paste0('https://search.naver.com/search.naver?sm=tab_drt&where=nexearch&query=',last:1,'%ED%9A%8C%EB%A1%9C%EB%98%90')
c=data.frame(t(parApply(cl,MARGIN=1,data.frame(url),function(x){
  (as.numeric(strsplit(stringr::str_trim(
    rvest::html_text(rvest::html_nodes(xml2::read_html(x,encoding='UTF-8'),css='.num_box'))),split=' ')[[1]][1:6]))})))
data=cbind(num=last:1,c)},silent = T)

stopCluster(cl)
Sys.sleep(3)
# 멀티코어로 크롤링을 실패한 경우 다음과 같이 진행
if(is.null(data)){

  url<-paste0('https://search.naver.com/search.naver?sm=tab_drt&where=nexearch&query=',last:1,'%ED%9A%8C%EB%A1%9C%EB%98%90')  
  data=NULL;t=0
  
  for( i in url){t=t+1
  data=rbind(data,data.frame(num=(last:1)[t],t(as.numeric(strsplit(stringr::str_trim(
    rvest::html_text(rvest::html_nodes(xml2::read_html(i,encoding = 'UTF-8'),css='.num_box'))),split=' ')[[1]][1:6]))))
  message(t/last*100)
}
}

 

분석용 데이터 생성

library(plyr)
rm(list=setdiff(ls(),c('data','data2')))
data2<-matrix(0,ncol=45,nrow=nrow(data));colnames(data2)=1:45

for(i in 1:nrow(data2)){
  for(j in 2:7){
    for(k in 1:45){
      if(data[i,j]==k)data2[i,k]<-1}}}
rownames(data2)<-nrow(data2):1

library(keras)
library(tensorflow)
library(reticulate)
delete=data2
train=data.matrix(delete[-1,])
train=array(train,dim=c(1,nrow(train),ncol(train)))
target=data.matrix(delete[-nrow(data),])

 모델 생성

model=keras_model_sequential()%>%
  layer_cudnn_lstm(units=128,batch_input_shape=c(1,1,dim(train)[3]),return_sequences = F,stateful = T)%>%
  layer_dense(units=45,activation = 'sigmoid')
model %>% compile(
  optimizer = "adam",
  loss = 'binary_crossentropy')
M_train_loss=c()
M_val_loss=c()
for(epoch in 1:150){
  model$reset_states()
  train_loss=c()
  
for (i in 1:700){
  xs=train[,i,,drop=F]
  ys=target[i,,drop=F]
  train_loss=c(loss,model$train_on_batch(xs,ys))}
val_loss=c()
for( i in 700:800){
  xs=train[,i,,drop=F]
  ys=target[i,,drop=F]
  val_loss=c(loss,model$test_on_batch(xs,ys))}
M_train_loss=c(M_train_loss,mean(train_loss))
M_val_loss=c(M_val_loss,mean(val_loss))
print(epoch)
}
matplot(cbind(M_train_loss,M_val_loss),type='l')

ls=list()
for(i in 1:800){
source('./MC_test.R')
}
ls1=ls

ls=list()
for(i in (800:(nrow(data)-1))){
  source('./MC_test.R')
}
ls2=ls
table(rep(names(unlist(ls1)),unlist(ls1)))
table(rep(names(unlist(ls2)),unlist(ls2)))

i=dim(train)[2]
ball_list=c()
for(j in 1:10){
  xs=train[,i,,drop=F]
  pred=model$predict_on_batch(xs)
  
  ball_box=rep(1:45,as.integer(pred*100+1))
  selected_balls=c()
  
  while(T){
    if (length(selected_balls)==6) break
    ball=sample(ball_box,1)
    if (!(ball %in% selected_balls))  selected_balls=c(selected_balls,ball)
  }
  ball_list=rbind(ball_list,sort(selected_balls))
}

source 코드로 사용된 MC_test.R 코드 

검증 코드는 편의상 2등을 생략하였는데 크롤링으로 데이터 생성할 때부터 보너스번호를 고려하여 짜면 될거 같다.

rank=c()
for(j in 1:10){
  xs=train[,i,,drop=F]
  pred=model$predict_on_batch(xs)
  
  ball_box=rep(1:45,as.integer(pred*100+1))
  selected_balls=c()
  
  while(T){
    if (length(selected_balls)==6) break
    ball=sample(ball_box,1)
    if (!(ball %in% selected_balls))  selected_balls=c(selected_balls,ball)
  }
  selected_balls
  
  temp=length(intersect(selected_balls,data[i+1,-1]))
  rank=c(rank,ifelse(temp==6,'1등',ifelse(temp==5,'3등',ifelse(temp==4,'4등',ifelse(temp==3,'5등',NA)))))
}
# print(i)
ls[[i]]=table(rank)

 

참고 : loss function 을 커스터마이징하여 분석을 진행할때 활용한 코드

lossfunction <- function(y, t) {
  k_binary_crossentropy(y,t)
}

model %>% compile(
  optimizer = "adam",
  loss = function(y_true, y_pred)
    lossfunction(y_true, y_pred)
)