Caderno operacional — calcular, simular e interpretar

Introdução: transformar entendimento em evidência

Neste laboratório, “entendi” significa conseguir prever, calcular, executar, provocar uma falha e explicar o diagnóstico. Você trabalhará com números pequenos para enxergar cada etapa. O objetivo não é construir um modelo de produção; é impedir que uma biblioteca esconda um erro conceitual.

O fio condutor continua sendo manutenção integrada ao sistema de gestão empresarial (ERP, Enterprise Resource Planning). Tempos de atendimento mostram o efeito de um extremo; sensores formam vetores; um detector de ordem crítica mostra a taxa-base; uma parábola simples torna visível o efeito da taxa de aprendizado. OS significa ordem de serviço.

Vocabulário operacional

  • caminho feliz é a execução com entradas válidas e resultado esperado;
  • caso negativo usa uma entrada inválida ou condição de falha para verificar a proteção;
  • saída determinística é aquela que se repete com as mesmas entradas e ambiente;
  • evidência de execução é o comando, a saída e a interpretação que outra pessoa consegue conferir;
  • falha provocada é um erro intencional e controlado; não é deixar código quebrado em produção;
  • diagnóstico liga sintoma, hipótese, verificação e correção;
  • asserção é uma verificação escrita com assert: se a condição for falsa, o programa para e revela a divergência.

Contrato do laboratório

Objetivo: confirmar à mão e em Python estatística, vetores, métricas de classificação e otimização.

Hipótese: se a fórmula e a implementação representam a mesma pergunta, os resultados coincidem; se uma premissa é violada, o programa falha com mensagem específica em vez de produzir número enganoso.

Pré-requisitos: ter lido o capítulo anterior; saber salvar um arquivo de texto; ter Python 3.11 ou superior disponível. O código usa apenas a biblioteca padrão e não precisa de internet, conta, pacote ou segredo.

Duração estimada: 120 minutos — 25 para cálculos manuais, 35 para execução, 25 para falhas, 20 para interpretação e 15 para revisão.

Arquivo de trabalho: crie uma pasta descartável e salve o bloco completo da solução como caderno_matematica.py.

Comando:

python caderno_matematica.py

Em alguns ambientes Windows, o comando pode ser py caderno_matematica.py. Use o interpretador aprovado pelo seu projeto; não instale pacotes para este exercício.

Etapa 0 — faça previsões antes de executar

Copie e complete a tabela. Não procure precisão decimal ainda; preveja direção e ordem de grandeza.

Experimento Sua previsão Por quê?
média de [1, 2, 2, 3, 42] maior, igual ou menor que a mediana?
escore do equipamento entre 0 e 1?
detector com evento raro precisão maior ou menor que recall?
taxa de aprendizado 0,1 perda cai ou cresce?
taxa 1,0 converge, oscila ou diverge?
taxa 1,1 converge, oscila ou diverge?

Essa previsão impede que você aceite qualquer número apenas porque apareceu no terminal.

Etapa 1 — estatística manual: qual é o “tempo típico”?

Use os tempos de atendimento em horas:

[1, 2, 2, 3, 42]
  1. Some os valores e divida por cinco: a média é 10 h.
  2. Ordene e escolha o valor central: a mediana é 2 h.
  3. Calcule os desvios em relação a 10, eleve ao quadrado e some: 1.282 h².
  4. Se os cinco registros forem a população, divida por 5: 256,4 h².
  5. Se forem amostra de uma população maior, a função variance do Python divide por n-1: 320,5 h².

O ponto de 42 horas puxa a média, mas não a mediana. Isso não autoriza apagar o valor. Primeiro investigue se ele é erro de medição, indisponibilidade real de peça, parada de ERP ou atendimento legítimo extremo.

Percentil exige método declarado

Este laboratório usa posto mais próximo: para o percentil p, ordene n valores e escolha a posição ceil(p×n), começando a contar em 1. Para cinco valores, o percentil 90 ocupa ceil(0,90×5)=5, portanto vale 42. Outros softwares podem interpolar e retornar outro número; divergência de método não é automaticamente bug.

