개발



이 글은 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이 가장 많이 나왔습니다.



전체 소스 코드는 아래에 첨부하였습니다.

lotto.py




이것으로 이번 포스트를 마치도록 하겠습니다.


다음 포스트에서는 조금 더 다양한 방법으로 로또 데이터 분석을 시도해 보도록 하겠습니다.



읽어 주셔서 감사합니다.


'개발' 카테고리의 다른 글

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