K vizinhos mais próximos

Introdução

Discutimos até agora regressão linear que é um método paramétrico.

Métodos Paramétricos:

  • Vantagens: fácil de ajustar, porque a estimação se resume a estimar um conjunto de coeficientes. Os coeficientes tem interpretação mais simples e podemos fazer testes estatísticos.

  • Desvantagem: fazem suposições sobre a forma de \(f(X)\). Se a forma funcional especificada está longe da verdadeira, a predição será ruim.

Métodos Não-Paramétricos:

  • Não assume explicitamente uma forma para \(f(X)\), o que permite maior flexibilidade e, portanto, melhores predições. No entanto, a interpretação geralmente é bem complicada.

\(k\) Vizinhos Mais Próximos (KNN)

Em inglês k-Nearest Neighbors (KNN) regression (usaremos essa sigla).

Esse é um método não-paramétrico bastante conhecido em algoritmos de classificação, mas também pode ser usado em algoritmos de regressão.

O "vizinho mais próximo" é definido de acordo com alguma medida de similaridade (por ex: distância Euclidiana, distância de Hamming).

"Diga-me com quem andas que te direi quem és!"

Um dos algoritmos mais simples vistos em machine learning e um dos top 10 em data mining (reconhecimento de padrão).

Algoritmo KNN

Classificação: classifica uma nova observação de acordo com a classificação da maioria de seus \(k\) vizinhos mais próximos.


Regressão: Estima o valor de uma nova observação de acordo com a média dos valores de seus \(k\) vizinhos mais próximos.

Algoritmo KNN

Considere os dados de treinamento \((x_i, y_i)\) para \(i=1, \ldots, n\) e \(x_i \in \mathbb R^p\), uma nova observação com preditores \(x_0\) e uma medida de distância \(d(x_0,.)\).

Escolhido um valor de \(k\), a regressão por KNN identifica \(k\) observações no dados de treinamento que estão mais próximos a \(x_0\) de acordo com \(d(x_0,.)\), ou seja, para todos os \(x_i\)'s de treinamento, calcula-se todas as distâncias (por exemplo, Euclidiana): \[\qquad \displaystyle d(x_0, x_i) = \sqrt{\sum_{j=1}^p (x_{0j} - x_{ij})^2}.\] Nota: A distância pode ser dominada por algum preditor que esteja numa escala bem maior que os demais. Portanto, é essencial padronizar os preditores!

Algoritmo KNN

Ordena as distâncias \(d(x_0, x_i)\) para \(i=1, \ldots, n\) e armazena \(k\) \(y_i\)'s correspondentes às menores distâncias.

Seja \(\mathcal N_k(x_0)\) essa vizinhança que contém os \(k\) vizinhos de \(x_0\).

A estimativa será dada pela média de todas as respostas no treinamento pertencentes a \(N_k(x_0)\): \[\widehat y_0 = \widehat f(x_0) = \frac{1}{k} \sum_{x_i \in \mathcal N_k(x_0)} y_i.\]

Nesse algoritmo não há muito de aprendizagem nos dados de treinamento.

Aqui \(k\) é o parâmetro de ajuste (tuning parameter ou hiperparâmetro).

Exemplo: KNN

Veja um exemplo de regressão KNN usando dois preditores em um conjunto com 64 observações (pontos laranja) com \(k=1\) (esquerda) e \(k=9\) (direita).

\(k=1\): interpolação dos dados de treinamento e toma a forma de uma escada.
\(k=9\): toma uma média de 9 observações, então o ajuste se torna mais suave.

Dilema do Viés-Variância

Valores pequenos de \(k\):

  • produzem ajustes mais flexíveis.
  • Muita flexibilidade pode resultar em overfitting e maior variância.
  • Maior variância: a predição em uma região depende de poucas ou apenas uma observação (\(k=1\)).

Valores grandes de \(k\):

  • ajustes mais suaves e menos flexíveis.
  • Não ser flexível o suficiente está relacionado a ser viesado.
  • Menor variância: a predição em uma região é a média de vários pontos, então se mudarmos uma observação, isso tem efeito menor.

Como encontrar o valor ótimo de \(k\)? Validação Cruzada.

KNN vs Métodos Paramétricos

Gráficos de \(\widehat f(X)\) por regressão KNN com um preditor com \(k=1\) (esquerda) e \(k=9\) (direita). A linha preta representa a verdadeira \(f(X)\).

Quando que um modelo paramétrico, no caso uma regressão linear, será melhor que um modelo não-paramétrico?

KNN vs Regressão Linear

Aqui a linha azul pontilhada (esquerda) representa o ajuste por mínimos quadrados e na direita temos o MSE no conjunto de teste da regressão linear (linha pontilhada) e o MSE de teste para a regressão KNN como função de \(1/k\).

Regressão linear será sempre melhor que KNN nesse caso, já que \(f(X)\) é de fato linear.

KNN vs Métodos Paramétricos

Na prática, a relação entre \(X\) e \(Y\) dificilmente é linear. Então, o que acontece quando aumentamos o nível de não-linearidade de \(f(X)\)?

A regressão linear é melhor para valores pequenos de \(k\). Para \(k \leq 4\), KNN apresenta melhor performance.

KNN vs Métodos Paramétricos

Relação entre \(X\) e \(Y\) claramente não linear:

Nesse caso, KNN tem melhor desempenho para qualquer valor de \(k\).

