ML Atlas

Machine learning do zero · Aula 4.4 · 23 de 33 aulas prontas · 12 min

Engenharia de atributos

Em resumo

A variedade 2 fica no meio do eixo e nenhum limiar a recorta. Uma coluna x² dá 77,4% em vez de 60,4%; 200 colunas de ruído derrubam o kNN de 98,1% para 77,4%.

Aquecimento Duas perguntas de aulas anteriores. Um minuto, e a aula nunca fica bloqueada.
Da aula 4.3: Categorias e escalonamento Por que o kNN sem escalonamento acerta só 0,695 nos vinhos?

Ver a resposta

Resposta certa: Porque a prolina tem dispersão enorme e manda na distância inteira

A prolina tem desvio-padrão de 314; a medida menos variável, de 0,124. Sem escalonamento a distância é quase só a diferença de prolina. Após padronizar a acurácia sobe para 0,963.

Da aula 4.2: Dados faltantes O IMC falta nos 110 pacientes mais pesados. O que faz preencher com a média dos outros?

Ver a resposta

Resposta certa: Enfraquece a relação IMC–doença, porque os mais doentes caem num IMC médio

A correlação cai de 0,586 para 0,352. 110 pacientes com muita progressão ficam num só ponto: na média de 24,3.

Na lição 4.3 mudamos o jeito de escrever os atributos: a escala dos números e o código das categorias. Hoje criamos atributos novos a partir dos que já temos. A engenharia de atributos consiste em acrescentar colunas que mostram ao modelo com mais clareza o que ele procura: um quadrado, uma razão, uma diferença, o número de dias desde um evento. Um bom atributo pode transformar um problema difícil num fácil. Muitos atributos fracos podem estragar um modelo que funcionava.

Preveja, depois confira Vinhos de três variedades. Um modelo linear deve distinguir a variedade 2 das outras só pelo teor de flavonoides. Num eixo, um modelo linear põe um limiar: “variedade 2” de um lado, “outra” do outro. A variedade 2 tem em média 2,08, a variedade 1 tem 2,98 e a variedade 3 tem 0,78. Um limiar separa a variedade 2?
Qual é o seu grau de certeza?

Experimento interativo

Este experimento interativo funciona em um navegador com JavaScript ativado. O texto ao redor descreve o que ele mostra.

Ver a resposta

Resposta certa: Não, porque a variedade 2 fica no meio e tem vinhos de outras variedades dos dois lados

Não. No meio do eixo, um limiar sempre deixa uma das outras duas variedades do lado “variedade 2”. O melhor limiar nos vinhos de treino acerta 61,6%, pouco mais que os 60,0% de dizer “outra variedade” para cada vinho, e nos vinhos de teste exatamente o mesmo: 60,4%. A SVM linear do lab não prevê a variedade 2 em lugar nenhum. Só uma coluna nova x² permite recortar o intervalo do meio.

Experimente

  • Comece só com x. Onde o modelo prevê a variedade 2? Qual é a acurácia de teste, e de onde ela vem?
  • Acrescente a coluna x². Como fica a fronteira no plano (x, x²), e no eixo dos flavonoides sozinho?
  • Passe para o ruído. Desça o controle a partir de 200 colunas. Quando o kNN reconhece melhor os vinhos separados?
  • Observe o contraste das distâncias. O que acontece com a diferença entre o vinho mais próximo e o mais distante quando as colunas se acumulam?

Depois de conferir no lab, vamos dar nome ao que você vê.

A ideia em palavras simples

Um modelo linear num eixo só sabe fazer uma coisa: pôr um limiar. A variedade 2 fica no meio do eixo dos flavonoides, então um limiar não consegue recortá-la de nenhum lado: separa no máximo uma das variedades vizinhas. O melhor limiar desse tipo separa a variedade 3 e acerta 61,6% no treino, enquanto dizer “outra variedade” para cada vinho acerta 60,0%. O ganho é mínimo, e no teste some. A SVM linear do lab não prevê a variedade 2 em lugar nenhum e fica com 60,4%, a proporção das outras variedades entre os 53 vinhos de teste. Vamos acrescentar a coluna x², o quadrado dos flavonoides padronizados. Os vinhos das duas pontas do eixo têm x² grande; os do meio, pequeno. O mesmo modelo linear agora traça uma reta no plano (x, x²). No eixo dos flavonoides isso são dois limiares, um intervalo de 1,11 a 2,82. A acurácia sobe para 77,4%. O modelo não mudou; mudou o que ele recebe.

