Um classificador como o XGBoost não entrega uma decisão. Ele entrega um escore \(\hat p(x) \in [0,1]\), e a decisão só aparece quando escolhemos uma regra:
As bibliotecas usam \(\tau = 0{,}5\) por padrão. Esse padrão parece neutro, mas não é: ele embute uma crença específica sobre o custo dos erros. No projeto Credit Default, mover \(\tau\) de 0,50 para 0,24 elevou o recall dos inadimplentes de 35,6% para 60,1% — uma mudança maior que a de qualquer busca de hiperparâmetros.
§1A visão de custos
Seja \(c_{FP}\) o custo de sinalizar um cliente que pagaria (falso positivo) e \(c_{FN}\) o custo de deixar passar um inadimplente (falso negativo). Para um cliente com probabilidade real de inadimplência \(p\), o custo esperado de cada ação é
Prever “inadimplente” é a melhor ação sempre que \(p\,c_{FN} \ge (1-p)\,c_{FP}\), o que leva ao threshold ótimo de Bayes
Ou seja, \(\tau = 0{,}5\) é ótimo apenas se os dois erros custam o mesmo. Invertendo (3), todo threshold implica uma razão de custos:
Lido ao pé da letra: escolher 0,24 diz que deixar passar um inadimplente custa cerca de três vezes mais que um falso alarme. É uma afirmação com a qual uma equipe de crédito pode concordar ou discordar — e esse é justamente o ponto. Um threshold transforma uma premissa de negócio em um número.
§2O que o projeto fez de fato
Não havia custos explícitos, então o threshold foi escolhido por um objetivo substituto: maximizar o F1 na validação (4.800 clientes, nunca usados na avaliação final). A busca em grade resultou em \(\tau = 0{,}24\), com F1 de validação = 0,5405. No conjunto de teste intocado (6.000 clientes), o mesmo threshold deu F1 = 0,5396 e recall = 0,6006 — quase nenhuma degradação, bom sinal de que a escolha não sofreu overfitting.
O explorador abaixo usa a curva do conjunto de teste do notebook de seleção de modelos (grade de 0,05) para mostrar todo o trade-off e a razão de custos que cada \(\tau\) implica:
§3Uma checagem pela literatura
Para um classificador calibrado, o threshold que maximiza o F1 é igual à metade do F1 máximo atingível (Lipton, Elkan & Narayanaswamy, 2014):
Com \(F1^{*} \approx 0{,}54\) na validação, (5) prevê \(\tau \approx 0{,}27\). O ótimo empírico, 0,24, fica próximo. Atualização: a nota seguinte verifica a calibração — os escores são bem calibrados e a diferença é ruído amostral: o intervalo bootstrap de 95% do threshold ótimo de F1 é [0,22; 0,33]. Isso também explica por que thresholds ótimos para F1 costumam ficar bem abaixo de 0,5: o F1 é no máximo 1, então, para um modelo calibrado, o threshold ótimo nunca passa de 0,5.
§4Conclusões
- O threshold faz parte do modelo. Reporte, justifique e versione — por isso a API devolve o threshold em toda previsão.
- Escolha \(\tau\) na validação, nunca no teste. O teste serve para um único número final e honesto.
- Se os custos são conhecidos, use (3). Se não, um substituto como o F1 funciona — mas traduza o resultado de volta em razão de custos com (4) e pergunte se faz sentido.
- Verifique a calibração antes de ler escores como probabilidades.
Referência: Z. C. Lipton, C. Elkan, B. Narayanaswamy. Thresholding Classifiers to Maximize F1 Score. ECML PKDD, 2014. · Dados: github.com/Igor-Millis/credit-default-api, notebooks 09 e 010.