Veja que o MSE de teste no KNN muda pouco com a mudança da relação de linear para não-linear. Enquanto que o MSE de teste aumenta significativamente com regressão linear.

KNN vs Métodos Paramétricos

Na prática, quando não conhecemos a verdadeira relação entre \(X\) e \(Y\), escolhemos KNN ou regressão linear?

Veja o que acontece com o mesmo exemplo do slide anterior, mas agora adicionando preditores que não estão associados com a resposta (ruído).

Conclusões?

Curse of Dimensionality

  • Com poucos preditores, KNN apresenta melhor desempenho se comparado a regressão linear.

  • À medida que p aumenta, o MSE nos dados de teste:
    • varia pouco para regressão linear
    • aumenta significativamente para KNN (mais de 10x)

Curse of Dimensionality

Problema comum em KNN: desempenho diminui à medida que aumenta a dimensionalidade dos dados. Isso vem do fato que em altas dimenções, há uma redução no número de efetivo de observações.

Pense no que acontece com \(n=100\) quando:

  • \(p=1\): existe um número razoável de observações na vizinhança para estimar \(f(X)\)
  • \(p=20\): para uma dada observação, dificilmente teremos algum vizinho próximo (curse of dimensiolity).

De maneira geral, métodos paramétricos tendem a ter melhor desempenho quando existe um número pequeno de observações por preditor.

Métodos paramétricos também são preferíveis pela sua interpretabilidade.

Exemplo: Dados de Cancer de Próstata

library(ElemStatLearn)
data(prostate)
  • lcavol: log cancer volume
  • lweight: log prostate weight
  • lpsa: response
  • train: a logical vector
  • age: in years
  • lbph: log of the amount of benign prostatic hyperplasia
  • svi: seminal vesicle invasion
  • lcp: log of capsular penetration
  • gleason: a numeric vector
  • pgg45: percent of Gleason score 4 or 5

Exemplo prostate

Resposta lpsa: nível de um antígeno específico de câncer de próstata.

Considere inicialmente apenas um preditor: lcavol (log do volume do câncer).

Exemplo prostate

Separando os dados de treinamento e teste:

library(dplyr)
prost.tr = prostate %>% filter(train) # train observations
prost.te = prostate %>% filter(!train) # test observations

Vamos ajustar uma regressão linear simples:

prost.linreg =  lm(lpsa ~ lcavol, data = prost.tr) 
summary(prost.linreg)$coef
##              Estimate Std. Error   t value     Pr(>|t|)
## (Intercept) 1.5163048 0.14772483 10.264387 3.123765e-15
## lcavol      0.7126351 0.08199036  8.691694 1.733134e-12

Exemplo prostate

Exemplo prostate

MSE para os dados de treinamento:

library(ModelMetrics)
pred.tr = predict(prost.linreg)
(lm.train.mse <- mse(prost.tr$lpsa, pred.tr))
## [1] 0.6646057

MSE para os dados de teste:

pred.te = predict(prost.linreg, newdata = prost.te)
(lm.test.mse <- mse(prost.te$lpsa, pred.te))
## [1] 0.4797387

Exemplo prostate: KNN

Ajustando uma regressão KNN com \(k=1, 5 e 15\).

Como aqui temos apenas uma covariável, não é necessário padronizar.

Para os dados de treinamento, usando o pacote FNN:

library(dplyr)
library(FNN)
Xtrain = prost.tr %>% select(lcavol) 

# Ajustando KNN e calculando o MSE_Tr para k=1
TrainKnny1 <- knn.reg(train = Xtrain, test = Xtrain, y = prost.tr$lpsa, k=1)
knn1.train.mse <- mse(prost.tr$lpsa, TrainKnny1$pred)

Exemplo prostate: KNN

Predição para os dados de teste, calculando as distâncias em relação aos dados de treinamento.

Xtest = prost.te %>% select(lcavol)

TestKnny1 <- knn.reg(train = Xtrain, test = Xtest, y = prost.tr$lpsa, k=1)
knn1.test.mse <- mse(prost.te$lpsa, TestKnny1$pred)

Exemplo prostate: comparando diferentes métodos

library(printr)
res <- cbind(c("LM", "KNN 15", "KNN5", "KNN 1"),
             round(c(lm.train.mse, knn15.train.mse, knn5.train.mse, knn1.train.mse), 2),
             round(c(lm.test.mse, knn15.test.mse, knn5.test.mse, knn1.test.mse), 2))

rbind(c("Método", "MSE-Treino", "MSE-Teste"), res)
Método MSE-Treino MSE-Teste
LM 0.66 0.48
KNN 15 0.69 0.52
KNN5 0.55 0.48
KNN 1 0.01 0.83

Exemplo prostate

k MSE-Train MSE-Test
1 0.0087720 0.8303316
4 0.5141037 0.4176132
7 0.6181437 0.4427197
9 0.6680769 0.4781785
12 0.7100130 0.4959484
14 0.6904456 0.5087311
17 0.7402980 0.5448028
20 0.7790462 0.5474455
45 0.9920038 0.7221205
48 1.0381039 0.7585145
50 1.0563493 0.7720519

Exemplo prostate

Leitura

  • ISLR: Seções 3.5



Slides produzidos pelas professoras:

  • Samara Kiihl

  • Tatiana Benaglia


Algumas figuras foram retiradas dos livros ELS e ISLR com permissão dos autores.