확률 보정: 분류 모델의 0.8을 실제 위험 80%로 해석할 수 있는 조건
확률 보정은 분류 모델이 출력한 점수와 실제 발생 빈도를 맞추는 과정이다. 모델이 predict_proba=0.8을 냈다는 사실만으로 한 사례의 위험이 정확히 80%라고 보장되지는 않는다. 같은 조건에서 0.8 근처 점수를 받은 사례를 충분히 모았을 때 실제 양성 비율도 약 80%여야 그 값을 운영상 위험 확률로 읽을 수 있다.
이 글은 scikit-learn 공식 문서와 원 논문을 대조하고, 2026년 8월 6일 수행한 합성 데이터 통제 실험으로 작은 보정 표본의 실패를 확인한 결과를 다룬다. 실험은 Python 3.12.3 표준 라이브러리로 sigmoid와 isotonic을 직접 구현한 것이며, scikit-learn 패키지 자체나 실제 의료·신용 데이터를 실행한 결과는 아니다.
20초 핵심 요약
- 무엇: 0.8 점수가 집단 수준의 실제 발생률 80%로 해석될 수 있는 조건을 확률 보정 실험으로 확인한다.
- 왜: 한 사례의 predict_proba 값만으로 숨은 참확률을 단정하면 표본 부족과 데이터 이동을 놓칠 수 있기 때문이다.
- 어떻게: 독립된 보정·테스트 세트에서 reliability curve, Brier·log loss, 오류 비용과 배포 후 안정성을 함께 확인한다.
핵심 요약
- 무엇: 0.8은 한 건의 숨은 참확률이 아니라 같은 조건의 0.8 점수대에서 관측되는 집단적 발생률이다.
- 왜: 데이터 이동, 표본 부족, 평가 데이터 재사용이 있으면 보정된 듯한 점수도 배포 환경에서 무너질 수 있다.
- 어떻게: 독립된 보정·테스트 세트에서 reliability curve, Brier와 log loss, 오류 비용을 함께 비교한다.
0.8을 실제 위험 80%로 읽으려면 여섯 조건이 필요하다
잘 보정된 이진 분류기에서 0.8은 “0.8 근처를 예측한 표본 가운데 약 80%가 양성”이라는 뜻이다. 특정 사례는 결과가 0 또는 1로 한 번 관측될 뿐이므로, 그 사례의 숨은 참확률이 정확히 0.8인지 직접 확인할 수는 없다. 정확한 표현은 “정의된 모집단에서 이 점수대의 장기 발생률이 0.8에 부합한다”다. 이 집단적 정의와 reliability diagram의 해석은 scikit-learn Probability calibration에서 확인할 수 있다.
이 해석에는 다음 조건이 붙는다.
- 사건 정의가 같아야 한다. positive class, 예측 시점, 관측 기간, 라벨 확정 규칙이 일치해야 한다. “30일 내 발생”과 “언젠가 발생”은 같은 위험이 아니다.
- 평가 표본이 배포 모집단을 대표해야 한다. 기본 발생률, 입력 분포, 정책에 따른 표본 선택이 달라지면 과거의 점수-결과 관계를 그대로 옮길 수 없다.
- 0.8 근처 사례가 충분해야 한다. 8/10과 800/1,000은 관측률이 모두 0.8이지만 불확실성은 다르다. 점과 함께 표본 수와 양성 수, 가능하면 신뢰구간을 봐야 한다.
- 모델 선택 이후까지 독립인 데이터로 평가해야 한다. 기본 모델뿐 아니라 calibrator와 보정 방법을 고르는 데도 쓰지 않은 테스트 세트가 필요하다.
- 운영상 중요한 하위집단에서도 관계가 유지돼야 한다. 전체 평균의 과대예측과 과소예측이 지역·장비·성별·기간 사이에서 서로 상쇄될 수 있다.
- 배포 뒤에도 안정성을 추적해야 한다. 기본 발생률이나
P(Y=1 | score)가 바뀌면 과거 mapping도 깨진다. 라벨 지연을 고려해 시간별 검증과 재보정 조건을 둬야 한다.
이 조건들은 모델의 출력 형식을 확률처럼 보이게 만드는 것과 그 숫자를 의사결정에 쓸 수 있게 검증하는 것이 서로 다른 일임을 보여준다.
calibration curve는 대각선보다 표본 수를 먼저 본다
reliability diagram 또는 calibration curve는 예측값을 bin으로 묶는다. x축에는 각 bin의 평균 예측확률, y축에는 실제 양성 비율을 놓는다. 점이 대각선 아래에 있으면 해당 구간에서 과대확신했고, 위에 있으면 과소확신한 것이다.
scikit-learn의 calibration_curve에서 strategy='uniform'은 0부터 1까지를 같은 폭으로 나누고, quantile은 각 bin에 비슷한 수의 표본이 들어가게 나눈다. uniform은 확률 구간을 보존하지만 데이터가 드문 영역에 빈 bin이 생길 수 있다. quantile은 점마다 표본 수를 비슷하게 만들지만 각 구간의 폭이 달라진다. 빈 bin은 결과에서 빠지므로 요청한 bin 수보다 점이 적을 수도 있다. 이 동작은 calibration_curve API 문서에 명시돼 있다.
bin을 늘리면 국소 왜곡을 자세히 볼 수 있지만 각 점의 표본이 줄어 변동이 커진다. 그래서 curve만 그리지 말고 예측확률 histogram, bin별 전체 건수와 양성 수를 함께 둬야 한다. 통제 실험의 독립 테스트에서도 0.8~0.9 uniform bin의 sigmoid 결과는 72건에 평균 예측 0.848, 실제 발생률 0.833이었다. 숫자는 가까워 보이지만 72건이라는 근거의 크기를 빼고 “0.85가 검증됐다”고 단정할 수는 없다.

