mozak.tech Engenharia de IA Corporativa 70%

Parte III — Governança, Conformidade e Responsabilidade na IA

3.3 — Vieses Algorítmicos: Métricas de Equidade e Estratégias de Mitigação (Bias & Fairness)

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ério

Igualdade 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].text

Aprofundamento 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 grupo

Exemplos 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ções

Padrã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-representados

Armadilhas

⚠️ 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écnica
⚗ Laboratório prático — mozak.tech
Se 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.