[개발 공부] / Holm-Bonferroni 보정: 여러 p-value를 한 번에 읽기.md

Holm-Bonferroni 보정: 여러 p-value를 한 번에 읽기

조회

2026년 5월 21일 | 개발 공부


여러 모델 설정을 한 표에서 비교하기 시작하면 p-value 하나는 금방 결론처럼 보인다. A/B 한 번이면 그나마 괜찮은데, baseline, reranker, threshold, prompt variant, seed 묶음까지 붙으면 "유의하다"는 칸이 우연히 하나쯤 튀어나오기 쉽다. Holm-Bonferroni correction은 이렇게 여러 번의 가설 검정을 한 묶음으로 볼 때 false positive를 줄이기 위해 p-value를 작은 순서대로 보정해 읽는 절차다. 새 검정법이라기보다, 이미 계산한 p-value들을 어떻게 조심해서 읽을지 정하는 후처리 규칙에 가깝다.

여러 번 보면 하나쯤 맞아 보이는 문제

내가 실험 로그에서 자주 헷갈렸던 부분은 "비교가 몇 개냐"였다. 예를 들어 retrieval 평가에서 query set은 하나인데, 설정은 네 개가 있다고 하자. 기준 설정과 세 후보를 각각 비교하면 벌써 검정이 세 번이다. 여기에 MRR, nDCG, coverage 같은 metric을 같이 보면 표는 더 그럴듯해지고, p-value가 0.05 아래로 내려간 칸도 생긴다. 문제는 그 칸이 정말 강한 신호인지, 아니면 여러 번 긁다 보니 나온 우연인지 구분하기 어렵다는 점이다.

Bonferroni 보정은 이 상황을 아주 보수적으로 다룬다. 전체 허용 오류율을 비교 개수로 나눠서 각 검정의 기준을 낮춘다. 비교가 다섯 개면 0.05 대신 0.01을 기준으로 보자는 식이다. 단순하고 안전하지만, 작은 개인 실험에서는 너무 뻣뻣하게 느껴질 때가 있다. Holm-Bonferroni는 여기서 한 발 덜 답답하다. 가장 작은 p-value부터 보되, 처음에는 엄격하게 보고 뒤로 갈수록 기준을 조금씩 풀어 주는 step-down 방식이다.

절차는 의외로 단순하다

절차 자체는 복잡하지 않다. 먼저 같은 family에 들어갈 p-value들을 정한다. 여기서 family는 한 번에 해석하려는 비교 묶음이다. 같은 query set에서 나온 세 개의 모델 비교일 수도 있고, 같은 실험 목적 아래의 여러 ablation일 수도 있다. 그다음 p-value를 작은 순서로 정렬한다. 첫 번째 값은 alpha / 전체 비교 수와 비교하고, 통과하면 두 번째 값은 alpha / 남은 비교 수와 비교한다. 어느 지점에서 통과하지 못하면 그 뒤의 값들은 더 이상 유의하다고 말하지 않는다.

중요한 건 이 보정이 효과 크기를 대신하지 않는다는 점이다. p-value가 보정 후에도 살아남았다고 해서 곧바로 "좋은 설정"이 되는 건 아니다. 평균 차이가 너무 작거나, 특정 cluster에서만 이겼거나, latency 비용이 같이 늘었다면 결론은 여전히 보류다. 반대로 보정 후에는 유의하지 않더라도 bootstrap interval이 좁아지고 실패 사례가 줄어든 설정이라면 다음 실험 후보로 남길 수 있다. 나는 그래서 보정값을 판정 도장보다 경고등에 가깝게 본다.

한 가지 더 조심할 점은 family를 결과를 본 뒤 마음대로 바꾸는 일이다. 마음에 드는 비교만 따로 떼어 "이 세 개만 한 묶음"이라고 하면 보정은 거의 의미가 없어진다. 반대로 관계없는 metric을 전부 한 바구니에 넣으면 신호가 필요 이상으로 죽는다. 그래서 실험 노트에는 보정을 계산하기 전에 비교 목적을 먼저 적어 둔다. "새 reranker 후보 세 개를 기준 profile과 비교"처럼 문장 하나만 있어도 나중에 표를 다시 읽을 때 훨씬 덜 흔들린다.