Brier score가 낮아도 보정만 좋아졌다고 말할 수 없다
이진 Brier loss는 다음과 같이 실제 라벨과 예측확률의 제곱 차이를 평균하며 0이 최선이다.
BS = (1/N) Σ(y_i - p_i)²
확률 예측 전체를 평가하는 proper scoring rule이지만 보정 오차만 분리해 재는 값은 아니다. Murphy의 원 논문이 제시한 decomposition 관점에서는 reliability뿐 아니라 결과를 서로 다른 위험군으로 가르는 resolution과 데이터 자체의 uncertainty도 섞인다. scikit-learn의 Brier score 설명도 낮은 값이 더 나은 calibration을 반드시 뜻하지는 않는다고 주의한다. 서로 다른 특징이나 모델의 Brier를 비교해 값이 낮다는 이유만으로 “더 잘 보정됐다”고 결론 내리면 안 된다.
log loss는 참 클래스에 0에 가까운 확률을 준 극단적 오류에 더 민감하다. ROC-AUC나 PR-AUC는 순위와 분류 성능을 보는 별도 목적의 지표다. 배포 판단에는 다음 묶음이 필요하다.
- reliability curve와 bin별 전체 건수·양성 수
- Brier loss와 log loss
- 별도로 보는 ROC-AUC 또는 PR-AUC
- 보정된 확률에 임계값을 적용한 FP·FN 업무 비용
- 기간과 주요 하위집단별 반복 결과
Brier 정의도 확인해야 한다. 이진 양성 클래스 하나만 계산하면 범위는 [0,1]이지만 모든 클래스를 합산하는 원래 다중분류 정의는 [0,2]다. scikit-learn 결과를 다른 구현과 비교할 때에는 정의와 scale_by_half 설정이 같은지 먼저 확인한다.
sigmoid와 isotonic은 유연성과 분산을 교환한다
sigmoid, 즉 Platt scaling은 원래 점수 f를 1/(1+exp(Af+B)) 형태로 바꾸고 두 매개변수를 최대우도로 학습한다. 형태가 제한된 만큼 작은 표본에서 비교적 안정적이며 엄격한 단조 변환이라 일반적으로 순위도 보존한다. 반대로 실제 왜곡이 sigmoid 모양과 다르면 충분히 고치지 못한다. 심한 클래스 불균형에서 클래스별 점수 분산 차이가 큰 경우에도 가정이 맞지 않을 수 있다.
isotonic regression은 점수가 커질수록 보정확률이 감소하지 않는다는 단조 제약 아래 계단 함수를 학습한다. 다양한 단조 왜곡을 표현할 수 있지만 자유도가 커서 작은 보정 세트에 과적합하기 쉽다. 계단의 tie 때문에 ROC-AUC가 미세하게 달라질 수 있고, 끝 구간이 0이나 1이 되면 독립 데이터의 반대 사례 한 건이 log loss를 크게 악화시킬 수 있다.
scikit-learn 문서에 나오는 isotonic의 “약 1,000개 초과”는 보장된 최소 표본 수가 아니다. Niculescu-Mizil과 Caruana의 2005년 연구가 여러 벤치마크에서 calibration set 크기를 바꿔 얻은 경험적 경향이다. scikit-learn Probability calibration 문서도 작은 표본에서 isotonic이 과적합하는 경향을 설명한다. 전체 건수 외에도 양성 사례 수, 점수 구간별 밀도, 왜곡 형태와 독립 테스트 결과를 함께 봐야 한다.
실무에서는 보정하지 않은 모델, sigmoid, isotonic을 모두 후보로 두는 편이 안전하다. 작은 표본이나 희귀 양성에서는 sigmoid를 안정적인 기준선으로 먼저 검토한다. 충분한 표본에서 비-sigmoid 형태의 단조 왜곡이 관측되고 독립 테스트에서도 이득이 유지될 때 isotonic의 유연성을 채택한다. 이미 잘 보정된 모델이거나 차이가 불확실하다면 보정하지 않는 선택도 가능하다.
train, calibration, test를 세 단계로 분리한다
가장 명확한 데이터 흐름은 train → calibration → test다. train으로 기본 분류기를 학습하고, calibration에는 고정된 모델이 보지 않은 표본의 점수와 라벨만 넣는다. test는 sigmoid와 isotonic을 포함한 방법 선택이 모두 끝날 때까지 봉인한다.
학습 점수를 calibrator에 다시 주면 기본 모델이 외운 결과까지 확률 관계로 학습할 수 있다. calibration set으로 mapping을 맞춘 뒤 같은 세트의 지표로 방법을 고르는 것 역시 독립 평가가 아니다. 기본 모델과 calibrator의 데이터만 분리하는 데서 끝나지 않고, 최종 선택용 test까지 분리해야 한다. 학습 데이터와 보정 데이터 분리의 근거는 Niculescu-Mizil과 Caruana의 원 연구에 제시돼 있다.
데이터가 작을 때 scikit-learn의 CalibratedClassifierCV는 CV split의 train subset에서 기본 모델을 학습하고 test subset의 out-of-fold 점수로 calibrator를 맞춘다. 기본 ensemble=True에서는 fold별 classifier와 calibrator가 낸 확률을 평균한다. 이미 학습된 모델을 FrozenEstimator로 감싸는 경우에는 그 모델의 학습 데이터와 calibrator 데이터가 겹치지 않도록 사용자가 책임져야 한다. 각 fold 양쪽에 모든 클래스가 나타나도록 stratified split과 최소 양성 수도 확인해야 한다. 이 교차검증 흐름과 사용자 분리 책임은 scikit-learn 공식 보정 문서에 설명돼 있다.
시간 의존적인 위험 모델이라면 무작위 분할보다 과거 train, 다음 기간 calibration, 가장 최근 기간 test가 배포 상황에 가깝다. 정책 개입 때문에 라벨이 선택적으로 관측된다면 단순 재보정만으로 그 선택 편향까지 해결할 수는 없다.
작은 표본 isotonic은 학습 세트에서만 가장 좋아 보였다
통제 실험은 고정 seed 20260805로 불균형 이진 합성 데이터를 만들고 점수를 의도적으로 단조 왜곡했다. 보정 120건과 독립 테스트 8,000건에서 보정하지 않은 점수, 직접 구현한 sigmoid, PAV 방식 isotonic을 비교했다. FP 비용 1, FN 비용 9, 확률 임계값 0.1에서 건당 비용도 측정했다.
아래는 프로젝트 루트에서 Python 3.12.3 표준 라이브러리 재현 스크립트를 실행한 핵심 출력이며 종료 상태는 0이었다. 실제 scikit-learn 구현이나 교차검증 ensemble을 실행한 결과가 아니라 데이터 분리 실패를 관찰하기 위한 통제 실험이다.
python 3.12.3 seed=20260805 calibration=120 test=8000 prevalence=0.1756
uncalibrated cal Brier=0.16076 logloss=0.49869 cost=0.85000 | test Brier=0.16448 logloss=0.50719 cost=0.81525
sigmoid cal Brier=0.08217 logloss=0.26149 cost=0.36667 | test Brier=0.10962 logloss=0.36020 cost=0.58025
isotonic cal Brier=0.06966 logloss=0.21857 cost=0.27500 | test Brier=0.11673 logloss=0.89738 cost=0.75225
isotonic_steps 62
exit_status=0

