Algoritmo de Classificação: KNN (K Nearest Neighbors) no R

O código a seguir é um exemplo de execução de KNN no R. Além do código para executar o algoritmo em si, você verá que há uma parte de análise descritiva que eu inseri. É sempre interessante saber o que há no seu conjunto de dados. No caso, utilizaremos um dataset famoso chamado iris que não requer nenhum download. Peço encarecidamente que você visite o post Algoritmo de Classificação: KNN (K Nearest Neighbors), caso conheça pouco do algoritmo KNN.

Bom, vamos começar carregando a base e analisando o que há dentro dela.

# Mostra as primeiras linhas

head(iris)

# Mostra as ultimas linhas

tail(iris)

# Resumo (minimo, maximo, mediana, quartis)

summary(iris)

# Resumo 2 (quantidade, missing, quartis, etc)

library("Hmisc");

describe(iris);

# Estrutura das variaveis (tipo)
str(iris)

# Histograma de cada variavel por especie

library("ggplot2")

ggplot(iris,aes(x=Sepal.Length))+geom_histogram()+facet_grid(~Species)+theme_bw()

ggplot(iris,aes(x=Sepal.Width))+geom_histogram()+facet_grid(~Species)+theme_bw()

ggplot(iris,aes(x=Petal.Length))+geom_histogram()+facet_grid(~Species)+theme_bw()

ggplot(iris,aes(x=Petal.Width))+geom_histogram()+facet_grid(~Species)+theme_bw()

# Graf de Dispersao por especie

qplot(Sepal.Length, Sepal.Width, data=iris, color=Species)

qplot(Petal.Length, Petal.Width, data=iris, color=Species)

Este começo é bastante autoexplicativo, então não vejo muita necessidade de abordar estes trechos iniciais. O que estou fazendo aí é apenas entendendo o que temos em mãos, não diz respeito especificamente ao knn. Como podemos ver, temos uma base com as informações dos comprimentos e larguras das pétalas e caules de cada espécie de flor. O que queremos é, com esse histórico, conseguir prever a espécie de uma flor com base nas informações de pétala e caule. Tendo esta base em mãos, se alguém te trouxer uma flor com a pétala tendo comprimento 1.5 e largura 0.5 e de caule com comprimento 5.0 e largura 3.6, você consegue dizer qual a espécie dessa flor? Por enquanto, imagino que não. Mas acompanhe as linhas a seguir que você será capaz disso.

Como expliquei no post Algoritmo de Classificação: KNN (K Nearest Neighbors), o KNN faz uso da distância entre os pontos. Então precisamos ajustar as grandezas das medidas:

# Scale data
# Scale: (x - media(x)) / desvpad(x)
iris_normal = iris
iris_normal[, -5] = scale(iris[, -5])

Como também já foi explicado no post mencionado, podemos usar o histórico para fazer predições. Porém, não adianta a gente tentar rodar um modelo com essa base inteira, a gente precisa usar parte dela para criar o modelo e a outra parte para testá-lo. Logo, a gente deve separar a base em treino e teste. Vamos reservar 60% da base para treinar o modelo, i.e. para criar nossas classes com base nas informações e os 40% restantes usaremos para testar a acurácia do modelo.

set.seed(000000)

# Separa em treino e teste
## Gera indices da base treino e teste
train_index = sample(1:nrow(iris_normal), 0.6*nrow(iris_normal), replace = FALSE)

## Gera base treino e teste
treino = data.frame()
treino = iris_normal[train_index,]

teste = data.frame()
teste = iris_normal[-train_index,]

Agora, o que fazemos é rodar o algoritmo. O que o R irá fazer é usar a base treino para definir as classes (no caso as espécies) e usar essa informação para predizer a que classe pertence cada flor da base teste. Depois, verificamos o acerto do modelo:

# Carrega biblioteca para rodar KNN
library("class")

# Roda com k=2
Knn_K2= knn(treino[,-5], teste[,-5],
treino$Species, k=2, prob=TRUE)

