Python

Python : 확률 이항 검정

Sorting 2021. 4. 11. 01:53
반응형

* 입문책을 읽고 정리한 내용으로, 전공자가 아니어서 잘못된 내용이 있을 수 있습니다.

* 잘못된 내용이 있다면 말씀 부탁 드립니다.

 

 

확률 시행의 결과가 정상인지 검증하기 위한 방법 중 가장 간단한 방법인 

이항검정에 대해 간단히 정리해보고자 한다.

 

내용은 통계학초입문 책을 참고했다.

book.naver.com/bookdb/book_detail.nhn?bid=15872446

 

통계학 초 입문

‘통계학’이 뭐지?― ‘돈’과 ‘노동력’의 낭비를 막는다! 통계학은 예부터 우리 실생활 곳곳에서 활용된다.젊은 세대가 앞으로 ‘무엇을 배워야 하느냐’고 묻는다면 저자는 다음 3가지를

book.naver.com

 

베르누이 시행의 횟수가 충분할 경우, 그 결과는 정규 분포를 따른다.

정규분포를 따를 경우, 해당 확률분포는 다음과 같은 규칙을 따른다.

 

1. 평균과 표준편차를 구할 수 있다.

2. 시행을 n번 반복했을 때 "성공"이 나올 횟수는, 평균-표준편차 ~ 평균+표준편차 범위 사이에 들어갈 확률이 68%,

   평균-2*표준편차 ~ 평균+2*표준편차 범위 사이에 들어갈 확률이 95% 이다. 

ko.wikipedia.org/wiki/68-95-99.7_%EA%B7%9C%EC%B9%99

 

68-95-99.7 규칙 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 어두운 파란색은 평균에서 1표준편차 이내이다. 이는 정규 분포에서 전체 중 68.27%를 차지한다. 2표준편차 범위(중간색과 어두운색)는 95.45%를 차지한다. 3표준편

ko.wikipedia.org

 

위 특징을 이용하면, 베르누이 시행의 결과를 검정할 수 있다.

시행의 결과가 95% 신뢰구간 안에 들어가는지 보면 되는 것이다.

이제 평균과 표준편차만 구하면 된다.

 

이항분포에서는 성공 확률이 p인 시행을 n회 반복했을 때,

나올 성공 횟수의 평균은 np 이고,

그리고 그 분포는 np(p - 1) 이다.

표준편차는 분포에 제곱근을 취하면 구할 수 있으므로,

$$\sqrt{np(p-1)}$$

이다.

 

이제 이것을 파이썬 코드로 구현해보자.

 


 

# 시행횟수 10000
# 성공 확률 1%

n = 10000
p = 1 / 100
q = 1 - p

E = n * p
print("평균(기댓값)", E)

Var = E * q
print("분산", Var)

SD= pow(Var, 0.5)
print("표준편차", SD)

print("약 68% 구간 : ", E - SD, E + SD)

beg = E - 2 * SD
end = E + 2 * SD 
print("약 95% 구간 : ", beg, end)

위 코드의 수행 결과는 다음과 같다.

평균(기댓값) 100.0
분산 99.0
표준편차 9.9498743710662
약 68% 구간 :  90.0501256289338 109.9498743710662
약 95% 구간 :  80.1002512578676 119.8997487421324

 


이제 랜덤함수를 이용해, 실제로 베르누이 시행 결과의 95%가 

beg(80.1) 과 end(119.8) 사이에 들어가는지 확인해보자.

 

p = random(1/p) 의 결과가 0이 나올 확률과 같다.

random(1/p)를 n번 수행했을 때, 0이 몇번 나왔는지를 카운팅하면 되겠다.

이 테스트를 수없이 많이 수행하면 

약 95%의 결과가 beg 과 end 사이에 들어가야 한다.

 

단, 시행의 결과가 정수(성공이 몇번 나왔는지)로 나오므로,

결과를 수집할 때 정수로만 수집할 수 있어 약간의 오차가 발생하게 된다.

 

import random

# 실제로 테스트해보자. 
# 진짜 시행의 95%가 beg, end 사이에 들어가는가?

# 몇번 성공했는지 결과를 수집한다.
result = {}
m = 1 / p
for _ in range(10000): # n=10000 인 테스트를 10000번 수행한다.
    count = 0
    for _ in range(n):
        if random.randrange(m) == 0:
            count += 1
            
    if count in result:
        result[count] += 1
    else:
        result[count] = 1
print(result)

이제 수행 결과가 result 딕셔너리에 저장되어 있다.

 

l = sorted(result.items())
keys = [e[0] for e in l]
values = [e[1] for e in l]

rngMin = round(beg) # 수집결과에서 정수 하나를 제외하면 오차가 너무 심하므로
rngMax = round(end) # 반올림한 값을 사용하여 집계

a = [result[e] for e in range(rngMin, rngMax)]
print(sum(a) / sum(values) * 100) # 95.54

나는 95.54% 라는 결과가 나왔다.

어느정도 결과가 들어맞는 것으로 보인다.

총 테스트의 약 95%가 beg, end 사이임을 확인했다.

 

내친김에 테스트 결과를 그래프로도 한번 그려보자

import matplotlib.pyplot as plt
plt.plot(keys, values)

 

테스트를 10000번만 반복해서 그래프가 조금 들쭉날쭉하지만,

어느정도 정규분포 느낌은 난다.

 

횟수를 매우 많이 반복하면 정규분포에 근사한 그래프가 나오게 된다.

 

 

반응형