Etapa 2 — vetor e matriz: unidades antes de pesos

O equipamento já foi transformado para atributos normalizados:

x = [0,80; 0,50; 0,40]

Use duas linhas de pesos:

risco = [0,60; 0,30; 0,10]
custo = [0,10; 0,20; 0,70]

Calcule:

risco · x = 0,67
custo · x = 0,46

Esses são escores sem unidade. O rótulo “custo” não os transforma em reais, e “risco” não os transforma em probabilidade. Para usar temperatura bruta, vibração e horas seria necessário documentar a transformação e calcular seus parâmetros apenas no conjunto de treino.

Etapa 3 — taxa-base e matriz de confusão

Calcule uma simulação determinística de 10.000 ordens:

  • prevalência crítica: 1%;
  • recall do detector: 90%;
  • taxa de falso positivo entre normais: 5%.

As contagens esperadas são:

verdadeiros positivos = 90
falsos negativos      = 10
falsos positivos      = 495
verdadeiros negativos = 9.405

Aqui “simulação” significa converter proporções esperadas em contagens inteiras com arredondamento; não estamos sorteando uma amostra aleatória. Em um experimento estocástico, seria necessário registrar a semente e analisar a variação entre execuções.

Antes de continuar, confira os dois totais: 90+10=100 ordens críticas e 495+9.405=9.900 normais. Depois calcule:

precisão = 90 / 585 ≈ 15,38%
recall   = 90 / 100 = 90%
acurácia = 9.495 / 10.000 = 94,95%

A documentação do scikit-learn apresenta definições e convenções de métricas (Metrics and scoring). Aqui fazemos as contas diretamente para enxergar os denominadores.

Etapa 4 — descida do gradiente como trajetória

A perda é L(θ)=(θ-3)²; sua derivada é 2(θ-3). Em cada passo:

θ_novo = θ_atual - taxa × 2(θ_atual-3)

Parta de θ=0 e registre parâmetro e perda. Use quatro taxas para separar comportamentos:

  • 0,1: convergência gradual;
  • 0,5: chega ao mínimo em um passo neste exemplo;
  • 1,0: alterna entre 0 e 6, sempre com perda 9;
  • 1,1: alterna e aumenta a distância, portanto diverge.

O desenho textual será uma tabela, não um gráfico decorativo. O que importa é observar se a perda cai, fica constante ou cresce. O exemplo é convexo, unidimensional e sem ruído; redes neurais não herdam automaticamente estes limites.

Solução executável comentada

O bloco abaixo é um programa completo para Python 3.11+. Ele não usa aleatoriedade; portanto não precisa de seed (semente). Todas as asserções são determinísticas. No dicionário da matriz, vp, fn, fp e vn abreviam verdadeiro positivo, falso negativo, falso positivo e verdadeiro negativo. lambda cria uma pequena função sem nome usada apenas para disparar cada caso inválido; a compreensão entre chaves constrói um dicionário percorrendo os pesos.

from math import ceil
from statistics import mean, median, pvariance, variance


def percentil_posto_mais_proximo(valores, proporcao):
    """Retorna percentil por nearest rank; proporcao deve estar em (0, 1]."""
    if not valores:
        raise ValueError("percentil exige ao menos um valor")
    if not 0 < proporcao <= 1:
        raise ValueError("proporção deve estar no intervalo (0, 1]")
    ordenados = sorted(valores)
    indice = ceil(proporcao * len(ordenados)) - 1
    return ordenados[indice]


def produto_escalar(a, b):
    if len(a) != len(b):
        raise ValueError("vetores precisam ter a mesma dimensão")
    return sum(x * y for x, y in zip(a, b))


