zenn.skin 무료버전 배포중!
자세히보기

DataScience

임의순열검정(random permutation test)

koosco! 2022. 8. 23. 05:23

1. 부트스트랩(Bootstrap)

표본분포를 추정하는 쉽고 효과적인 방법은, 현재 있는 표본에서 추가적으로 표본을 복원추출하여 통계량과 모델을 다시 계산하는 방법입니다.

이러한 방법을 부트스트랩이라 하며, 부트스트랩을 할 때 데이터나 표본통계량이 정규분포를 따라야 한다는 가정은 필요하지 않습니다.

 

원래 부트스트랩은 갖고있는 표본을 무한대로 복제한 후 거기에서 표본을 추출하는 방법을 의미합니다. 하지만 실제로는 표본을 복제하지 않고 복원추출하는 방법으로 부트스트랩을 사용합니다.

 

부트스트랩을 사용하는 이유는 작은 표본크기를 보완하거나 새로운 데이터를 만드는 것이 아닙니다. 표본을 이용해 가상의 모집단을 만들고 거기서 표본추출을 했을 때, 새로운 표본이 원래의 표본과 얼마나 비슷할지를 보여주는 역할을 합니다.

 

2. 재표본추출(resampling)

재표본추출은 부트스트랩과 비슷한 의미로 사용됩니다.

재표본추출은 여러 표본을 결합하고, 결합한 집단에서 비복원추출을 수행하는 순열과정을 같이 진행합니다. 반면 부트스트랩은 관측된 데이터로부터 반복적인 복원추출하는 것을 의미합니다.

import pandas as pd

def permuatation_test(x: pd.Series, nA: int, nB: int) -> float:
    n = nA + nB # 두 표본을 결합
    idx_B = set(random.sample(range(n), nB)) # B의 크기만큼 비복원 추출
    idx_A = set(range(n)) - idx_B # A의 크기만큼 비복원 추출
    
    return x.loc[idx_B].mean() - x.loc[idx_A].mean() # 새로 뽑은 표본들의 차이를 반환

 

예제)

Page A와 Page B에 대한 페이지 점유 시간이 주어질 때, 두 페이지의 점유 시간의 차이는 통계적으로 유의한지 확인해보자.

import pandas as pd

session_times = pd.read_csv("https://raw.githubusercontent.com/gedeck/practical-statistics-for-data-scientists/a760b479c06acd31ec74f0cc057fc3d145617fd1/data/web_page_data.csv")
session_times['Time'] = session_times['Time'] * 100
session_times.head()

import matplotlib.pyplot as plt

plt.figure(figsize=(16, 12))
ax = session_times.boxplot(by='Page', column='Time', grid=False)
ax.set_xlabel('')
ax.set_ylabel('')
plt.suptitle('')
plt.show()
 

nA = len(session_times[session_times['Page'] == 'Page A'])
nB = len(session_times[session_times['Page'] == 'Page B'])
permutation_differences = [permutation_test(session_times['Time'], nA, nB) for _ in range(1_000)]

nA는 Page A의 데이터 개수, nB는 Page B의 데이터 개수를 나타냅니다.

permutation_differences는 1,000번 순열검정을 반복했을 때의 차이를 나타냅니다.

mean_a = session_times[session_times['Page'] == 'Page A']['Time'].mean()
mean_b = session_times[session_times['Page'] == 'Page B']['Time'].mean()
mean_b - mean_a # 0.3567

- 실제 데이터에서 구한 Page A와 Page B의 평균 점유 시간 차이

fig, ax = plt.subplots(1, 1, figsize=(10, 10))
ax.hist(permutation_differences, bins=11, rwidth=0.9)
ax.axvline(x = mean_b - mean_a, color='black', lw=3)
ax.set_xlabel('Session time differences (in seconds)')
ax.set_ylabel('Frequency')
plt.show()

순열검정을 통해 구한 머문 시간 차이에 대한 그래프

p_value = sum(map(lambda x: x > mean_b - mean_a, permutation_differences)) / 1000
p_value  # 0.146

전체 순열검정 결과 중 검은색 수직선(실제 관측값)을 넘어서는 값의 비율을 통해 p-value를 구할 수 있습니다.

 

scipy.stats의 ttest_ind를 이용해 p-value를 구해보면 값에 큰 차이가 없는 것을 확인할 수 있습니다.

import numpy as np
from scipy.stats import ttest_ind

page_A = session_times[session_times['Page'] == 'Page A']['Time']
page_B = session_times[session_times['Page'] == 'Page B']['Time']
_, p = ttest_ind(page_A, page_B)
np.round(p / 2, 3) # 0.135

p-value는 랜덤 모델이 주어졌을 때, 결과가 실제로 관찰된 결과보다 극단적일 확률을 나타냅니다. 즉, 실제 관측값보다 랜덤 분포의 값이 더 큰 비율이 p-value가 나타내는 의미입니다. 순열검정을 사용하면 시각적으로 p-value를 확인할 수 있기 때문에 단순히 연산이나 수치를 통해 구하는 것보다 이해하기가 수월한 것 같습니다. p-value가 헷갈릴 때는 순열검정을 이용해 공부해 보는 것도 좋은 방법일 것 같습니다.

'DataScience'의 다른글

  • 현재글 임의순열검정(random permutation test)

관련글