# Roda com k=3
Knn_K3= knn(treino[,-5], teste[,-5],
treino$Species, k=3, prob=TRUE)

Testei o modelo para k igual a 2 e 3. Era possível testar para outros casos, mas por enquanto vou ficar somente nesses dois. Vejamos qual teve maior acerto:

# Analisa a matriz de confusao para cada um

table(teste$Species, Knn_K2)

table(teste$Species, Knn_K3)

# Analisa acuracia

sum(Knn_K2==teste$Species)/length(teste$Species)*100

sum(Knn_K3==teste$Species)/length(teste$Species)*100

A matriz de confusão mostra qual a espécie que o modelo previu e qual era a correta. É interessante pois você pode observar quanto de erro tipo I e tipo II seu modelo gera. No caso da acurácia, verificamos o acerto como um todo. Pela acurácia, o melhor modelo seria o utilizado para k = 3.

Claro que agora você está pensando “po, mas testar cada k ali é muito chato, por que não automatizar”? E foi isso que um usuário do Kaggle (Xavier Vivancos García) fez:

# Método para comparar diferentes k's

# cria uma lista para receber as predicoes

Knn_Testes = list()

# cria variavel para receber acuracia

acuracia = numeric()

# cria loop para testar de k=1 ate k=20

for(k in 1:20){

Knn_Testes[[k]] = knn(treino[,-5], teste[,-5], treino$Species, k, prob=TRUE)
acuracia[k] = sum(Knn_Testes[[k]]==teste$Species)/length(teste$Species)*100

}

# Comparacao grafica das acuracias
plot(acuracia, type="b", col="blue", cex=1, pch=1,
xlab="k", ylab="Acuracia",
main="Acuracia para cada k")

# Linha vertical vermelha marcando o maximo
abline(v=which(acuracia==max(acuracia)), col="red", lwd=1.5)

# Linha horizontal cinza marcando o maximo
abline(h=max(acuracia), col="grey", lty=2)

# Linha horizontal cinza para marcar o minimo
abline(h=min(acuracia), col="grey", lty=2)

Se você simplesmente digitar acuracia no R você vai obter a acurácia para os 20 casos. Fique a vontade para rodar para quantos k’s achar necessário. Como pudemos verificar, para k=1 e k=5, temos uma boa acurácia. Se utilizarmos k=5, podemos então fazer a previsão para aquela flor que queríamos lá em cima? Aquela com a pétala tendo comprimento 1.5 e largura 0.5 e de caule com comprimento 5.0 e largura 3.6. Bom, para isso, o que precisamos fazer é substituir essa flor pela base teste na execução do KNN:

# flor que queremos definir a especie
flor_exemplo = c(5, 3.6, 1.5, 0.5)

# copia o cabecalho da base teste
base_exemplo = teste[0:1, -5]

# une cabecalho com a flor
base_exemplo = rbind(base_exemplo, flor_exemplo)

# exclui primeira linha
base_exemplo = base_exemplo[2,]

Knn_K5_Predicao = knn(treino[,-5], base_exemplo,
treino$Species, k=5, prob=TRUE)

Knn_K5_Predicao

Pronto, aí está a espécie da flor! Bom, deve ser possível criar o dataframe a partir do teste[] de um jeito mais inteligente do que a maneira demonstrada acima (confesso que me causou certo desconforto). De qualquer forma, espero que o código seja proveitoso para você.

E se você gostou do post, não vá embora sem deixar uma curtida ou um comentário. Eu sei que não parece relevante, mas faz diferença para mim e custa pouco para você, vai… Se encontrou algum erro ou tem alguma sugestão, dúvida, elogio ou crítica, pode escrever nos comentários ou me enviar uma mensagem diretamente em Sobre o Estatsite. E visite também a conta do Twitter @EstatSite, costumo postar algumas coisas bem rapidinho por lá, geralmente são posts e códigos mais curtos ou compartilhamento de algo legal ou alguma reflexão.

Forte abraço e bons estudos!

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *