이 글은 python 초보자들을 대상으로 하는 로또 데이터 분석에 관련된 글입니다.
이전 포스트는 아래 링크를 따라가시기 바랍니다.
2016/06/21 - [개발] - 따라하는 python 로또 분석 (1)
2016/06/28 - [개발] - 따라하는 python 로또 분석(2)
이번 포스트부터는 드디어 제목에 맞게 로또 데이터를 분석해 보도록 하겠습니다.
첫 시간에는 각 숫자의 출현 빈도를 알아보도록 하겠습니다.
뭐, 이거는 컴퓨터 전공이라면 자료구조나 알고리즘 시간에 다들 배우셨을 텐데요,
굳이 설명할 필요가 있나 싶지만 혹시 또 모르니까 진행해 보도록 하겠습니다.
숫자의 출현 빈도를 어떻게 계산할 수 있을까요?
리스트 또는 배열을 이용할 수 있는데요, 간단한 배열을 이용한 방식을 사용해 보도록 하겠습니다.
먼저 1부터 45까지의 배열을 생성합니다.
그리고 데이터베이스에 저장된 각 회차별 당첨번호들을 하나씩 순회하면서 해당 숫자의 배열의 카운트를 하나씩 증가시키면 됩니다.
배열 초기화
인덱스 -> 1 2 3 4 .... 45
데이터 -> | 0 | 0 | 0 | 0 | .... | 0 |
최초의 배열은 위와 같이 모두 0으로 초기화 되어 있습니다.
만약 보너스 번호를 포함한 1회차 당첨 번호가 1, 11, 21, 31, 41, 2, 12 라면,
배열[1] = 배열[1]++, 배열[11] = 배열[11]++... 이런 식으로 증가시켜 주면 됩니다.
요 부분을 코드에 추가시켜 보겠습니다.
수정된 코드는 아래와 같습니다.
# lotto.py
import requests
from bs4 import BeautifulSoup
import MySQLdb
import sys
# 웹 크롤링 한 결과를 저장할 리스트
lotto_list = []
# 로또 웹 사이트의 첫 주소
main_url = "https://www.nlotto.co.kr/lotto645Confirm.do?method=byWin"
# 각 회차별 당첨정보를 알 수 있는 주소
basic_url = "https://www.nlotto.co.kr/lotto645Confirm.do?method=byWin&drwNo="
def getLast():
resp = requests.get(main_url)
soup = BeautifulSoup(resp.text, "lxml")
line = str(soup.find("meta", {"id" : "desc", "name" : "description"})['content'])
begin = line.find(" ")
end = line.find("회")
if begin == -1 or end == -1:
print("not found last lotto number")
exit()
return int(line[begin + 1 : end])
def checkLast():
db = MySQLdb.connect(host="localhost", user="lotto", passwd="lotto", db="lotto")
cursor = db.cursor()
sql = "SELECT MAX(count) FROM data"
try:
cursor.execute(sql)
result = cursor.fetchone()
except:
print(sys.exc_info()[0])
cursor.close()
db.close()
return result[0]
def crawler(fromPos, toPos):
for i in range(fromPos + 1, toPos + 1):
crawler_url = basic_url + str(i)
print("crawler: " + crawler_url)
resp = requests.get(crawler_url)
soup = BeautifulSoup(resp.text, "lxml")
line = str(soup.find("meta", {"id" : "desc", "name" : "description"})['content'])
begin = line.find("당첨번호")
begin = line.find(" ", begin) + 1
end = line.find(".", begin)
numbers = line[begin:end]
begin = line.find("총")
begin = line.find(" ", begin) + 1
end = line.find("명", begin)
persons = line[begin:end]
begin = line.find("당첨금액")
begin = line.find(" ", begin) + 1
end = line.find("원", begin)
amount = line[begin:end]
info = {}
info["회차"] = i
info["번호"] = numbers
info["당첨자"] = persons
info["금액"] = amount
lotto_list.append(info)
def insert():
db = MySQLdb.connect(host="localhost", user="lotto", passwd="lotto", db="lotto")
cursor = db.cursor()
for dic in lotto_list:
count = dic["회차"]
numbers = dic["번호"]
persons = dic["당첨자"]
amounts = dic["금액"]
print("insert to database at " + str(count))
numberlist = str(numbers).split(",")
sql = "INSERT INTO `lotto`. `data`(`count`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `persion`, `amount`) " \
"VALUES('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')" \
% (count,
int(numberlist[0]),
int(numberlist[1]),
int(numberlist[2]),
int(numberlist[3]),
int(numberlist[4]),
int(numberlist[5].split("+")[0]),
int(numberlist[5].split("+")[1]),
int(persons),
str(amounts))
try:
cursor.execute(sql)
db.commit()
except:
print(sys.exc_info()[0])
db.rollback()
break
cursor.close()
db.close()
def analysis(myarray):
db = MySQLdb.connect(host="localhost", user="lotto", passwd="lotto", db="lotto")
cursor = db.cursor()
# 처음 뽑힌 숫자들 전체를 조회
sql = "select `1` from data"
try:
cursor.execute(sql)
results = cursor.fetchall()
# 해당 숫자의 뽑힌 횟수를 하나씩 증가
for row in results:
i = row[0]
count = myarray[i]
myarray[i] = count + 1
except:
print(sys.exc_info()[0])
cursor.close()
db.close()
def main():
last = getLast()
dblast = checkLast()
if dblast < last:
print("최신 회차는 " + str(last) + " 회 이며, 데이터베이스에는 " + str(dblast) + "회 까지 저장되어 있습니다.")
print("업데이트를 시작합니다.")
crawler(dblast, last)
insert()
# 0부터 45까지의 배열을 생성하고 0으로 초기화
myarray = [0 for i in range(46)]
analysis(myarray)
for i in range(1, len(myarray)):
if (i % 10) == 0:
print("")
print("[" + str(i) + ":" + str(myarray[i]) + "]", end=" ")
print()
if __name__ == "__main__":
main()
anaysis() 함수가 추가되었습니다.
myarray라는 0부터 45까지의 배열을 생성하여 0으로 초기화 한 후 analysis 함수에 전달합니다.
위 코드를 실행하면 아래와 같은 결과가 나옵니다.
로또 공식 사이트에서 제공하는 당첨 번호는 정렬된 번호가 아니라 뽑힌 순서별로 되어 있습니다.
그러므로 위의 데이터 분석 결과를 보면,
매 회차 로또에서 첫 번째로 뽑히는 숫자의 출현 빈도는 1이 105번으로 가장 많습니다.
두 번째는 2가 73회의 출현 빈도를 가졌습니다.
이번에는 위를 모든 순서에 적용해서 가장 많이 출현한 숫자대로 정렬을 해 보겠습니다.
즉, 첫 번째 추첨에서 가장 많이 나온 숫자부터 보너스 숫자 추첨에서 가장 많이 나온 숫자까지를 뽑아보도록 하겠습니다.
analysis() 함수에 for 루프만 살짝 추가하면 됩니다. ^^
이렇게 수정된 코드는 아래와 같습니다.
# lotto.py
import requests
from bs4 import BeautifulSoup
import MySQLdb
import sys
# 웹 크롤링 한 결과를 저장할 리스트
lotto_list = []
# 로또 웹 사이트의 첫 주소
main_url = "https://www.nlotto.co.kr/lotto645Confirm.do?method=byWin"
# 각 회차별 당첨정보를 알 수 있는 주소
basic_url = "https://www.nlotto.co.kr/lotto645Confirm.do?method=byWin&drwNo="
def getLast():
resp = requests.get(main_url)
soup = BeautifulSoup(resp.text, "lxml")
line = str(soup.find("meta", {"id": "desc", "name": "description"})['content'])
begin = line.find(" ")
end = line.find("회")
if begin == -1 or end == -1:
print("not found last lotto number")
exit()
return int(line[begin + 1: end])
def checkLast():
db = MySQLdb.connect(host="localhost", user="lotto", passwd="lotto", db="lotto")
cursor = db.cursor()
sql = "SELECT MAX(count) FROM data"
try:
cursor.execute(sql)
result = cursor.fetchone()
except:
print(sys.exc_info()[0])
cursor.close()
db.close()
return result[0]
def crawler(fromPos, toPos):
for i in range(fromPos + 1, toPos + 1):
crawler_url = basic_url + str(i)
print("crawler: " + crawler_url)
resp = requests.get(crawler_url)
soup = BeautifulSoup(resp.text, "lxml")
line = str(soup.find("meta", {"id": "desc", "name": "description"})['content'])
begin = line.find("당첨번호")
begin = line.find(" ", begin) + 1
end = line.find(".", begin)
numbers = line[begin:end]
begin = line.find("총")
begin = line.find(" ", begin) + 1
end = line.find("명", begin)
persons = line[begin:end]
begin = line.find("당첨금액")
begin = line.find(" ", begin) + 1
end = line.find("원", begin)
amount = line[begin:end]
info = {}
info["회차"] = i
info["번호"] = numbers
info["당첨자"] = persons
info["금액"] = amount
lotto_list.append(info)
def insert():
db = MySQLdb.connect(host="localhost", user="lotto", passwd="lotto", db="lotto")
cursor = db.cursor()
for dic in lotto_list:
count = dic["회차"]
numbers = dic["번호"]
persons = dic["당첨자"]
amounts = dic["금액"]
print("insert to database at " + str(count))
numberlist = str(numbers).split(",")
sql = "INSERT INTO `lotto`. `data`(`count`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `persion`, `amount`) " \
"VALUES('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')" \
% (count,
int(numberlist[0]),
int(numberlist[1]),
int(numberlist[2]),
int(numberlist[3]),
int(numberlist[4]),
int(numberlist[5].split("+")[0]),
int(numberlist[5].split("+")[1]),
int(persons),
str(amounts))
try:
cursor.execute(sql)
db.commit()
except:
print(sys.exc_info()[0])
db.rollback()
break
cursor.close()
db.close()
def analysis():
db = MySQLdb.connect(host="localhost", user="lotto", passwd="lotto", db="lotto")
cursor = db.cursor()
for i in range(1, 8):
sql = "select `"
sql += str(i)
sql += "` from data"
try:
cursor.execute(sql)
results = cursor.fetchall()
# 해당 숫자의 뽑힌 횟수를 하나씩 증가
myarray = [0 for i in range(46)]
for row in results:
k = row[0]
count = myarray[k]
myarray[k] = count + 1
print(i, myarray.index(max(myarray)))
except:
print(sys.exc_info()[0])
cursor.close()
db.close()
def main():
last = getLast()
dblast = checkLast()
if dblast < last:
print("최신 회차는 " + str(last) + " 회 이며, 데이터베이스에는 " + str(dblast) + "회 까지 저장되어 있습니다.")
print("업데이트를 시작합니다.")
crawler(dblast, last)
insert()
analysis()
if __name__ == "__main__":
main()
위 코드를 실행하면 아래와 같은 결과를 볼 수 있습니다.
로또 추첨 708회차가 진행되는 동안 첫 번째 자리에 가장 많이 나온 번호는 1, 두 번째 자리에 가장 많이 나온 번호는 8, 세 번째는 20, 순서대로 27, 38, 45 였고, 보너스 번호는 43이 가장 많이 나왔습니다.
전체 소스 코드는 아래에 첨부하였습니다.
이것으로 이번 포스트를 마치도록 하겠습니다.
다음 포스트에서는 조금 더 다양한 방법으로 로또 데이터 분석을 시도해 보도록 하겠습니다.
읽어 주셔서 감사합니다.
'개발' 카테고리의 다른 글
Commands out of sync 문제 (0) | 2017.11.27 |
---|---|
Develop Security Static Code Analyzer (1) (0) | 2017.05.15 |
따라하는 python 로또 분석(4) (0) | 2016.07.11 |
따라하는 python 로또 분석(2) (0) | 2016.06.28 |
따라하는 python 로또 분석 (1) (0) | 2016.06.21 |