7.18.2 EP07_02 🟡 Normalização Z-score e Robustez do k-NN a Escalas Distintas
Este exercício revisita o classificador implementado no EP07_01, desta vez sob a ótica discutida na seção O Impacto da Escala e a Normalização de Características do capítulo: o k-NN decide com base na distância entre vetores, de modo que uma característica medida em uma escala muito maior do que as demais tende a dominar o cálculo da distância, mesmo quando ela não é a mais relevante para separar as classes.
Um sistema de inspeção registra, para cada peça, sua área (em pixels, podendo chegar a centenas ou milhares) e sua circularidade (sempre entre \(0\) e \(1\)). Você foi encarregado de classificar novas peças por k-NN de duas formas — com e sem a padronização Z-score apresentada no capítulo — e de reportar em quais casos as duas abordagens divergem.
7.18.2.1 📋 Diretrizes de Implementação
- Quantidade e parâmetro: Ler o inteiro \(N\) (número de exemplos de treinamento) e o inteiro ímpar \(k\).
- Exemplos de treinamento: Para cada um dos \(N\) exemplos, ler três valores: a área \(x_1\) (real), a circularidade \(x_2\) (real) e o rótulo \(r\) (inteiro, \(0\) ou \(1\)).
- Consultas: Ler o inteiro \(Q\) e, em seguida, as coordenadas \(x_1, x_2\) de cada consulta.
- Classificação sem normalização: Para cada consulta, classifique-a por k-NN diretamente sobre \((x_1, x_2)\), com distância euclidiana e as mesmas regras de desempate do EP07_01 (ordem de leitura para distâncias empatadas; vizinho mais próximo entre classes empatadas na votação).
- Parâmetros de normalização: Calcule a média \(\mu_j\) e o desvio-padrão populacional \(\sigma_j\) (divisão por \(N\), não por \(N-1\) — a mesma convenção adotada pela classe
StandardScaler) de cada característica \(j \in \{1,2\}\), exclusivamente sobre o conjunto de treinamento. - Padronização: Transforme cada característica de treinamento e de consulta por \[ z_j = \frac{x_j - \mu_j}{\sigma_j}. \] Se \(\sigma_j = 0\) (característica constante no treinamento), defina \(z_j = 0\) para todas as amostras dessa característica, evitando a divisão por zero.
- Classificação com normalização: Repita a classificação k-NN do item 4, agora sobre os vetores padronizados \((z_1, z_2)\), com as mesmas regras de desempate.
- Saída: Para cada consulta, na ordem de entrada, imprimir as duas classes previstas. Ao final, imprimir o número de consultas em que as duas classificações divergem.
7.18.2.2 📌 Restrições Computacionais
- Ajuste apenas no treino: \(\mu_j\) e \(\sigma_j\) são calculados unicamente a partir do conjunto de treinamento e reaplicados às consultas — nunca recalculados a partir delas. Essa prática evita o vazamento de dados (data leakage), mencionado na seção de normalização do capítulo.
- Desvio-padrão populacional: utilize \(\sigma_j = \sqrt{\frac{1}{N}\sum_i (x_{i,j}-\mu_j)^2}\), e não a versão amostral (divisão por \(N-1\)).
- Característica constante: trate \(\sigma_j = 0\) como caso especial (item 6); não deve ocorrer erro de divisão por zero.
- Regras de desempate: reutilize exatamente as convenções do EP07_01, tanto na seleção dos \(k\) vizinhos quanto na votação majoritária.
7.18.2.3 🧠 Fundamentação Teórica
| Elemento | Papel |
|---|---|
| Padronização Z-score | Reescala cada característica para média \(0\) e desvio-padrão \(1\), tornando escalas heterogêneas comparáveis |
| Ajuste (fit) apenas no treino | Garante que a avaliação sobre as consultas reflita apenas o que o modelo aprendeu no treinamento |
| Distância euclidiana sem normalização | Dominada pela característica de maior amplitude — aqui, a área |
| Predição divergente | Evidencia que a escala das características, e não apenas o algoritmo ou os dados, pode determinar a fronteira de decisão do k-NN |
Este exercício reforça, de forma controlada, a razão pela qual o StandardScaler é aplicado antes do k-NN ao longo do capítulo: sem essa etapa, características de circularidade — mesmo sendo altamente discriminativas — podem ser praticamente ignoradas pelo classificador diante de uma característica de área com amplitude centenas de vezes maior.
7.18.2.4 📦 Especificação de Entrada e Saída (VPL)
Entrada:
- Linha 1: Inteiros \(N\) e \(k\), separados por espaço.
- Próximas \(N\) linhas: três valores por linha — \(x_1\), \(x_2\) (reais) e \(r\) (inteiro \(\in \{0,1\}\)), separados por espaço.
- Próxima linha: inteiro \(Q\).
- Próximas \(Q\) linhas: dois valores por linha — \(x_1\), \(x_2\) (reais) da consulta, separados por espaço.
Saída:
- \(Q\) linhas, no formato
SemNorm=<0|1> ComNorm=<0|1>, na ordem de entrada das consultas. - Última linha:
Divergiu: <int>.
7.18.2.5 📌 Exemplos
| Entrada | Saída | Observação |
|---|---|---|
| 4 3 10 0.9 0 12 0.85 0 900 0.2 1 950 0.25 1 1 500 0.88 |
SemNorm=1 ComNorm=0 Divergiu: 1 |
Sem normalização, a área (escala de centenas) domina a distância e a consulta é classificada como classe 1. Após a padronização, a circularidade — muito mais próxima das amostras de classe 0 — passa a pesar de forma comparável, e a predição muda para 0. |
| 2 1 0 0.5 0 100 0.5 1 1 60 0.5 |
SemNorm=1 ComNorm=1 Divergiu: 0 |
A circularidade é constante no treinamento (\(\sigma_2=0\)); pela regra do item 6, \(z_2=0\) para todas as amostras, e a classificação depende apenas da área em ambos os casos. |
%%writefile EP07_02.py
# Código PythonWriting EP07_02.py
TestSuite("EP07_02.py").run()✔️ EP07_02.cases já existe em casos/
📋 5 caso(s) carregado(s) de casos/EP07_02.cases
🔍 Testando Python: EP07_02.py
⚠️ EP07_02.py: Arquivo sem conteúdo (menos de 3 linhas). Testes ignorados.