def matriz_confusao(total, prevalencia, recall, taxa_falso_positivo):
    for nome, valor in {
        "prevalência": prevalencia,
        "recall": recall,
        "taxa de falso positivo": taxa_falso_positivo,
    }.items():
        if not 0 <= valor <= 1:
            raise ValueError(f"{nome} deve estar entre 0 e 1")

    positivos = round(total * prevalencia)
    negativos = total - positivos
    vp = round(positivos * recall)
    fn = positivos - vp
    fp = round(negativos * taxa_falso_positivo)
    vn = negativos - fp
    return {"vp": vp, "fn": fn, "fp": fp, "vn": vn}


def metricas(matriz):
    vp, fn, fp, vn = (matriz[chave] for chave in ("vp", "fn", "fp", "vn"))
    if vp + fp == 0:
        raise ValueError("precisão indefinida: nenhum alerta positivo")
    if vp + fn == 0:
        raise ValueError("recall indefinido: nenhum caso positivo")
    total = vp + fn + fp + vn
    return {
        "precisao": vp / (vp + fp),
        "recall": vp / (vp + fn),
        "acuracia": (vp + vn) / total,
    }


def perda(theta):
    return (theta - 3) ** 2


def trajetoria(taxa, passos=5, theta_inicial=0.0):
    if taxa <= 0:
        raise ValueError("taxa de aprendizado deve ser positiva")
    theta = theta_inicial
    historico = []
    for passo in range(passos + 1):
        historico.append((passo, theta, perda(theta)))
        gradiente = 2 * (theta - 3)
        theta = theta - taxa * gradiente
    return historico


# 1. Estatística descritiva
tempos_horas = [1, 2, 2, 3, 42]
print("ESTATÍSTICA")
print(f"média={mean(tempos_horas):.1f} h")
print(f"mediana={median(tempos_horas):.1f} h")
print(f"variância populacional={pvariance(tempos_horas):.1f} h²")
print(f"variância amostral={variance(tempos_horas):.1f} h²")
print(f"p90 nearest-rank={percentil_posto_mais_proximo(tempos_horas, 0.90)} h")
assert mean(tempos_horas) == 10
assert median(tempos_horas) == 2
assert pvariance(tempos_horas) == 256.4
assert variance(tempos_horas) == 320.5

# 2. Dois escores produzidos por uma matriz 2x3
equipamento = [0.80, 0.50, 0.40]
pesos = {
    "risco": [0.60, 0.30, 0.10],
    "custo": [0.10, 0.20, 0.70],
}
escores = {nome: produto_escalar(linha, equipamento) for nome, linha in pesos.items()}
print("\nESCORES")
print({nome: round(valor, 2) for nome, valor in escores.items()})
assert round(escores["risco"], 2) == 0.67
assert round(escores["custo"], 2) == 0.46

# 3. Evento raro e métricas
matriz = matriz_confusao(10_000, 0.01, 0.90, 0.05)
resultado = metricas(matriz)
print("\nCLASSIFICAÇÃO")
print(matriz)
print({nome: f"{valor:.2%}" for nome, valor in resultado.items()})
assert matriz == {"vp": 90, "fn": 10, "fp": 495, "vn": 9405}
assert round(resultado["precisao"], 4) == 0.1538
assert resultado["recall"] == 0.90
assert round(resultado["acuracia"], 4) == 0.9495

# 4. Otimização: tabela compacta por taxa
print("\nOTIMIZAÇÃO (perda inicial -> perda após 5 passos)")
for taxa in (0.1, 0.5, 1.0, 1.1):
    historico = trajetoria(taxa)
    inicio = historico[0]
    fim = historico[-1]
    print(
        f"taxa={taxa:.1f}: θ {inicio[1]:.3f}->{fim[1]:.3f}; "
        f"perda {inicio[2]:.3f}->{fim[2]:.3f}"
    )

assert trajetoria(0.1)[-1][2] < trajetoria(0.1)[0][2]
assert trajetoria(0.5)[1][2] == 0
assert trajetoria(1.0)[-1][2] == 9
assert trajetoria(1.1)[-1][2] > trajetoria(1.1)[0][2]