작은 숫자로 한 번 눌러 보기

예를 들어 네 후보를 기준 설정과 비교해서 p-value가 0.004, 0.018, 0.031, 0.047로 나왔다고 하자. 아무 보정 없이 보면 네 칸이 전부 0.05 아래라서 표가 꽤 좋아 보인다. Holm-Bonferroni로 읽으면 첫 값은 0.05 / 4, 즉 0.0125를 통과한다. 두 번째 값은 남은 비교가 세 개라 0.05 / 3인 0.0167과 비교한다. 여기서 0.018이 통과하지 못하므로 그 뒤의 0.031, 0.047은 더 느슨한 기준을 기다리지 않고 멈춘다.

이 예시는 일부러 단순하게 만든 숫자지만, 내가 실제 표를 읽을 때 받는 느낌과 비슷하다. 원래는 별표가 네 개였는데, 보정 후에는 하나만 남는다. 그러면 결론이 약해졌다고 느끼기보다 질문이 바뀐다. 왜 첫 후보만 안정적으로 살아남았는지, 나머지 후보는 평균 delta가 작았는지, 특정 query 묶음에서만 반짝였는지 다시 보게 된다. 보정은 결과를 지우는 절차가 아니라, 다음에 볼 샘플을 고르는 절차에 가깝다.

실험 노트에 남기는 방식

작은 평가표에서는 p-value만 따로 떼어 쓰는 순간 과신이 생긴다. 내가 남기기 좋은 형식은 네 칸이다.

  • 비교 family: 어떤 후보들을 한 묶음으로 보정했는지
  • 원래 p-value와 Holm 보정 후 판정: 정렬 순서까지 함께 기록
  • 평균 delta와 bootstrap interval: 실제 차이 크기와 흔들림 폭
  • 다시 볼 샘플 목록: 큰 개선과 큰 악화가 어디서 나왔는지

이렇게 적어두면 표를 다시 볼 때 "유의하다/아니다"로 바로 닫히지 않는다. 특히 GraphRAG profile 비교처럼 query별 delta가 남는 실험에서는 보정된 p-value보다 어느 query group에서 차이가 반복되는지가 더 중요할 때가 많다. GNN 링크 예측에서도 seed별 AUC 차이만 보고 결론을 내리면 split 운이 섞일 수 있으니, 같은 family 안에서 어떤 비교를 동시에 본 것인지 먼저 고정하는 편이 낫다.

내가 쓰는 기준

Holm-Bonferroni를 붙일 만한 순간은 보통 두 가지다. 첫째, 같은 질문에 대해 여러 후보를 동시에 비교했을 때다. 둘째, 평균표를 보고 이미 마음이 기울었는데 그 결론이 너무 쉽게 나온 것 같을 때다. 이때 보정을 붙이면 결과가 화려해지는 대신 조금 차분해진다. 몇 개의 별표는 사라지고, 살아남은 차이도 effect size와 실패 사례를 같이 보게 된다. 그래서 보고서에는 보정 여부 자체보다 비교 family를 어떻게 잡았는지를 먼저 적는다.

나는 이 정도의 불편함이 오히려 좋았다. 통계 보정은 결론을 멋있게 만드는 장식이 아니라, 내가 여러 번 들여다본 사실을 보고서에 정직하게 반영하는 장치다. p-value 하나가 아니라 비교 묶음, 효과 크기, 흔들림 폭, 다시 볼 샘플까지 같이 남기면 다음 실험에서 덜 헤맨다. 작은 실험일수록 이런 얇은 안전장치가 평균표를 과하게 믿는 습관을 꽤 잘 눌러 준다. 결국 남는 건 별표 개수가 아니라, 다음 실험에서 어떤 후보를 계속 밀고 어떤 후보를 접을지에 대한 더 차분한 근거다.

댓글

홈으로 돌아가기

검색 결과

"" 검색 결과입니다.