Probability and Statistics – Basic

(** 인터넷 익스플로러에서 보면 파이썬 코드 줄이 제대로 적용되어 보이지 않을 수 있습니다.**)

파이썬을 활용하여 확률적 요소를 지닌 프로그램을 작성한다. 주사위 던지기나 동전 던지기에서 그 결과에 대해 시뮬레이션하고 그 결과를 그래프로 보여준다.

먼저 파이썬 random 모듈을 사용하여 주사위 던지기를 시뮬레이션하는 프로그램을 작성한다.

import random

random.choice( [1,2,3,4,5,6] ) 함수는 인자로 주어진 리스트의 원소를 임의로 선택하는 라이브러리이다. 이 함수를 활용하여 주사위 던지고 어떤 숫자가 나오는지 리턴하는 함수 rollDie()를 작성한다.

def rollDie():
    return random.choice([1,2,3,4,5,6])

rollDie()를 몇 차례 반복해서 사용해보자.

>>> rollDie()
1
>>> rollDie()
2
>>> rollDie()
6
>>> rollDie()
4

rollDie()를 확장해서 n번 주사위를 던진 결과를 (문자열로 만들어) 내는 함수 rollN(n)을 작성한다.

def rollN(n):
    result = ''
    for i in range(n):
        result = result + str(rollDie())
    print(result)

rollN() 함수를 두 세 차례 실행해보자. 첫 번째 실행 결과 162415433은 10번 주사위를 던저 첫 번째 숫자는 1, 두 번째 숫자는 6, ... 과 같은 결과를 얻었다고 해석하면 된다.

>>> rollN(10)
1624515433
>>> rollN(5)
21523
>>> rollN(100)
6442456646523663352443661122223244162646646634232355463631422355263526426442455335324655333223323136
>>>

이번에는 동전을 던져 앞과 뒤 어느 쪽이 나오는지 시뮬레이션하는 프로그램을 작성하자.

def flip(numFlips):
    heads = 0.0
    for i in range(numFlips):
        if random.random() < 0.5:
            heads += 1
    return heads/numFlips

flip()함수는 동전을 던질 횟수 numFlips를 인자로 받아 전체 중에 몇 번 앞 면이 나오는지 세어 그 비율을 계산한다. 이때 random.random() 함수는 0과 1 사이의 실수 값을 임의로 반환하는 함수다. 그 랜덤 값이 0.5보다 작으면 동전을 던져 앞 면이 나온 것으로 약속하자.

동전 던지기 횟수를 정하여 이 함수를 사용해보시오.

확률과 통계 과목에서 배운대로 동전 던지는 횟수가 상당히 많으면 그 비율은 0.5와 가까운 값이 되는 것을 이 프로그램을 실행하여 확인할 수 있다.

동전 던기기 시뮬레이션을 한 단계 더 발전시켜보자. flipSim(numFlipsPerTrial, numTrials) 함수는 두 번째 인자 numTrials 만큼 동전 던지기를 시도하고, 각 동전 던지기 시도에 첫 번째 인자 numFlipsPerTrial 회 만큼 동전을 던진다. 즉, flipSim(100, 10)은 100회 동전 던지기를 10번 시도한다. 그 결과로 각 시도의 평균을 계산하여 리턴한다.

def flipSim(numFlipsPerTrial, numTrials):
    fracHeads = []
    for i in range(numTrials):
        fracHeads.append(flip(numFlipsPerTrial))
    mean = sum(fracHeads)/len(fracHeads)
    return mean

flipSim(100,10) 또는 flip(200,1) 등을 실행하고 그 결과를 살펴보시오.

마지막으로 동전 던지기 시뮬레이션 결과를 그래프로 그려보는 파이썬 프로그램을 작성해본다. 이 프로그램은 pylab 모듈을 이용하여 그래프를 그린다. pylab 모듈의 title, xlabel, ylabel 함수로 그래프의 제목, X축 라벨, Y축 라벨을 지정할 수 있다.

def flipPlot(minExp, maxExp):
    ratios = []
    xAxis = []
    for exp in range(minExp, maxExp + 1):
        xAxis.append(2**exp)
    for numFlips in xAxis:
        numHeads = 0
        for n in range(numFlips):
            if random.random() < 0.5:
                numHeads += 1
        numTails = numFlips - numHeads
        ratios.append(numHeads/float(numTails))
    pylab.title('Heads/Tails Ratios')
    pylab.xlabel('Number of Flips')
    pylab.ylabel('#heads/#Tails')
    pylab.plot(xAxis, ratios)

flipPlot()함수를 다음과 같이 사용한다.

>>> import pylab
>>> flipPlot(4,20)
>>> pylab.show()

flipPlot(minExp, maxExp) 함수는 ratios와 xAxis를 각각 비어있는 리스트로 초기화하며 시작한다. xAxis는 X축 값들을 포함하는 리스트로, ratios는 Y축 값들을 포함하는 리스트로 만들려고 한다.

인자로 주어진 minExp와 maxExp는 X축 값을 2^minExp부터 2^maxExp까지 지수를 1씩 증가시키면서 만들려고 받은 최소 지수와 최대 지수이다. 첫 번째 for 반복문에서 xAxis 리스트를 만든다.

두 번째 for 반복문과 중첩된 세 번째 for 반복문에서 각 X축 값들만큼 동전을 던저 앞 면이 나오는 횟수 numHeads를 구하고, 전체 횟수와의 차이에서 뒷 면이 나오는 횟수 numTrails를 구한 다음, 그 비율 numHeads/numTrails를 구한다. 이 것을 Y축 값으로 ratios에 추가한다. 이때 float(...)은 정수 ...을 실수로 변환하는 파이썬 함수이다.

최종적으로 pylab.plot(xAxis, ratios)로 그래프를 그린다. 동전 던지기에서 앞 면이 나오는 횟수와 뒷 면이 나오는 횟수의 비율이므로 많이 반복하면 그 비율은 1에 가까워질 것이다. 이러한 상식을 위 프로그램을 실행하여 나온 그래프로 확인할 수 있다.