7.2. 유의성 검정#

import pandas as pd
import numpy as np
import seaborn as sns

7.2.1. 달인의 기준#

TV 프로그램 중 생활의 달인을 보면 보통 사람들이 가질 수 없는 특별한 능력을 가진 사람들이 있습니다. 특히 공장에서 불량품을 검수하시는 분들의 능력을 보면 우리가 깜짝 놀랄만한 특별한 능력 을 보여줍니다.

이제 우리는 “생활의 달인”과 “보통 사람”을 구별할 수 있는 기준에 대하여 생각해 봅시다. 생활의 달인 프로그램을 보면 마지막에 다양한 형태의 “실험”을 통하여 달인의 능력을 검증하기도 합니다. 주어진 제품의 모양을 숨기기 위하여 눈을 가리는 등 공정한 조건에서 실험을 하는 노력을 합니다.

통계학의 아버지라고 불리는 R. A. Fisher 는 20세기 초반에 영국의 Rothamsted 에 있는 농업연구소에서 근대 통계학의 근간이 되는 중요한 개념을 정립한 통계학자이자 유전학자입니다.

Fisher가 근무하는 연구소에도 생활의 달인 임을 주장하는 사람이 있었습니다. 연구소에 근무하는 부인이 자신은 우유를 넣은 차(milk tea)를 마셔보면 우유를 먼저 컵에 따랐는지, 차를 먼저 따랐는지 구별할 수 있다고 주장했습니다. 이에 Fisher 는 작은 실험을 준비하여 부인의 눙력을 검증하자고 제안합니다. 실험은 다음과 같습니다.

  • 8개의 컵을 준비하고 4잔은 우유를 먼저 따르고, 나머지 4잔은 차를 먼저 따른다.

  • 차와 우유가 잔에 따라진 순서를 모르게 하여 부인에게 우유를 먼저 따른 4잔을 선택하게 한다.

후에 전해진 실험의 결과 에 의하면 부인은 우유를 먼저 따른 4잔을 정확하게 선택했다고 합니다.

여러분은 이 부인을 생활의 달인이라고 인정할 수 있나요? 즉 실험의 결과가 부인이 특별한 능력을 가졌다는 충분한 근거가 있는 것인가요?

만약 8잔이 아니라 100잔을 가지고 실험했을 때 우유를 먼저 따른 50잔을 모두 맞추었다면 우리는 이 부인이 생활의 달인이라는데 이견이 없을 겁니다. 하지만 달인도 실수는 할 수 있습니다 (TV 프로그램에도 까끔 달인분들이 실수하지요). 만약 48잔을 맞추고 2잔은 틀렸다면 이는 달인의 기준에 드는 걸까요? 만약 45잔을 맞추고 5잔은 틀렸다면 어떻게 판단할까요?

7.2.2. Fisher의 생각#

사람들은 동일한 실험 결과를 보고 다른 의사 결정을 할 수 있습니다. 만약 만약 45잔을 맞추고 5잔은 틀렸을 때, 어떤 사람들은 부인의 능력을 충분히 보여주었다고 주장할 수 있지만 어떤 사람들은 50잔을 모두 맞추어야 달인의 자격이 있다고 주장할 수 있습니다.

이렇게 같은 증거에 대하여 사람들의 의사결정이 다를 수 있는 이유는 “달인의 능력”에 대한 기준이 다르기 때문입니다. 사람들마다 생각하는 달인의 기준이 다르다면 동일한 데이터를 가지고 서로 다른 의사결정을 할 수 밖에 없습니다.

수집한 데이터의 정보가 “달인의 기준”에 얼마나 가까이 있는가?

Fisher는 의사 결정에서 주관성을 제거하기 위하여 “달인이 가진 능력” 이 아닌 “보통 사람이 가진 능력” 으로 판단의 기준을 바꿉니다.

수집한 데이터의 정보가 “보통 사람의 기준”에서 얼마나 멀리 있는가?

Fisher 가 제시한 판단의 기준이 되는 보통 사람의 능력은 많은 경우 객관적으로 정의될 수 있습니다. 보통 사람인 여러분들은 8개의 잔 중 우유를 먼저 따른 잔 4개를 선택하라고 하면 어떻게 선택할 것입니까? 필자도 한 번 시도해았지만 우리의 능력으로는 도저히 맛을 보고 선택할 수 없습니다. 따라서 여러분은 답에 대하여 전혀 힌트가 없는 경우 4지선다형 문제를 풀때 처럼 임의로 4잔을 선택(randomly selected) 할 수 밖에 없습니다. 즉 보통 사람의 능력은 선택을 임의로 하는 것입니다.