Mais atributos não quer dizer melhor, porém. O kNN (k = 5) com 13 medidas químicas reconhece 98,1% dos vinhos separados. Acrescentamos colunas de ruído puro, números aleatórios na mesma escala. Com 200 colunas assim, a acurácia cai para 77,4%. Cada coluna de ruído pesa na distância tanto quanto uma medida real, então os vinhos “mais próximos” deixam de ser parecidos. É a maldição da dimensionalidade: em muitas dimensões, todos os pontos ficam quase à mesma distância uns dos outros.

Jak to policzono
  • Vinhos: Wine (Aeberhard e Forina, 1992; UCI, licença CC BY 4.0), 178 vinhos, 13 medidas químicas, 3 variedades. Divisão estratificada: 125 vinhos para aprender, 53 para o teste.
  • Atributo novo: um modelo linear (uma máquina de vetores de suporte linear, C = 1) sobre os flavonoides padronizados, variedade 2 contra o resto. Flavonoides médios calculados nos 178 vinhos.
  • Ruído: kNN com k = 5 sobre as 13 medidas padronizadas e de 0 a 200 colunas de números de uma distribuição normal (média 0, desvio-padrão 1), sorteados com uma semente fixa.

Por que funciona

Um modelo linear divide o espaço com uma reta (com um plano em mais dimensões). Num eixo, uma reta é um ponto: um limiar. A coluna x² acrescenta um segundo eixo. Os vinhos das duas pontas do eixo dos flavonoides ficam no alto da parábola; os do meio, embaixo. Agora uma reta consegue cortar a variedade 2 por cima. Em outras 20 divisões dos vinhos, sem x² a SVM linear não prevê nem uma vez a variedade 2, e o melhor limiar único do treino só supera “sempre outra” no teste em 1 de 20. Com x² sempre recorta um intervalo: de 67,9 a 84,9% no teste.

Com o ruído é o contrário. A distância no kNN é uma soma de diferenças ao quadrado de todas as colunas. Com 13 medidas, o vinho de treino mais distante está em média 296,5% mais longe que o mais próximo. Com 200 colunas de ruído, só 25,7%. As diferenças no ruído são aleatórias e numerosas, então afogam as 13 diferenças reais. Em 20 sorteios do ruído, 200 colunas dão de 64,2 a 83,0%, sempre abaixo dos 98,1% sem ruído.

Um erro comum

Verdadeiro ou falso: “mais atributos fazem um modelo melhor”. Falso. Um atributo ajuda quando carrega informação num formato que o modelo sabe usar, como x² para a variedade 2. Colunas sem informação atrapalham: 200 colunas de ruído derrubam o kNN de 98,1% para 77,4%. No código abaixo, a acurácia do kNN cai de 0,962 sem ruído para 0,689 com 200 colunas.

Um bom atributo novo costuma nascer de entender o problema: o que deveria importar, e em que formato. Jogar dentro tudo o que der é um convite ao ruído.

Quiz

Três perguntas para você se testar. Escolha uma resposta ou abra a resposta embaixo de cada pergunta. No teclado: as setas escolhem, Enter ou Espaço confirma.

1. Por que um único limiar só nos flavonoides não consegue separar a variedade 2?
Ver a resposta

Resposta certa: Porque a variedade 2 fica no meio e um limiar não recorta um intervalo central

Em média 2,08 contra 2,98 e 0,78 das outras. Cada limiar deixa também outra variedade do lado “variedade 2”. O melhor limiar acerta 61,6% no treino contra 60,0% de “sempre outra”, e a SVM linear não prevê a variedade 2 em lugar nenhum: 60,4%.

2. Você acrescenta 200 colunas de ruído aleatório às 13 medidas dos vinhos. O que acontece com o kNN?
Ver a resposta

Resposta certa: A acurácia cai, porque o ruído afoga na distância as diferenças reais

A acurácia cai de 98,1% para 77,4%. Cada coluna de ruído pesa na distância tanto quanto uma medida real.

3. Verdadeiro ou falso: “mais atributos fazem um modelo melhor”.
Ver a resposta

Resposta certa: Falso, porque atributos sem informação trazem ruído e podem baixar a acurácia

200 colunas de ruído derrubam o kNN de 98,1% para 77,4%. O que ajuda é um atributo com informação num bom formato, como x² para a variedade 2.

Pontos-chave

  • Um atributo num bom formato transforma um problema difícil num fácil: x² sobe a acurácia de 60,4% para 77,4%.
  • Um modelo linear com colunas novas continua linear; o que muda é o que ele recebe como entrada.
  • Colunas sem informação atrapalham: 200 colunas de ruído derrubam o kNN de 98,1% para 77,4%.
  • Em muitas dimensões as distâncias se igualam, então os modelos baseados em distância são os que mais perdem.