# 5. Casos negativos: as falhas são capturadas e verificadas
falhas_esperadas = []
for acao in (
    lambda: produto_escalar([1, 2], [1]),
    lambda: percentil_posto_mais_proximo([], 0.90),
    lambda: matriz_confusao(100, 1.20, 0.90, 0.05),
    lambda: trajetoria(0),
):
    try:
        acao()
    except ValueError as erro:
        falhas_esperadas.append(str(erro))

print("\nFALHAS ESPERADAS")
for mensagem in falhas_esperadas:
    print(f"- {mensagem}")
assert len(falhas_esperadas) == 4

print("\nTODAS AS VERIFICAÇÕES PASSARAM")

Resultado esperado e como lê-lo

Os valores centrais devem incluir:

média=10.0 h
mediana=2.0 h
variância populacional=256.4 h²
variância amostral=320.5 h²
p90 nearest-rank=42 h
{'risco': 0.67, 'custo': 0.46}
{'vp': 90, 'fn': 10, 'fp': 495, 'vn': 9405}
{'precisao': '15.38%', 'recall': '90.00%', 'acuracia': '94.95%'}
TODAS AS VERIFICAÇÕES PASSARAM

A trajetória exata de 0,1 termina após cinco atualizações em θ≈2,017, com perda menor que a inicial. A taxa 0,5 chega a zero; 1,0 mantém perda 9; 1,1 aumenta a perda. Pequenas diferenças apenas na última casa impressa podem vir da representação de ponto flutuante, mas as asserções documentam a tolerância usada.

Etapa 5 — provoque, observe e diagnostique

O programa já captura quatro falhas. Agora execute uma mutação de cada vez e depois desfaça:

  1. Remova a verificação de dimensão em produto_escalar e chame [1, 2] com [1]. A função zip, que forma pares de posições, trunca silenciosamente e retorna 1. Diagnóstico: o número parece válido, mas um atributo desapareceu.
  2. Troque vp / (vp + fp) por vp / (vp + fn) na precisão. O resultado vira 90%, igual ao recall. Diagnóstico: o denominador passou a responder outra pergunta.
  3. Troque a taxa 0,1 por 1,1. Diagnóstico: parâmetro alterna e a perda cresce; não é “mais rápido”.
  4. Remova o ponto de 42 horas. Diagnóstico: média e variância despencam; antes de excluir, investigue se era erro ou evento real.

Uma falha provocada passa quando você registra:

mutação -> sintoma observado -> hipótese -> cálculo de conferência -> correção

Não preserve as mutações no arquivo final. Rode o programa novamente e exija a mensagem TODAS AS VERIFICAÇÕES PASSARAM.

Etapa 6 — aplicação no sistema de manutenção/ERP

Produza uma nota de decisão de no máximo uma página com estas respostas:

  1. Qual é a ordem, unidade e faixa de cada atributo do vetor?
  2. Os parâmetros de normalização vieram somente do treino?
  3. O escore 0,67 é regra, ranking ou probabilidade calibrada?
  4. Qual custo operacional tem um falso negativo? E um falso positivo?
  5. Como o sistema reage quando sensor, identidade ou ERP está indisponível?
  6. Que pessoa ou política determinística autoriza a ação final?
  7. Quais métricas serão acompanhadas por unidade e tipo de equipamento?

Uma resposta aceitável não diz apenas “a IA decide prioridade”. Ela separa recomendação de execução. Por exemplo: o modelo sugere prioridade e razões; o backend valida identidade, estado e unidade; o supervisor confirma ações de alto impacto; a integração registra tentativa e falha do ERP sem inventar sucesso.

Segurança, privacidade e custo

  • use dados sintéticos neste laboratório; nenhum dado pessoal ou segredo é necessário;
  • em produção, limite retenção e acesso a medições e identificadores;
  • não publique métricas de grupos tão pequenos que revelem indivíduos ou equipes;
  • registre versão de dados, transformação, modelo e política;
  • meça custo de inspeções adicionais, atraso e falhas perdidas, não apenas custo computacional;
  • não use o conjunto de teste para ajustar o limiar depois de ver o resultado.