보통 사람인 여러분이 차부인(tea lady)의 실험에 참가해서 우유를 먼저 따른 4잔을 정확하게 선택한다면 여러분은 아마도 깜짝 놀랄 것입니다. 왜냐하면 보통 사람이 가진 능력의 기준으로는 매우 일어나기 힘든 일이 벌어졌기 때문입니다.

이렇게 Fisher는 다음과 같은 의사결정의 방법을 제시했습니다. 이러한 방법을 Fisher의 유의성 검정(significnace test) 라고 합니다.

보통 사람이 가진 능력을 기준으로 매우 일어나기 힘든 결과를 얻었다면, 그 결과는 보통 사람에 의한 것이 아니라 달인의 능력이라고 판단하자!!

7.2.3. 유의성 검정#

그럼 Fihser 가 생각하는 “보통 사람이 가진 능력으로는 매우 일어나기 힘든 결과가 일어났다” 를 판단하는 기준은 무었일까요?

차부인(tea lady)의 실험에서 보통 사람이 임의로 4잔을 선택 한다면 차부인이 보여준 4잔을 모두 맞추는 가능성이 얼마나 될까요?

보통 사람이 8개의 잔에서 임의로 4잔을 선택하는 경우의 수는 모두 70개입니다. 임의로 선택하였기 때문에 70 개의 경우는 모두 같은 가능성(equally likely)을 가집니다.

\[ {{8}\choose{4}} = \frac{(8)(7)(6)(5)}{(4)(3)(2)(1)} =70 \]

이때 차부인이 보여준 4잔을 모두 맞추는 경우는 딱 1가지 입니다. 8개의 잔에서 4개를 임의로 선택할 때 우유를 먼저 따른 4개를 제대로 선택할 경우의 수는 마치 여러분이 상자에 하얀 공 4개외 검은 공 4개가 들어있는 경우, 4개를 임의로 선택할 때 하얀 공 4개를 선택하는 경우의 수와 같습니다.

\[ {{4}\choose{4}} {{4}\choose{0}} = 1 \]

따라서 보통 사람이 가진 능력을 기준으로 4잔을 모두 맞추는 가능성을 확률로 나타내면 \(1/70\) 입니다.

\[ p-value = \frac{1}{70} = 0.0143 \]

Fisher 의 논리는 보통 사람이 가진 능력을 기준으로 실험의 결과가 나타날 확률, 즉 4잔을 모두 맞출 확률을 p-값(p-value) 으로 부르며 이 p-값이 미리 정한 수준보다 작으면 달인으로 인정하자는 것입니다.

유의성 검정에서 판단에 사용하는 수준을 유의수준(significnace level) 이라고 부르며 우리는 통상적으로 5%, 즉 확률 0.05 를 사용하고 있습니다. 보통 사람의 기준으로 깜짝 놀랄 일이 벌어지는 가능성의 기준이 바로 유의수준입니다.

Fisher 가 가정한 “차부인은 보통 사람이다” 라는 가설을 우리는 일반적으로 귀무가설(null hypothesis) 라고 부릅니다. 즉, 차부인의 주장과는 반대되는 가설이며 이는 우리와 Fisher가 자연스럽게 차부인의 주장을 의심하면서 가지는 생각을 나타냅니다. p-값이 유의수준보다 작으면 귀무가설을 기각(reject)한다고 말하며 이는 귀무가성을 포기하고 달인으로 인전한다는 의미입니다.

차부인 실험에 Fisher 의 유의성 검정을 적용하는 절차는 다음과 같습니다.

유의성 검정의 순서

차부인 실험

귀무가설을 세운다

차부인은 보통 사람이다

실험을 실시하여 데이터를 얻는다

8잔 중 우유를 먼저 따른 4잔을 정확하게 선택

귀무가설 하에서 결과 데이터가 관측되는 p-값을 계산한다

p-값은 1/70 =0.0143

p-값과 유의수준 5% 를 비교한다

p-값=0.0143 < 0.05

귀무가설을 기각한다.

차부인은 보통 사람이 아니다, 즉 생활의 달인이다

7.2.4. p-값의 계산#

