igor-millis~/research/calibration-check
EN/PT
← todos os artigos

τ = 0,24 é mesmo uma razão de custos?

Verificando a ressalva da nota anterior: os escores são calibrados, recalibrar ajuda e quão ruidoso é o threshold ótimo?

A nota anterior, “Um threshold é uma decisão”, leu o threshold operacional do modelo Credit Default como uma razão de custos — \(\tau = 0{,}24\) significa que deixar passar um inadimplente custa cerca de \(3{,}2\times\) um falso alarme — e terminou com uma ressalva: essa leitura só vale se os escores forem probabilidades calibradas. Esta nota faz a verificação.

§1O que é “calibrado”

Um escore \(\hat p\) é calibrado quando, entre todos os clientes que recebem o escore \(p\), uma fração \(p\) de fato fica inadimplente:

\[ \Pr\big(Y = 1 \mid \hat p(X) = p\big) = p \quad \text{para todo } p. \](1)

A qualidade de ordenação (ROC AUC) não diz nada sobre isso: qualquer transformação crescente de \(\hat p\) tem a mesma AUC. Três medidas, todas calculadas no conjunto de teste intocado:

\[ \text{Brier} = \frac1N\sum_{i}(\hat p_i - y_i)^2, \qquad \text{ECE} = \sum_{b=1}^{10}\frac{n_b}{N}\,\big|\bar p_b - \bar y_b\big|, \](2)

além da log loss. O ECE (erro de calibração esperado) compara, em cada um de 10 bins de probabilidade, a probabilidade prevista média \(\bar p_b\) com a taxa de inadimplência observada \(\bar y_b\).

§2Protocolo

  • O mesmo split do projeto. Treino/teste 80/20 estratificado e depois treino/validação 80/20, ambos com random_state = 42.
  • Modelo salvo. O pipeline de produção foi re-treinado nas 24.000 linhas de treino, então é avaliado apenas nas 6.000 de teste.
  • Recalibrar exige dados que o modelo nunca viu. Os mesmos hiperparâmetros foram re-treinados nas 19.200 linhas; Platt scaling (regressão logística sobre o logit) e regressão isotônica foram ajustados nas 4.800 de validação; tudo foi avaliado no teste.
  • Checagem. O refit reproduz o notebook exatamente: \(\tau = 0{,}24\), F1 = 0,5405 e ROC AUC = 0,7833 na validação. O modelo salvo dá ROC AUC = 0,7770 no teste, como reportado.

§3Resultado: os escores já são calibrados

modelo salvo · conjunto de teste · 10 binsn = 6.000
y: taxa de inadimplência observada · x: probabilidade prevista média0,000,000,250,250,500,500,750,751,001,00calibração perfeitap̄ = 0,067 · obs = 0,070 · n = 1.697p̄ = 0,144 · obs = 0,147 · n = 2.297p̄ = 0,240 · obs = 0,230 · n = 674p̄ = 0,344 · obs = 0,360 · n = 394p̄ = 0,446 · obs = 0,453 · n = 225p̄ = 0,551 · obs = 0,551 · n = 158p̄ = 0,655 · obs = 0,617 · n = 240p̄ = 0,748 · obs = 0,717 · n = 237p̄ = 0,834 · obs = 0,855 · n = 76n1.6972.297674394225158240237762
Cada ponto é um bin de probabilidade prevista (área ∝ n); a faixa de baixo mostra quantos clientes caem em cada bin. O bin 0,9–1,0 (n = 2) não é plotado. Fonte: research/calibration/calibration.py.

Os pontos ficam sobre a diagonal. No conjunto de teste inteiro, a probabilidade prevista média é 0,2213, contra uma taxa real de inadimplência de 0,2212, e o ECE = 0,0076 (intervalo bootstrap de 95%: 0,007–0,020; o ECE é viesado para cima em amostras finitas, por isso o intervalo pende para a direita). As maiores diferenças são uma leve superconfiança nos bins de 0,6 a 0,8 (previsto 0,66 contra observado 0,62, e 0,75 contra 0,72) — com cerca de 240 clientes por bin, isso dá cerca de 1 a 1,2 erro-padrão, dentro do ruído.

modeloBrierlog lossECEROC AUCp̂ médiog(0,24)cFN/cFP
salvo (24k)0,13550,43100,00760,77700,22130,2403,17×
refit, bruto0,13520,43010,01240,77940,22080,2403,17×
refit + Platt0,13520,43000,00980,77940,22320,2443,11×
refit + isotônica0,13560,43940,01020,77810,22380,2722,68×

Conjunto de teste (n = 6.000, taxa real de inadimplência = 0,2212). Calibradores ajustados na validação (n = 4.800). g(0,24) = probabilidade calibrada correspondente ao threshold bruto 0,24.

A recalibração confirma pelo outro lado. O mapa de Platt ajustado é \(\operatorname{logit} g(p) = 0{,}978\,\operatorname{logit} p - 0{,}006\) — quase a identidade. A regressão isotônica chega a piorar a log loss (0,4394 contra 0,4301): com 4.800 linhas de validação, sua função em degraus ajusta ruído.

§4Então τ = 0,24 é uma razão de custos?

Sim, aproximadamente. A recalibração é monótona, então não muda nenhuma decisão — muda apenas o que o threshold significa. Passando o corte bruto por cada calibrador, obtém-se

\[ \frac{c_{FN}}{c_{FP}} = \frac{1 - g(0{,}24)}{g(0{,}24)} \in [\,2{,}7;\; 3{,}2\,]. \](3)

A leitura de negócio se sustenta: o modelo trata deixar passar um inadimplente como cerca de três vezes mais caro que um falso alarme. Agora isso é uma afirmação defensável, não uma premissa.

§5Uma correção: o próprio threshold é ruidoso

A nota anterior comparou o ótimo empírico 0,24 com o threshold teórico que maximiza o F1 para escores calibrados, \(F1^{*}/2 \approx 0{,}27\), e atribuiu a diferença a uma calibração imperfeita. A calibração está boa, então essa explicação estava errada. Reamostrando a validação 500 vezes e recalculando o threshold ótimo para F1, obtém-se um intervalo bootstrap de 95% de [0,22; 0,33] (mediana 0,24). A curva de F1 na validação é plana — entre 0,532 e 0,541 para todo \(\tau\) de 0,22 a 0,30 —, então 0,27 está bem dentro do ruído. A diferença é variabilidade amostral, não descalibração.

§6Conclusões

  • Verifique a calibração antes de ler escores como probabilidades — e antes de “corrigi-la”. Aqui, recalibrar acrescentaria um componente sem melhorar nada.
  • Recalibrar tem custo: a regressão isotônica sobreajusta conjuntos de calibração pequenos. Platt scaling é o padrão mais seguro quando há poucos dados.
  • Um threshold ótimo é uma estimativa. Reporte sua incerteza; numa função objetivo plana, 0,24 contra 0,27 não significa nada.
  • Com a calibração verificada, a probabilidade devolvida pela API pode ser lida literalmente: um cliente com escore 0,30 pertence a um grupo em que cerca de 30% ficam inadimplentes.

Código e resultados: research/calibration/ (scikit-learn 1.9.0, xgboost 3.3.0) · Modelo: github.com/Igor-Millis/credit-default-api · Platt, J. (1999), Probabilistic outputs for support vector machines; Niculescu-Mizil & Caruana (2005), Predicting good probabilities with supervised learning, ICML.