Troubleshooting

Sintoma Verificação rápida Correção provável
python não encontrado python --version ou py --version usar o interpretador aprovado; não baixar executável desconhecido
AssertionError na estatística imprimir lista e denominador restaurar dados e distinguir pvariance de variance
precisão aparece como 90% conferir denominador usar VP/(VP+FP), não VP/(VP+FN)
escore incorreto imprimir pares de zip conferir ordem e dimensão
percentil diverge de planilha identificar método da ferramenta registrar método; não forçar igualdade entre convenções
perda vira número enorme imprimir taxa, gradiente e θ por passo reduzir taxa e conferir sinal da atualização
resultado muda sem aleatoriedade comparar arquivo e versão do Python remover estado oculto e registrar ambiente

Evidências e critérios de aceite

Entregue:

  • caderno_matematica.py sem as mutações;
  • saída completa do comando;
  • tabela de previsões preenchida antes da execução;
  • quatro cálculos manuais fotografados ou transcritos;
  • um registro de falha no formato mutação → sintoma → hipótese → conferência → correção;
  • nota de decisão do sistema de manutenção/ERP.

O laboratório está aprovado quando:

  • o programa termina com código de saída zero e todas as asserções passam;
  • média, mediana, variâncias, escores e matriz coincidem com o cálculo manual;
  • denominadores, unidades e método de percentil estão declarados;
  • taxa 0,1 reduz, 1,0 oscila e 1,1 aumenta a perda neste exemplo;
  • entradas inválidas geram quatro falhas esperadas, não números silenciosos;
  • a interpretação distingue escore, probabilidade, recomendação e autorização;
  • a nota explica ao menos uma limitação de dados e uma consequência de erro.

Recuperação ativa, repetição e transferência

Sem consultar, explique amanhã:

  1. por que média 10 e mediana 2 podem estar simultaneamente corretas;
  2. por que 90% de recall pode coexistir com 15,38% de precisão;
  3. por que taxa maior não significa treino melhor;
  4. por que produto escalar correto pode continuar semanticamente errado;
  5. por que reduzir perda de treino não prova benefício operacional.

Repita após 24 horas e sete dias. Na segunda repetição, troque “OS crítica” por fraude rara; na terceira, por defeito de fabricação. A aritmética da matriz permanece, mas prevalência, custo, limiar, revisão humana e impacto mudam.

Intercale com representação de dados: mostre como arredondamento, campo ausente ou unidade incorreta altera pelo menos um resultado deste caderno.

Limpeza

Apague somente a pasta descartável criada para o laboratório, depois de copiar as evidências para o local definido pelo curso. Não execute exclusão recursiva em diretório amplo. Nenhuma credencial, pacote global ou serviço precisa ser removido porque o exercício não os cria.

Conclusão

Você percorreu o ciclo completo: previu, calculou, implementou, executou, provocou falhas, diagnosticou e transferiu a conclusão para um sistema real. O valor do caderno não é a mensagem verde final; é conseguir explicar por que cada asserção existe, que pergunta cada denominador responde e onde a matemática termina e começa a política de negócio.

Fontes

Teste de fixação

Comprove o que você aprendeu

Responda todas as questões. O gabarito comentado só aparece depois do envio.

1. No conjunto `[1, 2, 2, 3, 42]`, qual interpretação é sustentada pelo exercício?
2. Antes de variar a taxa de falso positivo em um evento de 1%, por que o laboratório pede previsão da precisão?
3. Para `L(θ)=(θ-3)²`, o que a trajetória com taxa de aprendizado exatamente 1 tende a mostrar?

Consulta universal

O que você quer encontrar?

Títulos, capítulos, conceitos, termos, laboratórios e ferramentas em uma única busca.

Digite pelo menos dois caracteres.