이제 여러분들이 차부인 실험과 동일한 실험을 실시해서 우유를 먼저 따른 4개의 잔 중에서 3개를 제대로 선택하고 나머지 1개를 잘못 선택하였다고 합시다.

이러한 경우 p-값은 어떻게 계산할까요?

우유를 먼저 따른 4개의 잔 중에서 3개를 제대로 선택하고 나머지 1개를 잘못 선택할 경우의 수는 상자에 하얀 공 4개와 검은 공 4개가 들어있는 경우, 4개를 임의로 선택할 때 하얀 공 3개와 검은 공 1개를 선택하는 경우의 수와 같습니다. 즉

\[ {{4}\choose{3}} {{4}\choose{1}} = (4)(4) = 16 \]

하얀 공 3개와 검은 공 1개를 선택하는 확률은 \(16/70=0.2286\)입니다.

\[ \frac{16}{70} = 0.2286 \]

우유를 먼저 따른 4개의 잔 중에서 3개를 제대로 선택하고 나머지 1개를 잘못 선택한 경우 p-값을 계산하는 방법은 다음과 같습니다.

\[ p-value = P ( \text{실험에서 얻은 결과 또는} \text{더 극단적인 결과들}) \]

즉, 이 경우 p-값은 실험에서 얻은 결과(3개를 제대로 선택하고 나머지 1개를 잘못 선택한 사건)의 확률에 이 보다 더 극단적인 결과들(더 놀랄 사건들, 즉 4개를 모두 제대로 선택한 사건)의 확률을 더해서 구하게 됩니다.

\[ p-value = \frac{16 + 1}{70} =0.2428 \]

이 경우 p-값이 5% 보다 크기 때문에 귀무가설을 기각하지 못합니다. 즉, 4개 중에서 3개만 제대로 선택하는 경우는 달인이라고 할 수 없다는 것입니다.

4개 중에서 3개만 제대로 선택하는 경우 Fisher 의 유의성 검정을 적용하는 절차는 다음과 같습니다.

유의성 검정의 순서

차부인 실험

귀무가설을 세운다

이용희는 보통 사람이다

실험을 실시하여 데이터를 얻는다

먼저 따른 3잔을 제대로 선택하고 나머지 1잔은 잘 못 선택

귀무가설 하에서 결과 데이터가 관측되는 p-값을 계산한다

p-값은 17/70 =0.2428

p-값과 유의수준 5% 를 비교한다

p-값=0.2428 > 0.05

귀무가설을 기각하지 못한다.

이용희는 보통 사람이다

7.2.5. 예제: 모의실험을 통한 p-값의 근사#

7.2.5.1. 차부인 실험의 확장#

20개의 잔 중 10잔은 우유를 먼저 따르고, 나머지 10잔은 차를 먼저 따랐다. 친구가 우유를 따른 잔 10개중 8개를 제대로 선택하였다고 하자. 친구는 달인인가?

먼저 p-값을 이론적으로 구하려면 다음과 같이 구할 수 있다.

\[\begin{split} \begin{align*} p-value & = P( \text{잔 8개를 제대로 선택한 사건 또는 더 극단적인 사건들}) \\ & = P( \text{잔 8개를 제대로 선택한 사건} ) + P( \text{잔 9개 제대로 선택한 사건}) + P( \text{잔 10개 제대로 선택한 사건}) \\ & = \frac{ {{10}\choose{8}} {{10}\choose{2}} } {{20}\choose{10}} + \frac{ {{10}\choose{9}} {{10}\choose{1}} } { {20}\choose{10} } + \frac{ {{10}\choose{10}} {{10}\choose{0}} } { {20}\choose{10} } \end{align*} \end{split}\]

물론 위의 계산을 정확하게 구할 수도 있겠지만 모의실험을 통해서 근사적으로 구할 수 있다. 앞 장에서 지지율에 대한 모의실험을 한 것 처럼, 각각 10개의 0과 1로 구성된 20개의 자료에서 10개를 비복원으로 추출하는 모의실험을 반복적으로 수행하여 위의 확률을 근사적으로 구해보자.

n_cups = 20
n_cups_milk_first = 10
# 1 =우유 먼저, 0=차 먼저
CUPS = np.concatenate((np.ones(n_cups_milk_first), np.zeros(n_cups - n_cups_milk_first)), axis=0)
CUPS
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0.])
# 아래 모의실험은 시간이 7-8초 소요된다.

