1 왜 Gold Standard의 신뢰도를 측정해야 하는가
머신러닝 모델이나 의료 알고리즘을 평가할 때 우리는 반드시 정답 레이블(gold standard)이 필요하다. 그런데 이 정답은 어디서 오는가? 대부분은 인간 전문가가 직접 판정한다.
가령 AI 피부암 분류 모델을 검증한다면:
- 피부과 전문의 5명이 각 이미지를 독립적으로 판독
- 다수결 또는 합의로 gold standard를 결정
- AI 모델의 판정을 이 gold standard와 비교
여기서 결정적인 질문이 생긴다: 전문의 5명이 얼마나 서로 동의하는가?
전문의들이 서로 엇갈린 판정을 내렸다면, 그 합의 결과는 진짜 ’정답’이라고 할 수 없다. 불확실한 gold standard로 모델을 평가한다면, 모델의 성능 수치 자체가 신뢰할 수 없게 된다.
이것이 주석자 간 신뢰도(inter-rater reliability, IRR)를 반드시 보고해야 하는 이유다.
FDA는 의료기기 소프트웨어(SaMD) 검증 시 gold standard의 신뢰도 보고를 요구한다. 일반적으로 Cohen’s \(\kappa \geq 0.70\) (substantial agreement) 이상을 수용 가능한 기준으로 본다. 이보다 낮으면 gold standard의 질 자체를 의심해야 하며, 추가적인 합의 프로세스가 필요하다.
2 두 가지 다른 개념: 상관성 vs 일치성
주석자 신뢰도를 측정하기 전에 두 개념을 구분해야 한다.
| 개념 | 의미 | 적합한 지표 |
|---|---|---|
| 일치성 (Agreement) | 두 판정자가 동일한 판정을 내렸는가 | Cohen’s \(\kappa\), ICC (agreement형) |
| 일관성 (Consistency) | 두 판정자의 판정이 같은 방향으로 변화하는가 | ICC (consistency형), Spearman \(\rho\) |
판정자 A는 항상 판정자 B보다 점수를 5점 높게 준다고 하자. 상관계수는 1.0이지만 일치도는 낮다. 규제 검증에서는 일치성(agreement)이 요구된다. “두 판정자가 같은 답을 냈는가”가 중요하기 때문이다.
3 Cohen’s Kappa (\(\kappa\)) — 명목형 범주, 2명
3.1 정의
두 판정자 A, B가 \(n\)개 항목에 대해 \(k\)개 범주 중 하나를 독립적으로 부여할 때, 관측 일치율 \(P_o\)와 우연에 의한 기대 일치율 \(P_e\)를 사용하여 정의한다.
\[ \kappa = \frac{P_o - P_e}{1 - P_e} \]
여기서: - \(P_o = \sum_{i=1}^{k} \frac{n_{ii}}{n}\) (대각 원소의 합 / 전체) - \(P_e = \sum_{i=1}^{k} \frac{n_{i+} \cdot n_{+i}}{n^2}\) (주변 확률의 곱 합) - \(n_{ii}\): 두 판정자 모두 \(i\)로 분류한 항목 수 - \(n_{i+}\): 판정자 A가 \(i\)로 분류한 항목 수, \(n_{+i}\): 판정자 B가 \(i\)로 분류한 항목 수
3.2 직관적 이해
\(P_e\)는 “두 판정자가 무작위로 독립적으로 판정했을 때 우연히 일치할 확률”이다. \(\kappa\)는 이 우연을 제거하고 나서 얼마나 더 일치하는지를 측정한다.
- \(\kappa = 1\): 완벽한 일치
- \(\kappa = 0\): 우연 수준의 일치 (정보 없음)
- \(\kappa < 0\): 우연보다 더 자주 불일치 (드물지만 가능)
3.3 수치 예시
이진 분류(양성/음성)에서 두 병리학자 A, B가 100개 슬라이드를 판독한 결과:
| B: 양성 | B: 음성 | 합 | |
|---|---|---|---|
| A: 양성 | 40 | 10 | 50 |
| A: 음성 | 5 | 45 | 50 |
| 합 | 45 | 55 | 100 |
\[P_o = \frac{40 + 45}{100} = 0.85\]
\[P_e = \frac{50 \times 45}{100^2} + \frac{50 \times 55}{100^2} = 0.225 + 0.275 = 0.50\]
\[\kappa = \frac{0.85 - 0.50}{1 - 0.50} = \frac{0.35}{0.50} = 0.70\]
관측 일치율은 85%이지만, 우연 일치율이 50%이므로 \(\kappa = 0.70\)이 나온다. 단순 일치율(85%)보다 훨씬 보수적이고 신뢰할 수 있는 지표다.
4 Fleiss’ Kappa — 명목형 범주, 3명 이상
Cohen’s Kappa는 2명 판정자에 한정된다. 3명 이상에는 Fleiss’ Kappa를 사용한다.
\(n\)개 항목, \(k\)개 범주, \(m\)명 판정자인 경우:
\[ \kappa_F = \frac{\bar{P} - \bar{P}_e}{1 - \bar{P}_e} \]
여기서: - \(\bar{P} = \frac{1}{n \cdot m(m-1)} \sum_{i=1}^{n} \sum_{j=1}^{k} n_{ij}(n_{ij}-1)\) (평균 관측 일치율) - \(\bar{P}_e = \sum_{j=1}^{k} p_j^2\), \(p_j = \frac{\text{범주 } j \text{의 총 판정 수}}{n \cdot m}\)
Fleiss’ Kappa는 판정자 조합에 관계없이 전체 집합의 일치도를 하나의 수치로 요약한다.
5 ICC (급내 상관계수, Intraclass Correlation Coefficient) — 연속형
Kappa는 명목 범주형 데이터에 사용하지만, 판정이 숫자 점수(예: 1-10점 통증 척도, CT 병변 크기 mm)일 때는 ICC를 사용한다.
5.1 Mixed Models 맥락의 ICC vs 신뢰도 맥락의 ICC
ICC는 문맥에 따라 두 가지 다른 의미로 쓰인다.
| 맥락 | 의미 | 공식 |
|---|---|---|
| 혼합 모형 (Mixed Model) | 집단 내 분산 비율 — 군집화 정도 측정 | \(ICC = \frac{\tau^2}{\tau^2 + \sigma^2}\) |
| 신뢰도 측정 (여기서 다루는 것) | 판정자 간 일치도 — 반복 측정의 안정성 | ANOVA 기반 공식 |
이 포스트는 신뢰도 측정 맥락의 ICC를 다룬다.
5.2 ICC의 ANOVA 기반 정의
판정자를 무작위 효과(random effect)로 보는 ANOVA 분해:
\[ X_{ij} = \mu + \alpha_i + \beta_j + \varepsilon_{ij} \]
- \(\alpha_i\): 항목 \(i\)의 무작위 효과 (\(\sigma^2_\alpha\))
- \(\beta_j\): 판정자 \(j\)의 무작위 효과 (\(\sigma^2_\beta\))
- \(\varepsilon_{ij}\): 오차 (\(\sigma^2_\varepsilon\))
Agreement 형 ICC (판정자 간 절대 일치, FDA에서 요구되는 형태):
\[ ICC_{agreement} = \frac{\sigma^2_\alpha}{\sigma^2_\alpha + \sigma^2_\beta + \sigma^2_\varepsilon} \]
Consistency 형 ICC (판정자 간 상대적 일관성):
\[ ICC_{consistency} = \frac{\sigma^2_\alpha}{\sigma^2_\alpha + \sigma^2_\varepsilon} \]
Agreement 형은 판정자 편향(\(\sigma^2_\beta\))까지 오차에 포함하므로 더 엄격하다. 규제 검증에서는 절대 일치가 필요하므로 Agreement 형을 사용한다.
5.3 ICC의 6가지 모형 (Shrout & Fleiss, 1979)
| 모형 | 판정자 | 측정 | 표기 | 언제 사용 |
|---|---|---|---|---|
| ICC(1,1) | 무작위 선택, 1회 측정 | 단일 | One-way random | 판정자마다 서로 다른 항목을 봄 |
| ICC(1,k) | 무작위 선택, k회 평균 | 평균 | One-way random | 위와 같지만 k명 평균 보고 |
| ICC(2,1) | 무작위 선택, 1회 측정 | 단일 | Two-way random | 모든 판정자가 모든 항목을 봄, 판정자를 일반화 |
| ICC(2,k) | 무작위 선택, k회 평균 | 평균 | Two-way random | 위와 같지만 k명 평균 보고 |
| ICC(3,1) | 고정 집합, 1회 측정 | 단일 | Two-way mixed | 특정 판정자 집단에만 일반화 |
| ICC(3,k) | 고정 집합, k회 평균 | 평균 | Two-way mixed | 위와 같지만 k명 평균 보고 |
임상·규제 검증에서 가장 흔히 사용하는 것: ICC(2,1) — Agreement 형. 모든 판정자가 모든 항목을 독립 판독하고, 이 판정자들 이상의 모집단으로 결과를 일반화하는 상황에 해당한다.
6 어떤 지표를 쓸 것인가
| 조건 | 지표 |
|---|---|
| 이진 분류 (양성/음성), 판정자 2명 | Cohen’s \(\kappa\) |
| 다범주 명목형, 판정자 2명 | Cohen’s \(\kappa\) (다범주) |
| 명목형 (범주), 판정자 3명 이상 | Fleiss’ \(\kappa\) |
| 연속형 또는 순서형 점수, 2명 이상 | ICC |
| 절대 일치 필요 (규제, 임상) | ICC — Agreement 형 |
| 상대적 순위 일관성만 확인 | ICC — Consistency 형 또는 Spearman \(\rho\) |
7 해석 기준
Landis & Koch (1977)의 기준이 가장 널리 사용된다:
| \(\kappa\) 또는 ICC 범위 | 해석 | 실무적 의미 |
|---|---|---|
| < 0.00 | Poor | 우연보다 못함 — gold standard 폐기 |
| 0.00 – 0.20 | Slight | 거의 우연 수준 |
| 0.21 – 0.40 | Fair | 보통 미만 |
| 0.41 – 0.60 | Moderate | 보통 |
| 0.61 – 0.80 | Substantial | 충분한 일치 — FDA 최소 기준 |
| 0.81 – 1.00 | Almost Perfect | 우수한 일치 |
일반적으로 \(\kappa \geq 0.70\) 이상이어야 gold standard로 인정된다. \(0.61 \leq \kappa < 0.70\)이면 조건부 수용 가능하나 추가 합의 과정 문서화가 필요하다. \(\kappa < 0.61\)이면 gold standard 재설계를 권고한다.
8 응용 분야
| 분야 | 상황 | 사용 지표 |
|---|---|---|
| 의료 AI | CT/MRI 병변 어노테이션 일치도 | ICC (연속형 크기) |
| 임상시험 | 임상의 평가척도(MMSE, NIHSS) 신뢰도 | ICC 또는 Weighted Kappa |
| FDA 의료기기 | 알고리즘 검증용 gold standard 신뢰도 | Cohen’s \(\kappa\) (이진) |
| LLM 평가 | 인간 평가자 간 응답 품질 일치도 | Cohen’s \(\kappa\) 또는 Fleiss’ \(\kappa\) |
| 병리 조직검사 | 병리학자 간 종양 등급 판독 | Weighted Kappa |
| 신용 심사 | 심사원 간 대출 승인 일치도 | Cohen’s \(\kappa\) |
9 코드 예시
9.1 Step 1: 순수 구현 (원리 이해)
# R — Cohen's Kappa 수동 계산
compute_kappa <- function(mat) {
n <- sum(mat)
po <- sum(diag(mat)) / n
row_marginals <- rowSums(mat) / n
col_marginals <- colSums(mat) / n
pe <- sum(row_marginals * col_marginals)
kappa <- (po - pe) / (1 - pe)
list(po = po, pe = pe, kappa = kappa)
}
# 예시: 2×2 혼동 행렬
mat <- matrix(c(40, 10, 5, 45), nrow = 2, byrow = TRUE,
dimnames = list(c("A:Pos", "A:Neg"), c("B:Pos", "B:Neg")))
result <- compute_kappa(mat)
cat(sprintf("Po = %.3f, Pe = %.3f, κ = %.3f\n",
result$po, result$pe, result$kappa))
# Po = 0.850, Pe = 0.500, κ = 0.700# Python — Cohen's Kappa 수동 계산
import numpy as np
def compute_kappa(mat):
mat = np.array(mat)
n = mat.sum()
po = np.trace(mat) / n
row_m = mat.sum(axis=1) / n
col_m = mat.sum(axis=0) / n
pe = np.dot(row_m, col_m)
kappa = (po - pe) / (1 - pe)
return {"po": po, "pe": pe, "kappa": kappa}
mat = [[40, 10], [5, 45]]
result = compute_kappa(mat)
print(f"Po={result['po']:.3f}, Pe={result['pe']:.3f}, κ={result['kappa']:.3f}")
# Po=0.850, Pe=0.500, κ=0.7009.2 Step 2: 라이브러리 활용 (실무)
# R — Cohen's Kappa (2인), Fleiss' Kappa (3인+), ICC
library(irr)
# ── Cohen's Kappa (2인, 명목형) ───────────────────────────────
rater_a <- c("Pos", "Pos", "Neg", "Neg", "Pos")
rater_b <- c("Pos", "Neg", "Neg", "Neg", "Pos")
raters <- data.frame(A = rater_a, B = rater_b)
kappa2(raters)
# κ = 0.60 등 출력 (Kappa statistic, z, p-value)
# ── Fleiss' Kappa (3인 이상, 명목형) ─────────────────────────
# n개 항목 × m명 판정자 행렬 (각 셀에 부여된 범주)
ratings <- matrix(c(
1, 1, 2,
2, 2, 2,
1, 1, 1,
2, 1, 2
), nrow = 4, byrow = TRUE)
kappam.fleiss(ratings)
# ── ICC (연속형, 신뢰도 맥락) ────────────────────────────────
# 4명 판정자가 10개 항목에 대해 연속형 점수 부여
set.seed(42)
scores <- matrix(round(rnorm(40, mean = 5, sd = 1), 1), nrow = 10, ncol = 4)
# ICC(2,1) Agreement 형 — 규제 검증 권장
icc(scores, model = "twoway", type = "agreement", unit = "single")
# ICC, 95% CI, F-value, p-value 출력
# ICC(2,k) Agreement 형 — k명 평균 보고 시
icc(scores, model = "twoway", type = "agreement", unit = "average")# Python — Cohen's Kappa (sklearn), ICC (pingouin)
from sklearn.metrics import cohen_kappa_score
import pingouin as pg
import pandas as pd
import numpy as np
# ── Cohen's Kappa ─────────────────────────────────────────────
y1 = [1, 1, 0, 0, 1]
y2 = [1, 0, 0, 0, 1]
kappa = cohen_kappa_score(y1, y2)
print(f"Cohen's κ = {kappa:.3f}")
# ── ICC (pingouin) ─────────────────────────────────────────────
np.random.seed(42)
data = pd.DataFrame({
"Subject": np.repeat(range(1, 11), 4),
"Rater": list(range(1, 5)) * 10,
"Score": np.random.normal(loc=5, scale=1, size=40).round(1)
})
# ICC(2,1) Agreement 형
icc_result = pg.intraclass_corr(data = data,
targets = "Subject",
raters = "Rater",
ratings = "Score")
# ICC2 (two-way random, single, absolute agreement) 행 선택
print(icc_result[icc_result["Type"] == "ICC2"])9.3 Step 3: 결과 해석 출력 함수
# 결과를 Landis & Koch 기준으로 자동 해석
interpret_kappa <- function(k) {
if (k < 0) "Poor (worse than chance)"
else if (k < 0.20) "Slight"
else if (k < 0.40) "Fair"
else if (k < 0.60) "Moderate"
else if (k < 0.80) "Substantial"
else "Almost Perfect"
}
k_val <- 0.70
cat(sprintf("κ = %.3f → %s\n", k_val, interpret_kappa(k_val)))
# κ = 0.700 → Substantial10 자주 발생하는 오류
10.1 단순 일치율(Percent Agreement)로 보고
WRONG: "두 판정자의 일치율은 85%로 높다"
CORRECT: "관측 일치율은 85%이지만 우연 일치율이 50%이므로 κ = 0.70이다"
단순 일치율은 범주 분포가 불균형할 때 매우 높게 나올 수 있다. 예를 들어 99%가 음성인 데이터셋에서 두 판정자 모두 “항상 음성”으로 판정해도 일치율은 99%가 된다. Kappa는 이 문제를 \(P_e\) 보정으로 해결한다.
10.2 연속형 데이터에 Kappa 사용
WRONG: 통증 점수(1-10)에 Cohen's Kappa 적용
CORRECT: 통증 점수(1-10)에 ICC(2,1) Agreement 형 적용
순서형·연속형 데이터에 Kappa를 쓰면 인접 범주 불일치(3점 vs 4점)와 극단 불일치(1점 vs 10점)를 동일하게 취급하는 문제가 생긴다. 이를 부분적으로 해결하는 Weighted Kappa도 있지만, 이 경우 ICC가 더 자연스럽다.
10.3 ICC Agreement 형과 Consistency 형 혼동
규제 문서에서 “ICC = 0.85”만 보고하면 어떤 모형인지 알 수 없다. 반드시 ICC(2,1) agreement 또는 ICC(3,k) consistency 형태로 명시한다.
11 관련 주제
선행 지식
- 상관계수를 예측 정확도로 쓰면 안 되는 이유 — Agreement vs Correlation 개념적 차이
- 범주형 데이터 분석 — 분할표(contingency table) 기초
후속 주제
- 왜 Mixed Model인가 (GLM 한계, ICC, Fixed/Random) — 혼합 모형 맥락의 ICC
- Binary Classification Statistics — Sensitivity, Specificity, CMH 등 알고리즘 평가 지표