Data Science!/이론

[수학] 파이썬으로 배워보는 확률 - 1 편 (난이도 : 하)

양국남자 2021. 9. 9. 01:44

모든 수업은 파이썬 (Python 3 이상) 으로 진행됩니다. Pycharm 등 IDE 사용도 좋지만, Jupyter Notebook 이나 Google Colab 사용을 더욱 권장드립니다. Google Colab 에 있는 전체 컴필레이션은 확률편 마지막 강의에 올릴 예정입니다.

 

왜 확률을 배워야 하나요?

 

머신 러닝이니, 데이터 사이언스니 하는 머리아픈 일 들어가기 전에 잠깐 기본적인 이야기 좀 할게요. 인공지능도 사람이 만든 것, 결국 사람의 의사결정 구조를 본딴 거에 불과합니다. 

 

잠깐 생각해 봅시다. 우리가 어떻게 의사결정을 내리나요?

 

여러분 앞에 이렇게 생긴 강아지가 나타났다고 가정해봅시다.

 

화이트 포메라니안 내지 폼피츠죠

얘가 포메라니안인지, 말티즈인지, 스피츠인지, 사모예드인지, 스키퍼키인지 처음 보는 사람은 잘 모릅니다. 하지만 강아지를 많이 봐온 사람이라면 "쟤 루퐁이네 나오는 애 닮았는데 포메라니안 아냐?" 하는 식으로 판단을 내릴 수 있습니다. 우리의 생각 프로세스를 나타내자면 "포메라니안 - 70%, 폼피츠 - 25%, 스피츠 3%, 새끼 사모예드 - 2.5%, 기타 - 1%미만" 이런 식으로 판단을 내리게 됩니다.

 

머신 러닝이란 것도 사실 확률을 기반으로 한 겁니다. 수많은 강아지 사진을 학습시켜서 컴퓨터에게 판별능력을 갖추게 하는데, 그 과정에 쓰이는게 머신러닝이니 인공신경망이니 딥러닝이니 하는 기법들입니다. 

 

그러므로 머신러닝에 대한 이해를 키우려면, 기본 확률부터 짚고 넘어가야 합니다. 

 

 

확률에 필요한 개념

 

확률론의 아버지인 프랑스 수학자 라플라스는 확률을 이렇게 정의했습니다. (from 위키백과)

 

사건에 대한 확률은 이 사건 중 어느 하나가 다른 사건보다 더 많이 발생하여 우리에게 동등하게 가능할 것이라고 기대하지 않을 때 가능한 모든 사건의 수에 대해 유리한 사건의 수의 비율입니다.

 

확률을 이해하기 위해서는 다음과 같은 단어들을 이해해야 합니다.

 

Trial (시행) - 몇 번 실험을 실행하는지에 대한 횟수입니다. 주사위로 말하자면, 몇 번 주사위를 던지는가입니다.

 

Outcome (결과) - 실험에 대한 결과입니다. 주사위를 던져 나온 눈의 숫자입니다.

 

Sample Space (표본 공간) - 실험의 결과에 대한 전체 집합입니다. 주사위를 예시로 놓는다면 {1,2,3,4,5,6} 이 되겠죠.

 

Event (사건) - 표본 공간 내에서 일어나는 특정한 조건을 만족하는 결과입니다. '홀수' 라고 하면 {1,3,5} 가 될겁니다.

 

Probability (확률) - 라플라스 말을 조금 빌리자면, '유리한 사건' 의 비율입니다. 즉, 우리가 원하는 일이 일어날 비율이란 말이죠. "주사위에서 홀수가 나올 확률" 이라고 하면 총 6가지 중 3가지니까 50%가 되네요.

 

from fractions import Fraction #파이썬에서 유리수 계산을 위해서 임포트 해줍니다. 

def P(event, space): #표본공간에서 일어나는 사건의 확률이라는 정의에 맞게 로직을 짯습니다.
    return Fraction(cases(favorable(event, space)), 
                    cases(space))

favorable = set.intersection # 원하는 사건은 당연히 표본공간과 그 사건의 교집합입니다. 즉 event 와 space 의 교집합입니다.
cases     = len              # 당연하지만, 케이스의 수는 표본공간의 총 길이입니다. 표본공간에 원소가 6개 있으면 6이 되는거처럼요.