# 모의실험의 횟수
B = 100000 

# 실험에서 얻은 결과 
observed_val = 8

## 먼저 우유를 넣은 잔을 제대로 선택한 개수를 저장할 데이터프레임
milk_estimate = pd.DataFrame({'milk':np.zeros(B)})

## 모의실험 : 비복원추출에 유의
for i in np.arange(B):
  sample_milk = np.random.choice(CUPS, n_cups_milk_first, replace=False)
  milk_estimate.loc[i,'milk'] = np.sum(sample_milk)
milk_estimate.head(5)
milk
0 5.0
1 5.0
2 6.0
3 3.0
4 6.0
# 관측한 결과 또는 더 극단적인 사건의 개수
a, b = milk_estimate.loc[milk_estimate.milk >= observed_val ].shape
a
1127
# 모의실험에 의한 p-값의 근사 
pvalue = a/B
pvalue
0.01127

위에서 근사적으로 구한 p-값이 유의수준 5%, 즉 \(0.05\) 보다 작으므로 친구가 우유를 먼저 넣은 잔을 구별하는 능력이 있다고 판단한다.

7.2.5.2. 쇼핑몰 알고리즘의 개선#

다른 예제를 생각해 보자.

온라인 쇼핑몰을 운영하는 회사가 2020년 매달에 임의로 1000명의 고객에 대하여 접속 기록을 분석하여 접속 후 장바구니에 상품을 저장했던 고객이 평균적으로 540명인 것을 알고있다. 2021년 1월부터 고객이 장바구니를 선택하는 절차를 개선한 알고리즘을 새롭게 개발하고 온라인 쇼핑몰의 운용에 적용하였다.

2021년 1월부터 10월까지 매월 임의로 1000명의 고객에 대하여 접속 기록을 분석하여 접속 후 장바구니에 상품을 저장했던 평균 고객 수가 620 명으로 늘어난 사실을 확인하였다. 쇼핑몰의 알고리즘 개선 후 늘어난 장바구니 사용 회수가 유의한 증가(significant increase)인지 아닌지 판단해보자.

참고로 여러분이 온라인 쇼핑몰을 이용해 보았다면 장버구니에 상품을 저장했더라고 구매를 하지 않는 경우도 많다는 것에 유의하자. 하지만 관심있는 상품을 장바구니에 담기 쉽고 장바구니 안에서 선택한 상품들의 관리와 선택이 편리하다면 구매로 이어질 가능성이 클 것이다.

일단 기존의 알고리즘에 의한 장바구니 평균 이용율은 54%이다.

\[ \frac{540}{1000} = 0.54 \]

장바구니를 이용한 평균적인 이용률이 54% 인 것을 가정하고 1명의 고객이 장바구니를 이용할 확률 \(p\) 가 0.54 로 하는 귀무가설을 고려하자.

\[ \text{귀무가설: } p= 0.54 \]

이제 귀무가설이 참인 경우, 즉 \(p=0.54\) 인 경우 1000명의 고객이 장바구니를 이용하는 횟수 \(X\) 에 대한 분포를 생각해 보자. 이제 한 명의 고객이 장바구니를 이용할 \(0.54\) 이며 고객들 간에 행동이 서로 관련이 없다고 가정하면, 장바구니를 이용하는 횟수 \(X\)의 분포는 앞면이 나올 확률이 0.54 인 동전을 독립적으로 1000번 던질 때 앞면의 나오는 횟수의 분포와 동일하다.

이렇게 성공의 확률이 \(p\)인 사건을 \(n\) 번 독립적으로 시행할 때 나타나는 성공의 횟수 \(X\)의 분포는 이항분포(Binomial distribution)을 따른다고 한다.

\[ X \sim Binomail(n,p) \]

이항분포의 확률은 다음과 같이 계산한다.

\[ P(X=m) = {{n}\choose{m}} p^m (1-p)^{n-m}, \quad m=0,1,2,\dots, n \]

귀무가설이 참인 경우, 즉 고객이 장바구니를 이용할 확률 \(p\) 가 0.54 인 경우, 1000명의 고객 중에서 장버구니 이용자의 수가 620 명 또는 그 이상 나올 확률이 p-값이며 이론적으로 다음과 같이 구할 수 있다.

\[ p-value = P(X \ge 620) = \sum_{m=620}^{1000} {{1000}\choose{m}} (0.54)^m (1-0.54)^{1000-m} \]