Mais a fundo: fórmula, código, prática

A matemática

O atributo novo: z = (x − x̄) / s, e o modelo linear recebe (z, z²). A fronteira w₁ · z + w₂ · z² + b = 0 é uma equação do segundo grau em z, então tem até duas raízes: dois limiares no eixo x e um intervalo entre eles.

A distância no kNN: d(a, b)² = Σⱼ (aⱼ − bⱼ)² sobre todas as colunas. Para m colunas de ruído de N(0, 1), cada uma acrescenta em média 2 a d² (a variância da diferença de dois números independentes), qualquer que seja a variedade. Com m grande, a soma do ruído afoga os 13 termos reais, e o contraste (d_max − d_min) / d_min diminui.

No código (Python)

O mesmo experimento no scikit-learn: um modelo linear sobre os flavonoides sem x² e com x² na validação cruzada 10 × 5, depois o kNN com as 13 medidas e um número crescente de colunas de ruído.

import numpy as np
from sklearn.datasets import load_wine
from sklearn.model_selection import cross_val_score, RepeatedStratifiedKFold
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier

wine = load_wine(as_frame=True)
x, is2 = wine.data[["flavanoids"]], (wine.target == 1).astype(int)
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=10, random_state=0)
line = make_pipeline(StandardScaler(), SVC(kernel="linear", C=1))
squared = make_pipeline(StandardScaler(), PolynomialFeatures(2, include_bias=False), StandardScaler(), SVC(kernel="linear", C=1))  # a coluna nova x²
a, b = cross_val_score(line, x, is2, cv=cv), cross_val_score(squared, x, is2, cv=cv)
print(f"cultivar 2 vs the rest from flavanoids, 10 x 5 CV: x only {a.mean():.3f}, x and x^2 {b.mean():.3f}; always 'other' {1 - is2.mean():.3f}")
print(f"x only predicts cultivar 2 for {line.fit(x, is2).predict(x).sum()} of {len(x)} wines; x and x^2 wins in {(b > a).sum()} of 50 folds")
X, y = wine.data.to_numpy(), wine.target.to_numpy()
noise = np.random.default_rng(0).normal(size=(len(X), 200))  # colunas de ruído puro
for m in [0, 10, 50, 200]:
    acc = cross_val_score(make_pipeline(StandardScaler(), KNeighborsClassifier(5)), np.hstack([X, noise[:, :m]]), y, cv=cv)
    print(f"kNN on 13 measurements + {m} noise columns: {acc.mean():.3f}")

Saída

cultivar 2 vs the rest from flavanoids, 10 x 5 CV: x only 0.601, x and x^2 0.755; always 'other' 0.601
x only predicts cultivar 2 for 0 of 178 wines; x and x^2 wins in 49 of 50 folds
kNN on 13 measurements + 0 noise columns: 0.962
kNN on 13 measurements + 10 noise columns: 0.940
kNN on 13 measurements + 50 noise columns: 0.842
kNN on 13 measurements + 200 noise columns: 0.689

As divisões e o ruído são diferentes dos do lab, então os números também diferem um pouco. A imagem é a mesma: sem x² o modelo não prevê nem uma vez a variedade 2 (0,601, o mesmo que “sempre outra”), com x² chega a 0,755 e vence em 49 de 50 partes de validação. O ruído derruba o kNN de 0,962 para 0,689.

Para quem pratica
  • No scikit-learn: PolynomialFeatures(2) acrescenta quadrados e produtos de pares de atributos, SplineTransformer curvas suaves, FunctionTransformer(np.log1p) um logaritmo para atributos de cauda longa. Coloque-os em make_pipeline, para que a validação cruzada veja o caminho inteiro.
  • Os melhores atributos vêm do conhecimento do problema: uma razão (preço por metro quadrado), uma diferença (dias desde a última compra), uma parte da data (dia da semana). O modelo não vai inventá-los se não receber os ingredientes brutos num bom formato.
  • Quando há muitos atributos, escolha-os dentro de cada divisão (SelectKBest no pipeline) ou use um modelo com regularização (lição 3.4). Escolher atributos com todos os dados antes da validação é vazamento (lição 4.5).
  • Os métodos de kernel que você vai conhecer com as máquinas de vetores de suporte calculam o resultado como se tivessem acrescentado essas colunas, mas sem construí-las explicitamente.

Vá mais fundo no Atlas

Verbetes da enciclopédia sobre as ideias desta aula: