Aplicando KNN no Banco de Dados Iris
16 May 2020 - Anthony João Bet
Agora que já conhecemos o funcionamento do KNN iremos investigar os dados do Iris, aplicar o algoritmo e testar os resultados. Tudo isso será feito utilizando a biblioteca pandas para ler os dados e sklearn para aplicar o modelo.
Baixando os dados
Você pode encontra os dados para o projeto no UCI Machine Learning Repository ou diretamente pelo
link, o nome do arquivo é iris.data
.
O UCI foi criado em 1987 e hoje agrega mais de 490 datasets para diversos tipos de projetos.
Descrição dos dados encontrada no UCI:
- sepal length in cm
- sepal width in cm
- petal length in cm
- petal width in cm
- class:
- Iris Setosa
- Iris Versicolour
- Iris Virginica
Se abrirmos o arquivo de dados é isso que encontraremos:
As quatro primeiras colunas representam as características de uma planta e a última coluna, sua espécie. Então a pergunta que queremos responder é:
Dado um novo conjunto de características ['sepal_length','sepal_width','petal_length','petal_width']
, qual é a espécie dessa planta?
Bora pro codigo
Para ler o dataset nós iremos utilizar a biblioteca pandas;
import pandas as pd
def carregar_dados(path):
"""Função para ler os dados"""
df = pd.read_csv(path, names=['sepal_length','sepal_width','petal_length','petal_width','class'])
return df
df = carregar_dados('iris.data')
Em geral, em problemas reais muitos dados podem estar faltando no datset, isso pode acontecer por diversos motivos como a falha em algum sensor, erro humano, aleatoriedade no sistema e por aí vai. Os dados que estamos utilizando não possuem nem um erro desse tipo, então não iremos nos preocupar com isso agora. Tratar os dados antes de aplicar qualquer modelos é uma parte essencial do processo, mas iremos falar sobre isso quando chegar a hora.
No UCI podemos encontrar informações estatísticas sobre os dados:
Summary Statistics:
Min Max Mean SD Class Correlation
sepal length: 4.3 7.9 5.84 0.83 0.7826
sepal width: 2.0 4.4 3.05 0.43 -0.4194
petal length: 1.0 6.9 3.76 1.76 0.9490 (high!)
petal width: 0.1 2.5 1.20 0.76 0.9565 (high!)
Distribuição das classes: 33.3% para cada uma das 3 classes.
Isso nos diz que o tamanho das pétalas está altamente correlacionado com sua classe e que número de amostras está igualmente dividido entre o total dos dados, isso é muito importante, pois significa, de forma grosseira, que cada classe possui a mesma importância.
Nossos dados estão todos em um dataframe, precisamos separá-los em dois grupos X e Y, onde X será um novo conjunto apenas com as características (input) e Y um conjunto com as classes:
X = df[['sepal_length','sepal_width','petal_length','petal_width']]
Y = df['class']
Outra coisa que precisamos mudar é a forma como identificamos nossas classes, no momento cada classe é identificada por uma string, e queremos que cada classe seja identificada por um número inteiro. Essa transformação pode ser feita facilmente com a biblioteca sklearn, dessa forma:
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
encoder.fit(Y)
Y = encoder.transform(Y)
Se printarmos novamente, é isso que temos:
print(Y)
➜ iris python3 classification.py
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2]
Meio feio, mas é isso mesmo que queremos.
Agora precisamos preparar os dados para o treinamento. Para fazer isso os dados devem embaralhados e separados em grupo de treino e grupo de deste. O grupo de treino será utilizado para treinar o algoritmo, e o grupo de teste para validar este treino, ou seja, testar o algoritmo em dados que ele nunca viu, para garantir sua eficácia.
Novamente iremos utilizar a biblioteca sklearn. Existem dois parâmetros que precisamos entender nessa função, o parâmetro test_size
regula a porcentagem
do dataset que será separado como teste e com shuffle
escolhemos se queremos que os dados sejam embaralhados antes de serem separados, se olharmos para a
figura anterior veremos que as classes estão dispostas em sequência, sendo assim precisamos embaralhar nossos dados;
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split( X,
Y,
test_size = 0.3,
shuffle = True
)
Tudo pronto! Agora podemos finalmente aplicar o algoritmo nos dados;
from sklearn.neighbors import KNeighborsClassifier
modelo = KNeighborsClassifier(n_neighbors = 5,
algorithm = 'brute'
)
modelo.fit(X_train, Y_train)
Não é necessário informar que estamos utilizando distância euclidiana, isso já é escolhido por padrão.
O parâmetro n_neighbors
define quantos vizinhos vamos utilizar para contagem, devemos escolher um número que não gere empates e
algorithm = 'brute'
significa que o modelo irá calcular a distância entre o novo ponto e todos os outros pontos dos dados de treino, este é o jeito mais
pedestre e menos eficiente, mas como nosso banco de dados é pequeno isso não será um problema.
É isso aí, após aplicar o função fit nos dados o modelo estará “treinado”, agora podemos utilizar o modelo para fazer predições. Vamos escolher um ponto do conjunto de teste e ver qual a classificação:
#novo ponto será o último ponto em X_test
novo_ponto = X_test.values[-1]
print(f'Novo ponto: {novo_ponto}')
prediction = modelo.predict([novo_ponto])
print(f'Predição: {prediction}, Classe correta: {Y_test[-1]}')
Que nos retorna:
➜ iris python3 classification.py
Novo ponto: [6.3 3.3 4.7 1.6]
Predição: [1], Classe correta: 1
Um ponto é muito pouco para sabermos se a classificação é boa ou não, a acuracia do modelo é dada pela razão entre o número de acertos e o número de tentativas.
Podemos fazer o seguinte, vamos comparar o conjunto de predição com o conjunto
de teste (prediction == Y_test
) , isso irá comparar os dois arrays entrada por entrada, em ordem, e irá retornar um array de verdadeiro ou falso
([True, True, False, True, ... , False]
), podemos
então somar esse array, isso nos dará o número de acertos já que
verdadeiros são representados por 1 e falsos por 0, depois basta dividir
isso pelo tamanho da conjunto.
prediction = modelo.predict(X_test)
acertos = (prediction == Y_test).sum()
erros = len(X_test) - acertos
acuracia = acertos / len(prediction)
print(f'Acuracia: {acuracia}')
print(f'Acertos: {acertos}')
print(f'Erros: {erros}')
Ao rodarmos o programa, esse é o resultado que obtemos:
➜ iris python3 classification.py
Acuracia: 0.9555555555555556
Acertos: 43
Erros: 2
Note a que a cada vez que o programa for executado, o resultado será um pouco diferente, isso ocorre porque estamos escolhendo aleatoriamente os grupos de treino e teste a cada vez que rodamos o programa, para obtermos uma estimativa mais precisa da acurácia seria necessário fazer uma média, rodando varias vezes o programa. Depois de fazer isso você pode variar o número de K-vizinhos e observar como a acurácia reage a isso.
Eu não me preocupei em explicar como funciona cada biblioteca e não mostrei todas as suas ferramenta, mas deixei linkado as paginas com as documentações. É super difícil entender o funcionamento de cada função dessa na primeira vez, o que eu mostrei aqui tem o intuito se ser um primeiro passo, então não deixe de ler a documentação e aplicar em outros problemas.
Obrigado pela leitura e até a próxima.