위의 값은 실제로 아주 작은 수이다. 위의 p-값을 구하는 여러 가지 방법이 있지만 우리가 앞에서 배운 모의실험 방법으로 구해보자.

\[ p-value \approx \frac{\text{number of cases for } X \ge 620}{\text{number of simulation}} \]

모의실험은 라이브러리 numpyrandom.binomial(n,p,size) 함수를 이용할 것이다. 함수 random.binomial 는 성공 확률이 \(p\)인 사건을 \(n\) 번 독립적으로 시행할 때 나타나는 성공의 횟수를 size 만큼 반복적으로 모의실험해주는 함수이다.

1000명의 고객이 독립적으로 장바구니를 이용할 확률이 0.54인 경우, 즉 이용자의 수 \(X\)가 이항분포 \(Binomial(1000,0.54)\)를 따르는 경우 난수(random number)를 발생시켜 보자.

# 난수 1개를 발생시키는 경우 - 아래 코드를 반복적으로 실행시키면서 난수가 어떻게 변하는지 보자 
np.random.binomial(1000, 0.54, size= 1)
array([522])

이제 1000명의 고객이 각각 장바구니를 이용할 확률이 0.54인 경우 이용자의 수를 모의실험을 통하여 B=100000 번 발생시킨다.

B = 100000
bionomial_counts = np.random.binomial(1000, 0.54, size= B)
bionomial_counts
array([513, 536, 545, ..., 537, 536, 521])

이제 모의실험으로 발생시킨 10000개의 이용자 수에 대한 분포를 히스토그램으로 그려보자.

bionomial_df = pd.DataFrame({'count':bionomial_counts})
bionomial_df.plot.hist()
<AxesSubplot:ylabel='Frequency'>
../../_images/5f2b37208ea14591dcc82d1cbca40ec3c54ccb63ef05e2a8105572ff73cbd9fe.png

위에서 B=10000 번의 모의실험에서 성공의 횟수가 620명 이상인 비율을 구해보자.

observed_count = 620
bionomial_counts >= observed_count
array([False, False, False, ..., False, False, False])
np.sum(bionomial_counts >= observed_count)
0
p_value = np.sum(bionomial_counts >= observed_count)/B
p_value
0.0
p_value < 0.05
True

이제 위의 모의실험에서 1000명의 고객이 각각 장바구니를 이용할 확률이 0.54인 경우 모의실험으로 구한 B=10000개 의 이용자 수들 중에 620 명 이상이 나올 확률은 근사적으로 0으로 나타났다. 근사적이라는 의미는 정확한 확률이 0 아니라 B=10000 번 모의실험한 경우 한번도 나타나지 않았다는 것이다.

p-값의 근사값은 0 이고 유의수준 0.05 보다 작으므로 알고리즘 적용 후 고객이 장바구니를 이용할 확률은 0.54 보다 커졌다고 판단할 수 있다.

유의성 검정의 결과를 다시 말하면, 평균 이용율이 54%인 경우 1000명의 고객 중 620명 이상의 고객들이 장바구니를 이용할 가능성은 거의 없으므로 귀무가설을 기각하고 이용율이 증가했다고 결론을 내릴 수 있다.

7.2.5.3. 정확한 p-값의 계산#

이항분포에 대한 확률을 계산하기 위해서는 scipy.stats 라이브러리의 binom 객체를 이용해야 한다. 아래 코드에서 binom.cdf(x, n, p) 는 성공확률이 p인 경우 시행횟수가 n이고 성공의 회수가 x 와 같거나 작은 확률이다. cdf 는 누적분포함수(cumulative distribution function)의 줄임말이다.

\[ \text{binom.cdf(x, n, p)} = \sum_{i=0}^x P(X =i) = P(X \le x) \]

위에서 p-값은 성공회수가 620개 또는 그 이상 일 확률이기 때문에 다음과 같이 여사건의 확률을 이용하여 정확하게 게산할 수 있다.

\[ p-value = P(X \ge 620) = 1 - P(X \le 619) \]

아래 주어진 p-값의 정확한 값을 보면 \(0.000000193\)으로 매우 작으며 이러한 작은 확률의 시간은 B=10000 번의 모의실험으로는 1번이라도 나타나기 힘들다.

from scipy.stats import binom

p_val_exact = 1.0 - binom.cdf(619, 1000, 0.54)
p_val_exact
1.929786053178617e-07