2026년 5월 12일 | 개발 공부
McNemar 검정은 같은 테스트셋 위에서 두 모델이나 두 설정을 비교할 때, 전체 정확도 차이보다 서로 다르게 맞힌 샘플만 떼어 보는 검정이다. 나는 처음 이 이름을 봤을 때 통계 교과서 안쪽에 있는 기법처럼 느꼈는데, 실제로 평가 로그에 붙일 때의 감각은 꽤 단순했다. A와 B가 둘 다 맞힌 샘플은 승부를 가르지 않는다. 둘 다 틀린 샘플도 마찬가지다. 진짜로 봐야 하는 건 A만 맞히고 B는 틀린 샘플 수, 그리고 B만 맞히고 A는 틀린 샘플 수다.
모델 비교를 할 때 평균 accuracy나 F1 차이를 먼저 보는 건 자연스럽다. 문제는 같은 1,000개 테스트 샘플을 놓고 두 모델을 비교하면서도, 무심코 두 점수를 서로 독립인 것처럼 읽을 때가 있다는 점이다. A가 812개를 맞혔고 B가 826개를 맞혔다면 B가 14개 더 맞힌 것은 맞다. 그런데 그 14개 차이가 A가 틀린 걸 B가 대거 주워 담아서 생긴 것인지, 아니면 둘이 다른 샘플에서 엇갈린 결과가 우연히 조금 기운 것인지는 평균 숫자만으로는 잘 안 보인다.
독립 비교가 아니라 짝지어진 비교
McNemar 검정의 핵심은 paired comparison이다. 같은 샘플을 두 설정이 함께 풀었기 때문에, 샘플별 결과가 한 쌍으로 묶인다. 샘플 37번에서 A는 맞고 B는 틀렸는지, 샘플 38번에서 A는 틀리고 B는 맞았는지처럼 한 줄씩 비교한다. 이 구조를 버리고 전체 정답 개수만 비교하면, 테스트셋 자체의 쉬운 샘플과 어려운 샘플이 만든 공통 흔들림을 놓치기 쉽다.
그래서 표는 보통 네 칸으로 자른다. 행은 A의 결과, 열은 B의 결과로 놓으면 된다. 둘 다 맞음, A만 맞음, B만 맞음, 둘 다 틀림. 여기서 검정에 직접 들어가는 칸은 가운데의 불일치 두 칸이다. 둘 다 맞거나 둘 다 틀린 샘플은 두 설정이 같은 판단을 한 것이므로, 어느 쪽이 더 낫다는 증거로 쓰기 어렵다.
| 구분 | B 정답 | B 오답 | 해석 |
|---|---|---|---|
| A 정답 | 둘 다 맞음 | A만 맞음 | A 쪽 불일치 승리 |
| A 오답 | B만 맞음 | 둘 다 틀림 | B 쪽 불일치 승리 |
예를 들어 A만 맞힌 샘플이 18개, B만 맞힌 샘플이 42개라면 B가 단순히 전체 정확도만 조금 높은 게 아니라, A와 엇갈린 자리에서 꽤 많이 이긴 셈이다. 반대로 A만 맞힘이 28개, B만 맞힘이 31개라면 전체 평균 차이는 있어 보여도 불일치 표만 놓고는 그렇게 강하게 말하기 어렵다. 이 차이가 내가 McNemar 표를 좋아하는 지점이다. 평균표에서 흐릿하던 승부의 위치가 바로 드러난다.
검정식보다 먼저 볼 숫자
실제로는 p-value를 계산할 수 있다. continuity correction을 넣은 근사식은 대략 A만 맞힘과 B만 맞힘의 차이에서 1을 뺀 뒤 제곱하고, 두 불일치 수의 합으로 나누는 형태다. 불일치 수가 작으면 카이제곱 근사보다 exact binomial test를 쓰는 편이 낫다. 다만 나는 이걸 처음부터 p-value 생산기로 쓰는 것에는 조심하는 편이다. 작은 프로젝트 실험에서는 숫자 하나가 주는 권위가 너무 쉽게 커진다.
내가 먼저 보고 싶은 건 네 가지다. 첫째, 전체 테스트 샘플 수. 둘째, 두 설정의 평균 점수. 셋째, A만 맞힘과 B만 맞힘의 개수. 넷째, 그 불일치 샘플을 실제로 몇 개 열어 봤을 때 어떤 유형인지다. p-value는 그 다음에 붙여도 늦지 않다. 불일치 표가 거의 비슷한데 p-value만 들고 결론을 내리는 것보다, B가 이긴 샘플이 특정 query cluster에 몰려 있는지 보는 쪽이 다음 실험에는 더 도움이 된다.
Retrieval 평가에도 붙일 수 있는 방식
이 검정은 classification 정확도에만 갇혀 있지 않다. GraphRAG나 검색 평가에서도 query 단위 성공 여부를 이진값으로 만들면 비슷하게 쓸 수 있다. 예를 들어 profile A와 profile B가 같은 query set을 풀었고, 각 query에 대해 top-1 hit 여부나 full coverage 여부를 기록했다고 하자. 그러면 query마다 A 성공/B 실패, A 실패/B 성공을 셀 수 있다. MRR이나 nDCG처럼 연속적이거나 graded한 metric은 paired bootstrap이나 permutation 쪽이 더 자연스럽지만, 성공/실패로 분명히 자른 지표에는 McNemar식 표가 꽤 잘 맞는다.
중요한 건 success rule을 결과를 본 뒤 바꾸지 않는 것이다. top-1 hit로 볼지, top-5 안 기대 문서 포함으로 볼지, full coverage로 볼지 먼저 정해 둬야 한다. profile B가 좋아 보이는 기준을 나중에 골라 붙이면 검정이 아니라 사후 설명이 된다. 나는 이런 지점에서 통계 기법보다 운영 습관이 더 중요하다고 느낀다. 평가 단위와 성공 기준을 먼저 잠가야, 나중에 숫자가 나왔을 때 해석이 덜 흔들린다.
내가 실험 노트에 남기는 형태
개인 프로젝트 수준에서는 거창한 리포트보다 작은 표 하나면 충분할 때가 많다. 모델명 두 개, metric 평균, A만 맞힘, B만 맞힘, McNemar p-value, 그리고 disagreement sample 링크 몇 개. 이 정도만 있어도 “B가 평균 1.4%p 높다”보다 훨씬 읽을 정보가 많다. 특히 두 설정의 평균이 비슷할수록, 불일치 표는 어디서 갈렸는지를 빠르게 보여 준다.
- paired unit: 샘플, query, edge처럼 한 줄 비교의 단위를 먼저 고정
- success rule: 정답/오답 또는 성공/실패 판정을 결과 확인 전에 정의
- discordant counts: A만 성공, B만 성공 두 칸을 별도 기록
- inspection queue: 한쪽만 맞힌 샘플 일부를 다시 열어 실패 유형 확인
이 방식의 장점은 결론을 늦춰 준다는 데 있다. 평균이 조금 높은 설정을 바로 기본값으로 올리기 전에, 그 개선이 실제로 같은 샘플 위에서 일어난 것인지 한 번 더 묻게 만든다. 반대로 평균 차이는 작아도 B만 맞힌 샘플이 특정 중요 유형에 몰려 있다면, 그건 제품이나 실험 목적에 따라 꽤 의미 있는 신호일 수 있다. 통계적 유의성 하나만으로 운영 결정을 끝내지 않고, 불일치 샘플을 다음 분석 큐로 넘기는 편이 더 안전하다.
주의할 경계
물론 McNemar 검정이 모든 비교에 맞는 건 아니다. 점수 차이가 연속값인 regression, graded relevance를 쓰는 ranking metric, 여러 label이 강하게 얽힌 multi-label 문제에서는 다른 paired test나 resampling이 더 어울릴 수 있다. 또 같은 사용자에서 여러 샘플이 나온 데이터처럼 독립성이 애매하면, 샘플 단위를 더 크게 묶어야 한다. query 하나하나가 독립이라고 가정했는데 사실은 같은 템플릿 변형이라면, 깔끔한 2x2 표도 자신감을 과하게 줄 수 있다.
그래도 같은 테스트셋에서 두 설정을 비교할 때 McNemar 표를 한 번 만드는 습관은 꽤 쓸 만하다. 평균 점수는 방향을 보여 주고, bootstrap은 흔들림 폭을 보여 주고, McNemar 표는 서로 다르게 맞힌 자리를 보여 준다. 이 셋을 같이 두면 실험 결과를 읽는 속도가 조금 느려진다. 나에게는 그 느려짐이 오히려 좋다. 모델 비교에서 가장 위험한 순간은 숫자가 없는 때보다, 숫자 하나가 너무 빨리 결론처럼 보일 때이기 때문이다.
'[개발 공부]' 카테고리의 다른 글
| Paired permutation test: 평균 차이를 직접 뒤섞어 보기 (0) | 2026.05.13 |
|---|---|
| Bootstrap 신뢰구간: 평균 점수 옆에 흔들림 붙이기 (0) | 2026.05.06 |
| MRR과 nDCG, 첫 정답과 전체 순서를 분리해서 보기 (0) | 2026.05.01 |
| Negative Sampling, 링크 예측에서 없는 간선을 고르는 기준 (0) | 2026.04.29 |
| MLA KV Cache, 긴 문맥에서 먼저 줄어드는 병목 (0) | 2026.04.28 |