p값
고친 사람 github-actions[bot]
p값은 눈에 보인 차이가 우연만으로도 흔히 나올 만한지를 숫자 하나로 알려 줍니다. 값은 0과 1 사이에 놓입니다. 작을수록 우연으로는 보기 드문 결과라는 뜻입니다. 실험이나 측정 결과를 믿어도 될지 가릴 때 이 숫자를 미리 정한 기준과 비교합니다.
쉽고 빠른 이해
p값은 「아무것도 안 바뀌었다면 이런 결과가 얼마나 자주 나올까」에 답하는 확률입니다. 동전을 열 번 던졌더니 앞면이 아홉 번 나왔습니다. 멀쩡한 동전으로 그만큼 앞면 쪽에 쏠릴 확률은 약 0.011입니다.
이 숫자가 없으면 흔들림과 진짜 변화를 가를 공통의 잣대가 없습니다. 평균 응답 시간이 0.01초 늘었을 때, 그것이 변화인지 늘 있는 흔들림인지를 사람마다 다르게 읽게 됩니다.
- 먼저 「차이가 없다」고 가정합니다
- 그 가정 아래서 지금만큼, 또는 지금보다 더 쏠린 결과가 나올 확률을 구합니다
- 그 확률을 미리 정한 기준과 비교합니다. 기준으로는 0.05를 가장 많이 씁니다
대가도 있습니다. 기준을 0.05로 잡으면 차이가 전혀 없을 때도 스무 번에 한 번꼴로 「달라졌다」는 판정이 나옵니다. 그리고 p값이 작다고 차이가 큰 것은 아닙니다.
상세
단골 식당의 김치찌개가 오늘따라 짜다고 해 봅시다. 맛은 원래 날마다 조금씩 오르내립니다. 그 폭 안이면 그냥 넘어갑니다. 몇 년 다니며 한 번도 없던 짠맛이라면 주방장이 바뀌었나 의심합니다.
p값은 이 「평소에 이런 일이 얼마나 자주 있었나」를 확률로 바꾼 값입니다. 아무것도 안 바뀌었다고 치고 확률 하나를 계산합니다. 지금 본 결과만큼, 또는 그보다 더 쏠린 결과가 나올 확률입니다. 이 확률이 작으면 「안 바뀌었다」는 가정을 의심하게 됩니다.
p 는 확률을 뜻하는 영어 probability 의 머리글자입니다. 영어로는 p-value 라고 씁니다.
이 절은 동전 던지기 하나를 끝까지 들고 갑니다. 가정을 세웁니다. 경우의 수를 센 뒤 코드로 다시 확인합니다. 그다음 응답 시간 같은 값으로 넓힙니다. 끝으로 기준과 비교하는 법과 흔히 잘못 읽는 방식을 봅니다.
차이가 없다는 가정
p값 계산은 「정말 달라졌나」를 바로 묻지 않습니다. 먼저 「아무것도 안 달라졌다」고 가정합니다. 이 가정이 귀무가설입니다. 반대편 주장인 「달라졌다」는 대립가설입니다.
거꾸로 시작하는 까닭은 계산에 있습니다. 「안 달라졌다」는 상태가 하나로 정해집니다. 그래서 그 상태에서 우연이 어떤 결과를 얼마나 자주 만드는지 셀 수 있습니다. 「달라졌다」는 얼마나 달라졌는지가 안 정해져 있어 계산의 출발점이 못 됩니다.
동전이라면 귀무가설은 「이 동전은 앞면과 뒷면이 반반으로 나온다」입니다. 서버라면 「새 버전과 옛 버전의 평균 응답 시간이 같다」가 귀무가설이 됩니다.
가정을 세우는 데서 시작해 판정까지 가는 절차 전체를 가설 검정이라고 합니다. 가정 아래서 p값을 구한 뒤, 그 값을 미리 정한 기준과 비교해 가정을 버릴지 정합니다. 뒤에 나오는 「~ 검정」은 모두 이 절차를 하는 한 가지 방식입니다.
지금보다 쏠린 결과가 나올 확률
동전을 열 번 던져 앞면이 아홉 번 나왔습니다. 반반인 동전이라면 앞뒤가 나오는 순서는 2를 열 번 곱한 1024가지입니다. 그 순서들은 모두 같은 확률로 나옵니다.
그중 앞면이 아홉 번인 순서는 10가지입니다. 뒷면이 나올 한 번을 열 번 가운데 어디에 둘지 고르는 수입니다. 앞면이 열 번인 순서는 1가지뿐입니다.
p값은 지금 결과에 더해 지금보다 더 쏠린 결과까지 셉니다. 앞면 아홉 번이 의심스럽다면 앞면 열 번은 더 의심스럽기 때문입니다. 그래서 10과 1을 더한 11가지를 1024로 나눕니다. 약 0.011이 나옵니다.
그 결과 하나의 확률만 보면 안 되는 까닭도 있습니다. 던지는 횟수가 늘면 어떤 결과든 하나하나의 확률은 작아집니다. 반반인 동전을 천 번 던져 딱 오백 번 앞면이 나올 확률도 약 0.025밖에 안 됩니다. 가장 흔한 결과조차 그 하나만 떼어 보면 드물어 보입니다.
결과마다 얼마나 자주 나오는지를 늘어놓은 것을 확률 분포라고 합니다. 아래 그림은 반반인 동전을 열 번 던질 때 앞면 수마다 순서가 몇 가지인지 보입니다. 가운데가 높고 양 끝이 낮습니다.
xychart-beta
title "반반인 동전 10번 · 앞면 수마다 순서 가짓수"
x-axis "앞면 수" [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y-axis "가짓수" 0 --> 260
bar [1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
앞면 아홉 번과 열 번은 오른쪽 끝의 낮은 막대 둘입니다. 분포의 끝부분을 꼬리라고 부릅니다. p값은 지금 결과에서 바깥쪽 꼬리까지의 막대를 모두 더해, 전체 막대 합 1024로 나눈 값입니다.
코드로 세어 보기
공식 없이도 p값을 어림할 수 있습니다. 「차이가 없는 세상」을 컴퓨터로 여러 번 돌려 봅니다. 그리고 지금만큼 쏠린 결과가 몇 번 나오는지 셉니다. 이렇게 무작위로 여러 번 돌려 답을 어림하는 방식이 시뮬레이션입니다.
아래 코드는 반반인 동전 열 번 던지기를 십만 번 되풀이합니다. random.random() 은 0과 1 사이
난수를 줍니다. 그 값이 0.5보다 작으면 앞면으로 칩니다. 100_000 은 십만을 읽기 쉽게 끊어 쓴
표기입니다.
import random
trials = 100_000
hits = 0
for _ in range(trials):
heads = sum(random.random() < 0.5
for _ in range(10))
if heads >= 9:
hits += 1
print(hits / trials) # 약 0.011
앞면이 아홉 번 이상 나온 판의 비율은 약 0.011입니다. 앞에서 센 값과 맞습니다. 난수를 쓰므로 돌릴 때마다 끝자리는 조금씩 달라집니다.
경우의 수를 바로 세면 어림이 아닌 값이 나옵니다. comb(n, k) 는 n 번 가운데 k 번을 고르는
가짓수입니다. 2**n 은 2를 n 번 곱한 값입니다.
from math import comb
n = 10
tail = comb(n, 9) + comb(n, 10) # 10 + 1
print(tail) # 11
print(tail / 2**n) # 0.0107421875
두 코드가 같은 질문에 답합니다. 앞의 것은 차이 없는 세상을 직접 흉내 냅니다. 뒤의 것은 그 세상의 모든 순서를 셉니다.
한쪽 꼬리와 양쪽 꼬리
앞의 계산은 앞면 쪽으로 쏠린 결과만 셌습니다. 그런데 「이 동전은 반반이 아니다」를 의심한다면 뒷면 쪽으로 쏠려도 똑같이 의심스럽습니다. 앞면이 한 번 이하인 순서도 11가지입니다.
양쪽 꼬리를 다 세면 22가지를 1024로 나눠 약 0.021이 됩니다. 한쪽 꼬리만 세는 방식을 단측 검정이라고 합니다. 양쪽 꼬리를 다 세는 방식은 양측 검정입니다.
어느 쪽을 쓸지는 무엇을 묻느냐가 정합니다. 「새 버전이 더 느려졌나」처럼 방향이 하나뿐이면 한쪽만 셉니다. 「달라졌나」처럼 어느 쪽이든 문제라면 양쪽을 셉니다.
이 선택은 결과를 보기 전에 합니다. 결과를 보고 나서 한쪽 꼬리로 바꾸면 같은 데이터에서 p값이 반으로 줄어듭니다. 원하는 결론 쪽으로 계산을 고른 셈이 됩니다.
이어진 값에서 구하는 법
응답 시간처럼 이어진 값은 동전처럼 경우를 셀 수 없습니다. 새 버전을 올린 뒤 평균 응답 시간이 0.20초에서 0.21초가 됐습니다. 같은 서버에 같은 요청을 보내도 응답 시간은 매번 조금씩 다릅니다. 이 0.01초가 코드 탓인지 흔들림 탓인지는 차이만 봐서는 모릅니다.
이럴 때는 옛 버전과 새 버전에 각각 요청을 여러 번 보내 응답 시간을 모읍니다. 이렇게 전체 가운데 일부만 뽑아 잰 값의 묶음이 표본입니다. 버전마다 하나씩, 표본이 둘 생깁니다. 표본의 평균은 표본을 새로 뽑을 때마다 조금씩 달라집니다.
표본을 다시 뽑을 때마다 평균이 오르내리는 폭을 표준 오차라고 합니다. 이 폭은 표본이 클수록 작아집니다. 값을 많이 모을수록 평균이 덜 흔들린다는 뜻입니다.
두 표본 평균의 차이도 표본을 다시 뽑을 때마다 오르내립니다. 그 오르내림의 폭이 차이의 표준 오차입니다.
지금 본 차이를 이 표준 오차로 나눈 값을 만듭니다. 차이가 평소 흔들림의 몇 배인지를 나타내는 값입니다. 이렇게 판정에 쓰려고 만든 값을 검정 통계량이라고 합니다.
차이가 없다면 이 값은 대개 0 가까이에 떨어집니다. 0에서 멀어질수록 드물어져, 0을 가운데 둔 종 모양의 분포를 이룹니다. 표본이 넉넉하면 이 분포는 정규 분포에 가깝습니다. 모양이 알려진 분포라서 어느 범위에 얼마나 자주 떨어지는지를 계산으로 구할 수 있습니다.
지금 값보다 0에서 더 먼 쪽에 놓인 몫이 p값입니다. 동전 그림에서 꼬리의 막대를 더한 것과 같은 일입니다.
두 평균을 이렇게 비교하는 대표적인 방법이 t 검정입니다. 계산 방법은 검정마다 다르지만 p값의 뜻은 어느 검정에서나 같습니다.
기준과 비교하기
p값만으로는 판정이 나오지 않습니다. 얼마나 작아야 「우연이 아니다」로 볼지 선을 따로 긋습니다. 이 선이 유의 수준입니다. 그리스 문자 알파(α)로 적습니다.
p값이 유의 수준보다 작으면 귀무가설을 버립니다. 그리고 차이가 통계적으로 유의하다고 말합니다. 유의 수준은 관례로 0.05를 가장 많이 씁니다. 더 엄격하게 볼 때는 0.01을 씁니다.
아래 표는 동전 예의 p값을 유의 수준 0.05에 대 본 것입니다. 「반반이 아니다」를 묻는 경우라 판정은 양쪽 꼬리 값으로 합니다.
| 앞면 수 | 한쪽 꼬리 p값 | 양쪽 꼬리 p값 | 0.05 기준 판정 |
|---|---|---|---|
| 8번 이상 | 약 0.055 | 약 0.109 | 유의하지 않다 |
| 9번 이상 | 약 0.011 | 약 0.021 | 유의하다 |
| 10번 | 약 0.001 | 약 0.002 | 유의하다 |
앞면 여덟 번은 기준을 넘어 유의하지 않습니다. 아홉 번부터는 기준보다 작아 유의합니다. 같은 동전에서도 앞면 하나 차이로 판정이 갈립니다.
기준은 결과를 보기 전에 정합니다. p값을 보고 나서 선을 옮기면 원하는 결론에 맞춰 선을 긋게 됩니다. 그러면 판정이 아무것도 걸러 내지 못합니다.
기준이 곧 오경보 확률
오경보는 아무 일도 없는데 경보가 울리는 것입니다. p값 판정에서도 차이가 없는데 「유의하다」가 나올 수 있습니다. 그런 일이 얼마나 자주 생기는지는 유의 수준이 정합니다.
차이가 정말 없는 경우를 생각합니다. p값이 0.05보다 작다는 것은 지금 결과가 차이 없는 세상의 결과 가운데 가장 쏠린 쪽 0.05만큼의 몫 안에 들었다는 뜻입니다. 그러니 차이 없는 세상에서 그런 결과가 나올 확률도 0.05입니다. 응답 시간처럼 이어진 값을 다룰 때 그렇습니다.
차이가 없는데도 스무 번에 한 번꼴로 유의하다는 판정이 나온다는 뜻입니다. 이렇게 차이가 없는데 있다고 판정하는 것이 1종 오류입니다. 감시 경보로 치면 오경보입니다.
반대로 차이가 있는데 못 잡는 것은 2종 오류입니다. 유의 수준을 낮추면 1종 오류는 줄어듭니다. 그 대신 작은 차이를 놓치는 2종 오류가 늘어납니다.
p값이 말해 주지 않는 것
p값은 귀무가설이 맞을 확률이 아닙니다. p값 0.03은 「차이가 없을 확률이 0.03」이 아닙니다. 「차이가 없다면 이만한 결과가 나올 확률이 0.03」입니다. 조건과 결과의 방향이 반대입니다.
방향이 뒤집히면 값도 달라집니다. 「비가 오면 땅이 젖을 확률」과 「땅이 젖었을 때 비가 왔을 확률」은 다릅니다. 땅은 물청소로도 젖기 때문입니다. 이렇게 조건을 붙인 확률이 조건부 확률입니다. 가설이 맞을 확률을 직접 구하려면 베이즈 추론 같은 다른 방법이 필요합니다.
p값은 차이의 크기도 아닙니다. 표본이 크면 표준 오차가 아주 작아집니다. 그러면 요청 백만 건을 비교할 때 0.0001초 같은 작은 차이도 p값이 아주 작게 나옵니다.
차이가 얼마나 큰지는 따로 봅니다. 그 크기를 재는 값이 효과 크기입니다. 평균이 0.20초에서 0.21초가 됐다면 차이 0.01초가 가장 단순한 효과 크기입니다.
크기와 흔들림을 함께 보려면 신뢰 구간을 씁니다. 차이를 한 값 대신 「0.005초에서 0.015초 사이」처럼 범위로 적습니다. 표본의 흔들림을 감안할 때 진짜 차이가 있을 만한 범위를 보여 줍니다. 범위가 좁을수록 차이를 정밀하게 잰 것입니다.
성능 회귀를 가릴 때 이 구분이 쓰입니다. 바꾸기 전과 후를 여러 번 재 두 표본을 만듭니다. p값이 작다는 것만으로는 회귀로 치지 않습니다. 차이가 미리 정한 허용 폭도 넘을 때 회귀로 봅니다.
p값이 크다고 차이가 없다는 뜻도 아닙니다. 표본이 작으면 흔들림이 커서 있는 차이도 못 잡습니다. 「이번 측정으로는 차이를 가려내지 못했다」가 맞는 읽기입니다.
있는 차이를 잡아낼 확률을 검정력이라고 합니다. 표본을 늘리면 표준 오차가 줄어 검정력이 올라갑니다.
여러 번 들여다볼 때
백엔드에서 p값을 만나는 대표적인 곳이 A/B 테스트입니다. 사용자를 둘로 나눠 서로 다른 버전을 보여 주는 실험입니다. 그리고 두 쪽의 결과를 비교합니다. 구매까지 간 사용자의 비율 같은 지표가 두 버전 사이에서 흔들림 이상으로 다른지를 p값으로 가립니다.
이 실험에서 흔한 실수는 중간에 계속 들여다보는 것입니다. 대시보드에서 p값을 매일 보다가 0.05 아래로 내려간 날 실험을 멈춥니다. 그러면 차이가 없어도 0.05 아래로 내려갈 기회가 여러 번 생깁니다. 1종 오류가 날 확률이 0.05보다 훨씬 커집니다.
그래서 표본을 몇 개 모을지 미리 정합니다. 다 모은 뒤에 한 번 봅니다. 중간 확인이 꼭 필요하면 그것을 감안해 기준을 짜는 순차 검정을 씁니다.
지표 여럿을 한꺼번에 검사할 때도 같은 일이 생깁니다. 지표 스무 개를 각각 유의 수준 0.05로 판정한다고 해 봅시다. 지표끼리 서로 영향을 주지 않는다고 치면, 아무것도 안 달라졌어도 하나 이상이 유의하게 나올 확률이 약 0.64입니다.
검사를 여러 번 할수록 1종 오류가 쌓이는 이 문제가 다중 비교 문제입니다. 검사가 많을수록 우연히 걸리는 지표가 하나쯤은 나오기 쉬워집니다.
가장 단순한 대응은 기준을 검사 수로 나누는 것입니다. 스무 개라면 0.05를 20으로 나눈 0.0025를 기준으로 씁니다. 이 방법이 본페로니 보정입니다.
원하는 p값이 나올 때까지 분석을 이리저리 바꾸는 것을 p-해킹이라고 합니다. 지표를 바꿔 보고 기간도 바꿔 봅니다. 데이터를 걸러 보기도 합니다.
그러다 보면 어디선가 0.05 아래가 나옵니다. 검사를 여러 번 한 것과 같은 일이라 판정이 아무것도 보장하지 못합니다.
관련 항목
p값을 계산하는 가설 검정의 구성 요소
가설 검정 · 귀무가설 · 대립가설 · 검정 통계량 · 유의 수준 · 단측 검정 · 양측 검정
p값을 내놓는 검정 방법
t 검정 · 카이제곱 검정 · 맨-휘트니 U 검정 · 이항 검정 · 순열 검정 · 부트스트랩
p값 판정이 빠지는 오류와 보정
1종 오류 · 2종 오류 · 검정력 · 다중 비교 · 본페로니 보정 · 거짓 발견률 · p-해킹 · 순차 검정
p값과 함께 읽는 차이의 크기 지표
효과 크기 · 신뢰 구간 · 표준 오차 · 표본 크기 · 실무적 유의성
p값 계산의 바탕이 되는 확률 개념
확률 · 조건부 확률 · 확률 분포 · 이항 분포 · 정규 분포 · 균등 분포 · 표본 · 표준편차 · 중심 극한 정리
p값으로 흔들림을 가려내는 측정
A/B 테스트 · 성능 회귀 · 벤치마크 · 응답 시간 · 시뮬레이션
p값과 맞세워지는 추론 방식
베이즈 추론 · 베이즈 인자 · 사후 확률
p값이 속하는 상위 분류
다른 이름: p-value · p value · p-값 · 유의 확률