중고등학교 수학책에서부터 확률 하면 주사위였죠! 주사위 하면 확률이고요!

 

주사위 굴리기

 

예나 지금이나 확률 하면 주사위니까, '라플라스의 정의에 기반해서' 파이썬으로 간단한 주사위 시뮬레이션을 짜 봅시다.

 

# 주사위를 굴리면 짝수 눈이 나올 확률
D     = {1, 2, 3, 4, 5, 6} # 표본공간입니다. 주사위를 던질때 생길 수 있는 모든 결과죠.
even  = {   2,    4,    6} # 모든 짝수 결과입니다.

P(even, D)

 

위 코드를 응용한다면 주사위 외에도 다른 확률도 할 수 있습니다. 예를 들면 소수라던가요.

 

prime = {2, 3, 5, 7, 11, 13} #소수인 숫자
odd   = {1, 3, 5, 7, 9, 11, 13} #홀수인 숫자

P((even | prime), D) # 주사위 눈 중에서 짝수나 소수가 나올 확률
#결과 : Fraction(5,6) 2,3,4,5,6 으로 5/6 입니다

P((odd & prime), D) # 소수이자 홀수인 숫자가 주사위 던져서 나올 확률
#결과 : Fraction(1,3) 3,5 로 1/3 입니다

 

너무 쉬우니까, 이번에는 트럼프 카드로 가봅시다. 

 

당신 말고 카드 말이에요...

#조커는 제외했습니다.
suits = u'♥♠♦♣' #하트, 스페이드, 다이아, 클럽
ranks = u'AKQJT98765432' #2에서 에이스까지 모든 숫자입니다.10은 T로 표현했습니다.
deck  = [r + s for r in ranks for s in suits] #for 루프를 사용해서 모든 숫자당 모든 슈트를 붙인 배열을 만들었습니다.
len(deck) #갯수. 52장입니다. 당연하지만.

이렇게 덱을 만들었습니다.

 

덱을 만들었으니, 카드를 뽑아봐야죠.

import itertools # itertools 는 루핑을 위한 아이터레이터(반복기) 를 만드는 파이썬 내부 함수입니다.

def combos(items, n):
    #n 개의 items 를 가지고 만들어지는 모든 조합들을 공백으로 분리된 스트링으로 만드는 함수입니다.
    return set(map(' '.join, itertools.combinations(items, n)))

Hands = combos(deck, 5)
#덱에서 5개의 카드를 뽑아 만들 수 있는 모든 카드패의 경우의 수

len(Hands)
#딱 봐도 52C5, 또는 52에서 5 뽑는 조합 입니다. 2598960이 나올겁니다.

포커를 좋아하시는 분들이라면, 한번 플러시(같은 슈트의 카드 5장)나 포 오브 어 카인드 (같은 숫자 4개) 가 나올 확률을 계산하는 함수를 짜보는건 어떨까요?

 

실제로 포 오브 어 카인드가 플러시보다 강하다고 나와 있네요. 그렇다면 플러시가 더 자주 일어난다는건데, 과연 포커는 과학적으로 공평한 게임일까요?

 

flush = {hand for hand in Hands if any(hand.count(suit) == 5 for suit in suits)}
#플러시

P(flush, Hands)
#Fraction(33, 16660) 이 나올 겁니다.


four_kind = {hand for hand in Hands if any(hand.count(rank) == 4 for rank in ranks)}
#포 오브 어 카인드

P(four_kind, Hands)
#Fraction(1, 4165) 이 나옵니다.

플러시 확률 33/16660, 포 오브 어 카인드 1/4165로 포 오브 어 카인드가 훨씬 더 어려운 패이고, 당연히 포커에서 더 높은 점수를 따야 한다는게 확률적으로 증명되었습니다.

 

오늘은 초등학교 고학년이나 중학생이어도 무난하게 따라오실 수 있는 확률 강의로 마무리 짓겠습니다.

 

다음 강의에는 비등가 확률(모든 사건의 발생 확률이 균등하지 않음.. 조작된 주사위를 생각해보면 어떨까요?)과 사전조건(짝수란 xx다 같은 조건) 을 파이썬으로 구현해보는 시간을 가져보겠습니다. 비등가 확률같은 경우에는 머신러닝에서 자주 사용되는 베이지언 추론에 자주 활용되거든요.