Objetivo da Aula
Ao concluir esta aula, você será capaz de:
Calcular Paridade Demográfica: diferença de taxa de aprovação entre grupos
Calcular Igualdade de Oportunidade (True Positive Rate) por grupo
Implementar calcular_equidade(dataset) com as métricas de fairness
Implementar sugerir_mitigacao(metricas, equidade) via LLM
Explicar o teorema de impossibilidade de Chouldechova
Por que isso importa
Um modelo de contratação que rejeita 80% do grupo B e 40% do grupo A pode estar perfeitamente calibrado por features técnicas — e ainda assim ser discriminatório. Paridade demográfica detecta isso. Mas nem toda disparidade é viés: se grupos diferem sistematicamente em features relevantes, alguma disparidade de resultado é esperada. A tensão entre essas métricas é o núcleo da ética em ML.
Fundamento: Métricas de Fairness e Teorema de Impossibilidade
Três métricas frequentes de equidade algorítmica: Paridade Demográfica — taxa de resultados favoráveis igual entre grupos; Igualdade de Oportunidade — taxa de verdadeiro positivo (TPR) igual entre qualificados de grupos diferentes; Calibração — o score de probabilidade reflete a frequência real de ocorrência. O teorema de Chouldechova prova que essas métricas são matematicamente incompatíveis quando as taxas base diferem entre grupos — você não consegue otimizar todas ao mesmo tempo. Consequência de design: escolha a métrica com base no custo do erro — falso positivo ou falso negativo tem peso diferente dependendo do contexto (crédito vs saúde vs segurança pública).
Conceitos Fundamentais
Paridade Demográfica
Definição: grupos devem ter taxas de aprovação iguais
P(Aprovado | Grupo A) ≈ P(Aprovado | Grupo B)
Threshold prático: disparidade > 0.1 (10 pp) merece investigação
Disparidade > 0.2 (20 pp): problema sérioIgualdade de Oportunidade (Equal Opportunity)
Foca nos candidatos qualificados: entre os que merecem aprovação,
a taxa de aprovação deveria ser igual entre grupos.
Definição formal:
P(Aprovado | Qualificado, Grupo A) ≈ P(Aprovado | Qualificado, Grupo B)
"Qualificado" = score_tecnico >= 80 (no dataset de exemplo)TODO 1: calcular_equidade(dataset)
def calcular_equidade(dataset: list[dict]) -> dict:
from collections import defaultdict
por_grupo = defaultdict(list)
for row in dataset:
por_grupo[row["grupo"]].append(row)
# 1. Paridade demográfica: diferença de taxas de aprovação
taxa_por_grupo = {}
for grupo, rows in por_grupo.items():
total = len(rows)
aprovados = sum(1 for r in rows if r["decisao"] == "CONTRATADO")
taxa_por_grupo[grupo] = aprovados / total
grupos = sorted(taxa_por_grupo.keys())
if len(grupos) >= 2:
paridade_demografica = abs(taxa_por_grupo[grupos[0]] - taxa_por_grupo[grupos[1]])
else:
paridade_demografica = 0.0
# 2. Igualdade de oportunidade (TPR por grupo)
# Candidato "qualificado" = score_tecnico >= 80
igualdade_oportunidade = {}
for grupo, rows in por_grupo.items():
qualificados = [r for r in rows if r.get("score_tecnico", 0) >= 80]
if qualificados:
aprovados_qualif = sum(1 for r in qualificados if r["decisao"] == "CONTRATADO")
igualdade_oportunidade[grupo] = round(aprovados_qualif / len(qualificados), 3)
else:
igualdade_oportunidade[grupo] = None
# 3. Disparidade total
if len(grupos) >= 2 and all(igualdade_oportunidade.get(g) is not None for g in grupos):
disparidade_tpr = abs(igualdade_oportunidade[grupos[0]] - igualdade_oportunidade[grupos[1]])
else:
disparidade_tpr = None
return {
"paridade_demografica": round(paridade_demografica, 3),
"taxa_aprovacao_por_grupo": {g: round(t, 3) for g, t in taxa_por_grupo.items()},
"igualdade_oportunidade": igualdade_oportunidade,
"disparidade_tpr": round(disparidade_tpr, 3) if disparidade_tpr is not None else None,
"alerta": paridade_demografica > 0.1,
}TODO 2: sugerir_mitigacao(metricas, equidade)
def sugerir_mitigacao(metricas: dict, equidade: dict) -> str:
grupos = equidade.get("taxa_aprovacao_por_grupo", {})
grupos_str = "\n".join(f" Grupo {g}: {taxa*100:.0f}% aprovados" for g, taxa in grupos.items())
paridade = equidade.get("paridade_demografica", 0)
tpr = equidade.get("igualdade_oportunidade", {})
tpr_str = "\n".join(f" Grupo {g}: TPR={v}" for g, v in tpr.items())
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=400,
system="Você é especialista em ética em IA e fairness em ML.",
messages=[{
"role": "user",
"content": f"""Análise de equidade em sistema de contratação:
Taxas de aprovação por grupo:
{grupos_str}
Paridade demográfica (diferença): {paridade:.1%} {'⚠️ ALERTA' if paridade > 0.1 else '✓ OK'}
True Positive Rate (entre candidatos qualificados):
{tpr_str}
Gere 3 estratégias concretas de mitigação, priorizando:
1. Rebalanceamento de dados de treino
2. Ajuste de threshold por grupo
3. Revisão humana dos casos limítrofes""",
}],
)
return response.content[0].textAprofundamento Técnico
Teorema de Impossibilidade de Chouldechova (2017)
Quando dois grupos têm prevalências (taxas base) diferentes, é matematicamente impossível satisfazer simultaneamente: - Paridade Demográfica (mesma taxa de aprovação) - Calibração (mesma probabilidade de ser qualificado dado aprovado) - Igualdade de Oportunidade (mesmo TPR)
Implicação prática: você precisa ESCOLHER qual métrica priorizar.
Essa escolha é uma decisão ética, não técnica.
Em crédito: priorizar Igualdade de Oportunidade
→ candidatos igualmente qualificados têm a mesma chance
Em medicina diagnóstica: priorizar Paridade em FNR
→ não deixar doenças graves não diagnosticadas em nenhum grupoExemplos Anotados
Exemplo 1: Dataset com Viés Embutido
# Dataset: 100 decisões, viés embutido de 20% no grupo B
metricas = calcular_metricas_basicas(DATASET)
# Grupo A: 65% aprovados
# Grupo B: 45% aprovados ← 20pp de diferença!
equidade = calcular_equidade(DATASET)
# → paridade_demografica: 0.20 ← ALERTA
# → igualdade_oportunidade: {A: 0.90, B: 0.70} ← candidatos qualificados do grupo B têm 20% menos chance!Padrões e Armadilhas
Padrões
Padrão 1: Medir antes de corrigir
# Sempre medir equidade no dataset atual ANTES de tentar corrigir
# Sem baseline, não há como medir o impacto das correçõesPadrão 2: Documentar a escolha de métrica e o motivo
Decisão: priorizamos Igualdade de Oportunidade (TPR) em vez de Paridade Demográfica
Motivo: candidatos igualmente qualificados não devem ser penalizados por pertencer a grupos historicamente sub-representadosArmadilhas
⚠️ Armadilha 1: Paridade demográfica = remover features de grupo
Remover "gênero" ou "raça" do dataset não resolve viés —
as features correlacionadas (CEP, escola, etc.) reproduzem o mesmo viés⚠️ Armadilha 2: Threshold global vs threshold por grupo
Threshold 0.6 global pode ser mais fácil de atingir para grupo A
Threshold 0.5 para A e 0.55 para B pode equacionar o TPR
→ é uma decisão de negócio e ética, não apenas técnicaSe não for realizar o laboratório, pule para o próximo capítulo.
Ponte para o Lab
TODO 1 — calcular_equidade(dataset): agrupar por grupo, calcular taxa de aprovação por grupo, paridade demográfica (diferença absoluta), TPR (aprovados entre score≥80 por grupo).
TODO 2 — sugerir_mitigacao(metricas, equidade): montar prompt com taxas e paridade, pedir 3 estratégias concretas.
Agora você está pronto para o lab.