보정에 쓴 120건을 평가에도 재사용하면 isotonic의 Brier 0.06966, log loss 0.21857, 비용 0.27500이 모두 가장 좋아 보인다. 그러나 미사용 8,000건에서는 sigmoid보다 Brier가 0.00711, log loss가 0.53718, 비용이 0.17200 나빴다. 실행 오류가 아니라 평가 데이터를 재사용한 방법론적 실패다. 특히 작은 표본에서 만들어진 0과 1의 계단 출력이 독립 사례의 log loss를 크게 손상했다.
보정 표본을 3,000건으로 늘린 별도 실험에서는 테스트 Brier가 sigmoid 0.10805, isotonic 0.10872였고 log loss는 0.34723과 0.35948, 비용은 0.51425와 0.51787로 가까워졌다. 작은 표본 과적합과 큰 표본에서의 수렴이라는 방향은 공식 문서와 원 연구에 부합한다. 그래도 세 지표 모두 sigmoid가 근소하게 좋았으므로 “1,000건을 넘으면 isotonic이 우위”라는 절대 규칙은 성립하지 않는다. 두 표본 크기의 테스트 데이터가 서로 달라 표본 크기 효과의 엄밀한 paired estimate로도 해석하지 않는다.
배포 결정은 보정도와 오류 비용을 함께 통과해야 한다
보정은 확률 척도를 바꾼다. 기존 모델에서 쓰던 0.5 같은 숫자 임계값을 그대로 유지하면 조치 건수와 FP·FN 비용도 달라질 수 있다. 확률이 정확하고 비용이 사례마다 같다는 단순 가정에서는 FP 비용이 C_FP, FN 비용이 C_FN일 때 임계값을 C_FP/(C_FP+C_FN)로 둘 수 있지만, 용량 제한·조치 효과·사례별 비용·공정성 제약이 있으면 이 공식도 달라진다.
배포 전에는 다음 순서로 확인한다.
- positive class, 예측 시점, 관측 기간과 라벨 확정 규칙을 고정한다.
- 기본 모델 학습, calibrator 학습, 최종 평가 데이터의 독립성을 확인한다.
- 보정하지 않음, sigmoid, isotonic을 같은 미사용 holdout에서 비교한다.
- reliability curve에 bin count와 불확실성을 붙이고 Brier·log loss를 함께 본다.
- 새 확률 척도에서 임계값을 다시 정한 뒤 실제 FP·FN 비용을 평가한다.
- 시간과 주요 하위집단에서 관계가 유지되는지 확인하고 재보정·보류 기준을 정한다.
작은 보정 세트에서는 sigmoid를 우선 후보로 삼고 isotonic은 보류하는 판단이 합리적이다. 양성 사례와 점수 구간 밀도가 충분한 뒤에도 독립 시간 holdout의 reliability, proper score와 업무 비용이 함께 유지될 때만 더 유연한 방법을 채택한다. 보정 오차가 줄어도 비용이 악화되면 임계값을 다시 검증하고, 그래도 개선되지 않으면 배포하지 않는다.
이 통제 결과는 실제 의료·신용 위험, 라벨 지연, censoring, 시간 이동, 그룹 공정성이나 다중분류를 검증하지 않았다. 배포 데이터에서는 0.8 점수대의 신뢰구간과 별도 시간 holdout을 다시 마련해야 한다. 확률의 의미를 검증한 다음 단계는 분류 임계값과 오류 비용에서 보정된 확률을 실제 조치 기준으로 옮기는 것이다.