IV Semana Acadêmica Integrada da UFT Gurupi: MiniCurso: Machine Learning com R

Author

Professor Dr. Fernando Machado Haesbaert

IV Semana Acadêmica Integrada da UFT Gurupi
Câmpus de Gurupi da UFT, Gurupi - Tocantins
De 04/11 a 07/11 de 2024

Veremos uma introdução prática e objetiva, cobrindo os principais conceitos e aplicações reais relevântes para as áreas de Agronomia, Engenharia Florestal, Biotecnologia, Química e Agroindústria.

Objetivos Gerais:

  • Introduzir os conceitos básicos de Machine Learning (ML).
  • Demonstrar o uso de R para modelagem preditiva.
  • Aplicar algoritmos de ML em conjuntos de dados.
  • Incentivar o pensamento crítico sobre a aplicação de ML em problemas práticos.

Introdução ao Machine Learning (15 minutos)

Apresentar os principais conceitos de Machine Learning, supervisionado e não supervisionado.
Tópicos: Definição de ML: O que é e por que é importante?

Tipos de ML

Supervisionado: Regressão e classificação.
Não supervisionado: Agrupamento (clustering).

Conceitos fundamentais: Features (variáveis preditoras), target (variável de resposta), treino, validação e teste.

Material de Apoio:
Slides simples com exemplos visuais aplicados às áreas de interesse dos alunos (ex.: previsões de produtividade agrícola, classificação de espécies, etc.).

Introdução ao R e ao RStudio aplicado ao Machine Learning

Definindo a pasta de trabalho.

Code
setwd("~/Ciência de Dados/MC Machine Learning com R")

Pacotes básicos: * readr e readxl para importação de dados
* tidyverse para manipulação de dados
* caret para machine learning

Code
#install.packages("tidyverse")
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Importação dos Dados

Importação de dados com readr.

Code
library(readxl)
tabela <- readxl::read_xlsx("soja.xlsx")

Tarefas comuns de pré-processamento de dados

Limpeza e tratamento de dados (ex.: valores faltantes, variáveis categóricas).
Seleção de variáveis relevantes para o modelo.

Resumos Estatísticos e Visualizações dos Dados

Code
glimpse(tabela)
Rows: 200
Columns: 6
$ pH     <dbl> 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1…
$ MO     <dbl> 3.8, 3.6, 3.6, 3.5, 3.5, 3.5, 3.4, 3.4, 3.4, 3.3, 3.3, 3.3, 3.3…
$ P      <dbl> 33.4, 32.7, 32.1, 31.8, 31.4, 30.9, 30.5, 30.5, 30.4, 30.2, 30.…
$ K      <dbl> 34.3, 34.1, 33.9, 33.8, 33.6, 33.6, 33.4, 33.3, 33.3, 33.2, 33.…
$ Arg    <dbl> 40.3, 39.3, 37.3, 36.1, 35.9, 34.8, 34.2, 34.0, 33.7, 33.4, 33.…
$ Classe <chr> "alta", "alta", "alta", "alta", "alta", "alta", "alta", "alta",…
Code
summary(tabela)
       pH             MO              P               K              Arg       
 Min.   :3.60   Min.   :0.900   Min.   :14.10   Min.   :25.30   Min.   :10.30  
 1st Qu.:5.90   1st Qu.:2.175   1st Qu.:22.70   1st Qu.:29.25   1st Qu.:22.00  
 Median :6.55   Median :2.500   Median :25.10   Median :30.40   Median :25.10  
 Mean   :6.50   Mean   :2.494   Mean   :24.86   Mean   :30.28   Mean   :25.28  
 3rd Qu.:7.20   3rd Qu.:2.800   3rd Qu.:26.90   3rd Qu.:31.60   3rd Qu.:28.32  
 Max.   :8.90   Max.   :3.800   Max.   :33.40   Max.   :34.30   Max.   :40.30  
    Classe         
 Length:200        
 Class :character  
 Mode  :character  
                   
                   
                   
Code
#if(!require(skimr)) install.packages("skimr")
library(skimr)
skim(tabela)
Data summary
Name tabela
Number of rows 200
Number of columns 6
_______________________
Column type frequency:
character 1
numeric 5
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
Classe 0 1 4 5 0 3 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
pH 0 1 6.50 0.95 3.6 5.90 6.55 7.20 8.9 ▁▃▇▆▂
MO 0 1 2.49 0.51 0.9 2.18 2.50 2.80 3.8 ▁▃▇▆▂
P 0 1 24.86 3.31 14.1 22.70 25.10 26.90 33.4 ▁▃▇▇▂
K 0 1 30.28 1.84 25.3 29.25 30.40 31.60 34.3 ▁▃▇▆▂
Arg 0 1 25.28 4.83 10.3 22.00 25.10 28.33 40.3 ▁▃▇▃▁
Code
library(visdat)
vis_dat(tabela)

Code
vis_miss(tabela)

Classificação de Dados com Machine Learning

Nesta aula veremos alguns algoritmos de classificação, começando com o K-Nearest Neighbors (KNN), que é um algoritmo de aprendizado supervisionado. O KNN é um algoritmo simples que armazena todos os casos disponíveis e classifica novos casos com base em uma medida de similaridade (por exemplo, distância Euclidiana). O KNN tem sido usado em estatística e reconhecimento de padrões por muitos anos.

As técnicas de classificação são utilizadas para a identificação do rótulo de determinadas observações com base em características e informações previamente conhecidas (Lantz 2013). A classificação é uma técnica de aprendizado supervisionado, onde o objetivo é identificar a qual classe pertence uma determinada observação.

A capacidade do modelo de gerar uma predição satisfatória é denominada capacidade de generalização, ou seja, quão bom o modelo é na predição de classe ou valor dos novos registros ainda não rotulados.

Neste tutorial exploramento o algoritmo K vizinhos mais próximos (K Nearest Neighbor - KNN).

Classificação com Algortimo KNN

O algoritmo KNN é um dos algoritmos mais simples de classificação e é baseado na ideia de que os objetos semelhantes tendem a estar próximos uns dos outros. O algoritmo KNN é um tipo de aprendizado supervisionado, onde o resultado é classificado por maioria de votos dos vizinhos mais próximos.

O algoritmo K-Nearest Neighbors (KNN) é um dos métodos clássicos de classificação, conhecido por sua simplicidade e eficiência. Ele é amplamente utilizado para classificar objetos com base em exemplos de treinamento que estão mais próximos no espaço de características, ou seja, ele toma como base a proximidade entre pontos de dados para inferir a classe de novos exemplos.

Para seu funcionamento, o KNN necessita inicialmente de uma métrica de distância que permita calcular o quão próximos dois exemplos estão um do outro. A métrica mais comum utilizada é a distância Euclidiana, mas outras métricas, como a distância de Manhattan ou de Minkowski, também podem ser aplicadas, dependendo da natureza dos dados.

Outro passo importante no uso do KNN é a definição do valor de K, que indica quantos vizinhos mais próximos serão considerados pelo algoritmo na classificação. A escolha de K é crucial, pois um valor muito pequeno pode tornar o modelo sensível a ruídos, enquanto um valor muito grande pode diluir a influência dos vizinhos mais relevantes.

Finalmente, a classificação de um exemplo desconhecido é feita por meio de uma votação majoritária entre os K vizinhos mais próximos. Ou seja, o rótulo de classe que for mais frequente entre os vizinhos próximos será atribuído ao exemplo a ser classificado. Este processo simples e intuitivo faz do KNN uma escolha comum em problemas de classificação, especialmente quando a interpretação da decisão é importante.

A imagem acima ilustra o funcionamento do algoritmo KNN. Neste exemplo, temos um conjunto de dados com duas classes distintas (amarelo e roxo) e um novo exemplo a ser classificado (ponto vermelho). O algoritmo KNN calcula a distância entre o novo exemplo e os exemplos de treinamento, selecionando os K vizinhos mais próximos. Neste caso, K = 3, então os três vizinhos mais próximos são selecionados (dois da classe roxo e um da classe amarelo). Como a maioria dos vizinhos é da classe roxo, o novo exemplo é classificado como roxo. Para o K = 6, o novo exemplo seria classificado como amarelo, pois são quatro amarelos e dois roxos.

Vantagens e Desvantagens do KNN

Vantagens

  1. Simplicidade: O KNN é um algoritmo simples e fácil de entender, o que o torna uma boa escolha para problemas de classificação.
  2. Não paramétrico: O KNN não faz suposições sobre a distribuição dos dados, o que o torna útil para dados não lineares e complexos.
  3. Interpretabilidade: A classificação do KNN é baseada na proximidade dos exemplos, o que torna fácil interpretar as decisões do modelo.
  4. Robustez: O KNN é robusto a outliers e ruídos nos dados, pois considera vários vizinhos próximos em vez de depender de um único exemplo.

Desvantagens

  1. Sensibilidade à escala: O KNN é sensível à escala dos dados, o que pode levar a resultados distorcidos se as variáveis tiverem escalas diferentes.
  2. Custo computacional: O KNN precisa calcular a distância entre o novo exemplo e todos os exemplos de treinamento, o que pode ser computacionalmente caro para grandes conjuntos de dados.
  3. Escolha de K: A escolha do valor de K é crucial para o desempenho do modelo, e um valor inadequado pode levar a resultados subótimos.

Exemplo de Classificação com Algortimo KNN

Code
dados <- tibble(
  a1 = c(0,10,2,6,4,1,8,10,6),
  a2 = c(250,150,90,78,20,170,160,180, 200),
  a3 = c(36,34,10,8,1,70,41,38,45))

classe <- factor(c(rep(c("A", "B"), 4), NA))
dados <- cbind(dados, classe)

Vamos visualizar os dados:

a1 a2 a3 classe
0 250 36 A
10 150 34 B
2 90 10 A
6 78 8 B
4 20 1 A
1 170 70 B
8 160 41 A
10 180 38 B
6 200 45 NA

Padronizar os dados

A padronização dos dados é uma etapa importante para garantir que todas as variáveis tenham a mesma escala e não influenciem indevidamente o algoritmo.

O cálculo do valor padronizado é feito subtraindo a média da variável e dividindo pelo desvio padrão:
\[x^* = \frac{x_i - \bar x}{s} \] Onde o \(x^*\) é o valor padronizado, \(x_i\) é o valor original, \(\bar x\) é a média da variável e \(s\) é o desvio padrão.
Para isso, vamos padronizar os dados utilizando a função scale() do R.

Code
# Padronizando
df <- scale(dados[,1:3], 
            center = T)

Vamos visualizar os dados padronizados:

a1 a2 a3
-1.3984751 1.50950320 0.2099027
1.2794559 0.08245186 0.1177503
-0.8628889 -0.77377895 -0.9880787
0.2082835 -0.94502511 -1.0802311
-0.3273027 -1.77271489 -1.4027646
-1.1306820 0.36786212 1.7764938
0.7438697 0.22515699 0.4402838
1.2794559 0.51056726 0.3020551
0.2082835 0.79597753 0.6245886

Calculando a distância entre dois pontos.

Existem várias formas diferentes de calcular essa distância. A mais simples é a distância euclidiana. É a distância entre pontos, que pode ser provada pela aplicação repetida do teorema de Pitágoras.

A distância euclidiana entre dois pontos, p e q, em um espaço n-dimensional é calculada da seguinte forma:

\[d(p, q) = \sqrt{(p_1 - q_1)^2 + (p_2 - q_2)^2 + \ldots + (p_n - q_n)^2}\]

Onde: - \(p_1, p_2, \ldots, p_n\) são as coordenadas do ponto p; - \(q_1, q_2, \ldots, q_n\) são as coordenadas do ponto q; - \(n\) é o número de dimensões do espaço.

Essencialmente, a distância Euclidiana é a raiz quadrada da soma dos quadrados das diferenças entre as coordenadas correspondentes de 𝑝 e 𝑞.

Vamos calcular a distância entre os pontos:

Code
distancias <- philentropy::distance(x = df,
                              method = "euclidean") |> 
  round(digits = 3)
Metric: 'euclidean'; comparing: 9 vectors.
Code
distancias
      v1    v2    v3    v4    v5    v6    v7    v8    v9
v1 0.000 3.036 2.634 3.205 3.811 1.957 2.508 2.860 1.806
v2 3.036 0.000 2.558 1.907 2.887 2.940 0.641 0.466 1.383
v3 2.634 2.558 0.000 1.089 1.207 3.003 2.371 2.811 2.492
v4 3.205 1.907 1.089 0.000 1.037 3.417 1.992 2.275 2.437
v5 3.811 2.887 1.207 1.037 0.000 3.916 2.922 3.271 3.316
v6 1.957 2.940 3.003 3.417 3.916 0.000 2.306 2.829 1.817
v7 2.508 0.641 2.371 1.992 2.922 2.306 0.000 0.622 0.804
v8 2.860 0.466 2.811 2.275 3.271 2.829 0.622 0.000 1.155
v9 1.806 1.383 2.492 2.437 3.316 1.817 0.804 1.155 0.000

Observe que o resultado é uma matriz de distâncias entre os pontos. Cada elemento da matriz representa a distância entre os pontos correspondentes nas linhas e colunas. Para o nosso exemplo em estudo, o elemento na linha 9 é o que desejamos verificar as distâncias.

Desta forma, a distância entre o ponto 9 e os demais pontos é observada na última linha da matriz. Sendo a distância do ponto 9 para o ponto 1 de 1.806, para o ponto 2 de 1.383, para o ponto 3 de 2.492, para o ponto 4 de 2.437, para o ponto 5 de 3.316, para o ponto 6 de 1.817, para o ponto 7 de 0.804 e para o ponto 8 de 1.155.

Outra função que pode ser utilizada para calcular a distância entre os pontos é a função dist() do pacote {stats} R.

Code
dist2 <- dist(df, method = "euclidean") |> 
  round(digits = 3)
dist2
      1     2     3     4     5     6     7     8
2 3.036                                          
3 2.634 2.558                                    
4 3.205 1.907 1.089                              
5 3.811 2.887 1.207 1.037                        
6 1.957 2.940 3.003 3.417 3.916                  
7 2.508 0.641 2.371 1.992 2.922 2.306            
8 2.860 0.466 2.811 2.275 3.271 2.829 0.622      
9 1.806 1.383 2.492 2.437 3.316 1.817 0.804 1.155

O resultado é a distância entre os pontos, de forma semelhante a função philentropy::distance().

Classificação do ponto 9

Vamos classificar o ponto 9 utilizando a lógica por trás do algoritmo KNN. Para isso, vamos considerar inicialmente os 3 vizinhos mais próximos (k = 3). E por votação majoritária atribui-se à amostra desconhecida a classe mais frequente entre os K vizinhos. Cada vizinho vota com a sua classe, e a classe com mais votos é atribuída ao novo ponto. Por isso a importância de escolher um valor de K ímpar.

Voltando a nossa base de dados originais.

Code
dados
  a1  a2 a3 classe
1  0 250 36      A
2 10 150 34      B
3  2  90 10      A
4  6  78  8      B
5  4  20  1      A
6  1 170 70      B
7  8 160 41      A
8 10 180 38      B
9  6 200 45   <NA>

Vamos analisar as distâncias do ponto 9 para os demais pontos em ordem crescente.

Code
distancias[9,] |> 
  sort()
   v9    v7    v8    v2    v1    v6    v4    v3    v5 
0.000 0.804 1.155 1.383 1.806 1.817 2.437 2.492 3.316 

Agora vamos considerar os 3 vizinhos mais próximos para o ponto 9. Que são os pontos 7 (distância de 0.804), 8 (distância de 1.155) e 2 (distância de 1.383). Agora obervando a classe desses pontos, temos que a classe do ponto 7 é \(A\), do ponto 8 é \(B\) e do ponto 2 é \(B\), sendo a classe mais frequente a classe B. Portando, o ponto 9 é classificado como \(B\).

Se quisermos classificar o ponto 9 para um valor de \(K = 5\), temos que os pontos mais próximos são os pontos 7, 8, 2, 1 e 6. E a classe mais frequente é a classe \(B\). Portanto, o ponto 9 é classificado como \(B\) também para k = 5.

Para \(k = 7\), temos que os pontos mais próximos são os pontos 7, 8, 2, 1, 6, 4 e 3. E a classe mais frequente é a classe \(B\). Portanto, o ponto 9 é classificado como \(B\) para k = 7.

Implementação do KNN

Para isso, vamos utilizar a função knn() do pacote {class} R.

Como é um exemplo simples, não dividimos em treino e teste, no entanto o equivalente a nossos conjunto de dados teste são os oito primeiros pontos e o ponto 9 é o ponto a ser classificado.

Code
treino <- df[1:8,]
classe <- dados[1:8,4]
prever <- df[9,1:3] # Elemento da linha 9

Agora vamos classificar o ponto 9 para \(k = 3\) utilizando a função knn() do pacote {class} R.

Code
if(!require(class)) install.packages("class")
Carregando pacotes exigidos: class
Code
library(class)
previsão <- knn(treino, 
                prever, 
                cl = classe, 
                k = 3)
previsão
[1] B
Levels: A B

Observamos que a previsão para o ponto 9 é a classe \(B\).

Mudando o valor do hiperparâmetro \(k\) para 5 e 7, temos:

Code
previsão <- knn(treino, 
                prever, 
                cl = classe, 
                k = 5)
previsão
[1] B
Levels: A B

A classificação do ponto 9 para \(k = 5\) é a classe \(B\). E para \(k = 7\) temos:

Code
previsão <- knn(treino, 
                prever, 
                cl = classe, 
                k = 7)
previsão
[1] B
Levels: A B

Para os três valores de \(k\) testados, a classificação do ponto 9 foi a classe \(B\). Podemos concluir que o ponto 9 foi classificado como \(B\) para os valores de \(k = 3\), \(k = 5\) e \(k = 7\), sendo razoável aceitas esta classificação.

Exemplo 2 de Aplicação do KNN

Vejamos outro exemplo de aplicação do KNN.

O exemplo a seguir é um exemplo de classificação de sementes de soja.

Code
rm(list = ls())

Carregando os dados

Code
# Classes de sementes de soja
df <- read_excel("soja.xlsx")
glimpse(df)
Rows: 200
Columns: 6
$ pH     <dbl> 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1…
$ MO     <dbl> 3.8, 3.6, 3.6, 3.5, 3.5, 3.5, 3.4, 3.4, 3.4, 3.3, 3.3, 3.3, 3.3…
$ P      <dbl> 33.4, 32.7, 32.1, 31.8, 31.4, 30.9, 30.5, 30.5, 30.4, 30.2, 30.…
$ K      <dbl> 34.3, 34.1, 33.9, 33.8, 33.6, 33.6, 33.4, 33.3, 33.3, 33.2, 33.…
$ Arg    <dbl> 40.3, 39.3, 37.3, 36.1, 35.9, 34.8, 34.2, 34.0, 33.7, 33.4, 33.…
$ Classe <chr> "alta", "alta", "alta", "alta", "alta", "alta", "alta", "alta",…
Code
# Transformar a classe em fator na sequêcia: Alta, Média e Baixa. 
df$Classe <- factor(df$Classe, 
                    levels = c("alta", "media", "baixa"))
df$Classe
  [1] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [13] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [25] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [37] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [49] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [61] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [73] alta  alta  alta  alta  alta  alta  alta  alta  alta  media media media
 [85] media media media media media media media media media media media media
 [97] media media media media media media media media media media media media
[109] media media media media media media media media media media media media
[121] media media media media media media media media media media media media
[133] media media media media media media media media media media baixa baixa
[145] baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa
[157] baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa
[169] baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa
[181] baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa
[193] baixa baixa baixa baixa baixa baixa baixa baixa
Levels: alta media baixa

Vamos visualizar os dados:

Code
plot(df[,1:5])

Visualizar os dados usando o pacote {GGally}

Code
#install.packages("GGally")
library(GGally)
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2
Code
ggpairs(df, 
        columns = 1:5, 
        mapping = aes(color = Classe))

A função skimr::skim() é uma função que fornece um resumo estatístico dos dados.

Code
# Verificação de escala.
skimr::skim(df)
Data summary
Name df
Number of rows 200
Number of columns 6
_______________________
Column type frequency:
factor 1
numeric 5
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
Classe 0 1 FALSE 3 alt: 81, med: 61, bai: 58

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
pH 0 1 6.50 0.95 3.6 5.90 6.55 7.20 8.9 ▁▃▇▆▂
MO 0 1 2.49 0.51 0.9 2.18 2.50 2.80 3.8 ▁▃▇▆▂
P 0 1 24.86 3.31 14.1 22.70 25.10 26.90 33.4 ▁▃▇▇▂
K 0 1 30.28 1.84 25.3 29.25 30.40 31.60 34.3 ▁▃▇▆▂
Arg 0 1 25.28 4.83 10.3 22.00 25.10 28.33 40.3 ▁▃▇▃▁

Podendo ser realizada por categoria.

Code
# Resumo por Classe
df |> 
      group_by(Classe) |>
      skimr::skim()
Data summary
Name group_by(df, Classe)
Number of rows 200
Number of columns 6
_______________________
Column type frequency:
numeric 5
________________________
Group variables Classe

Variable type: numeric

skim_variable Classe n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
pH alta 0 1 6.50 0.29 6.0 6.3 6.50 6.70 7.0 ▆▅▇▅▃
pH media 0 1 6.53 0.75 5.5 5.8 7.10 7.20 7.4 ▅▂▁▁▇
pH baixa 0 1 6.46 1.57 3.6 5.1 6.50 7.88 8.9 ▂▇▁▅▆
MO alta 0 1 2.99 0.28 2.6 2.7 3.00 3.20 3.8 ▇▅▆▂▁
MO media 0 1 2.40 0.14 2.2 2.3 2.40 2.50 2.6 ▅▇▆▇▅
MO baixa 0 1 1.90 0.28 0.9 1.8 2.00 2.10 2.2 ▁▁▁▅▇
P alta 0 1 27.90 1.76 25.7 26.6 27.50 28.70 33.4 ▇▆▂▁▁
P media 0 1 24.59 0.79 23.2 23.9 24.60 25.40 25.7 ▅▅▅▃▇
P baixa 0 1 20.90 2.04 14.1 20.2 21.30 22.20 23.2 ▁▁▂▆▇
K alta 0 1 32.01 0.91 30.7 31.4 31.80 32.60 34.3 ▆▇▃▃▂
K media 0 1 30.08 0.41 29.4 29.7 30.10 30.50 30.7 ▆▅▃▆▇
K baixa 0 1 28.06 1.07 25.3 27.7 28.20 28.80 29.4 ▂▁▃▇▇
Arg alta 0 1 29.87 2.97 26.5 27.7 29.30 31.30 40.3 ▇▆▂▁▁
Arg media 0 1 24.51 1.07 22.9 23.7 24.50 25.30 26.5 ▇▇▆▆▅
Arg baixa 0 1 19.69 2.32 10.3 18.3 19.85 21.30 22.8 ▁▁▂▆▇

Outra forma de visualizar os dados é através de uma tabela de frequência.

Code
xtabs(~Classe, data = df)
Classe
 alta media baixa 
   81    61    58 

Vamos padronizar os dados.

Code
# Padronizando
df_p <- data.frame(scale(df[,1:5]), 
                   as.factor(df$Classe)) |> 
  rename(Classe = as.factor.df.Classe.)
summary(df_p)
       pH                 MO                 P                  K           
 Min.   :-3.04415   Min.   :-3.10779   Min.   :-3.24583   Min.   :-2.70948  
 1st Qu.:-0.62982   1st Qu.:-0.62273   1st Qu.:-0.65134   1st Qu.:-0.55867  
 Median : 0.05249   Median : 0.01072   Median : 0.07271   Median : 0.06752  
 Mean   : 0.00000   Mean   : 0.00000   Mean   : 0.00000   Mean   : 0.00000  
 3rd Qu.: 0.73479   3rd Qu.: 0.59544   3rd Qu.: 0.61574   3rd Qu.: 0.72093  
 Max.   : 2.51929   Max.   : 2.54451   Max.   : 2.57669   Max.   : 2.19111  
      Arg            Classe  
 Min.   :-3.1023   alta :81  
 1st Qu.:-0.6799   media:61  
 Median :-0.0381   baixa:58  
 Mean   : 0.0000             
 3rd Qu.: 0.6296             
 Max.   : 3.1089             

Observe que os valores foram padronizados, para média igual a zero e desvio padrão igual a 1.
A padronização dos dados é uma etapa fundamental em diversos processos de análise estatística, aprendizado de máquina e modelagem preditiva. Ela envolve transformar variáveis para que tenham uma escala comum, o que pode ser feito subtraindo a média e dividindo pelo desvio padrão, ou reescalando os valores para uma faixa específica, como [0, 1]. A padronização é particularmente importante em algoritmos que dependem de medições de distância ou variáveis com diferentes escalas.
Algoritmos que dependem de medições de distância, como KNN (K-vizinhos mais próximos) e clustering (K-means, por exemplo), podem ser severamente influenciados por variáveis com escalas maiores. Nesse caso, variáveis com valores numéricos maiores podem influenciar fortemente as distâncias calculadas, distorcendo os resultados. Padronizar os dados assegura que todas as variáveis tenham um impacto comparável nas medidas de distância.

Agora vamos dividir os dados em treino e teste.

Code
# Separando em treino e teste.
n <- nrow(df_p)
set.seed(134) # Para reprodutibilidade dos resultados.
i <- sample(x = c(TRUE, FALSE),
            size = n,
            replace = TRUE,
            prob = c(0.70, 1 - 0.70))

df_train <- df_p[i, ]
nrow(df_train)
[1] 139
Code
df_test <- df_p[!i, ]
nrow(df_test)
[1] 61

Vamos verificar a proporção de treino e teste.

Code
# Proporção treino e teste
round(c(nrow(df_train), 
        nrow(df_test))/n, 
      digits = 3)*100
[1] 69.5 30.5

Muito próximo de 70% para treino e 30% para teste.

Obtendo as predições para o conjunto de teste via conjunto de treino.

  • K = 3
Code
library(class)
m0 <- knn(train = df_train[, -6],
          test = df_test[, -6],
          cl = df_train[, 6],
          k = 3)

Avaliação do modelo

Code
# Tabela de confusão.
ct <- table(df_test[, 6], m0)
# Renomeando as linhas e colunas
rownames(ct) <- c("Alta_V", "Média_V", "Baixa_V")
colnames(ct) <- c("Alta_Prev", "Média_Prev", "Baixa_Prev")
ct
         m0
          Alta_Prev Média_Prev Baixa_Prev
  Alta_V         21          3          0
  Média_V         0         18          1
  Baixa_V         0          0         18
Code
# Conferindo a Tabela do teste
xtabs(~Classe, data = df_test)
Classe
 alta media baixa 
   24    19    18 

Visualizando os erros e acertos.

Code
library(gt)
# Juntando a base de teste com a previsão
df_comp <- cbind(df_test, Previssao = m0)
df_comp |> 
  gt()
pH MO P K Arg Classe Previssao
-0.5248530 2.15469678 2.18449952 1.97330252 2.48780137 alta alta
-0.4198824 1.76488280 1.70180387 1.64659681 1.80456697 alta alta
-0.4198824 1.56997581 1.61129843 1.59214585 1.68034254 alta alta
-0.4198824 1.56997581 1.58112995 1.59214585 1.68034254 alta alta
-0.4198824 1.56997581 1.46045604 1.59214585 1.59752625 alta alta
-0.4198824 1.56997581 1.46045604 1.59214585 1.59752625 alta alta
-0.2099412 1.37506882 1.33978213 1.37434204 1.28696516 alta alta
-0.2099412 1.37506882 1.30961365 1.31989109 1.26626108 alta alta
-0.2099412 1.37506882 1.15877126 1.26544014 1.24555701 alta alta
-0.1049706 1.18016183 1.06826582 1.15653823 1.07992443 alta alta
-0.1049706 1.18016183 1.00792886 0.99318538 0.99710814 alta alta
-0.1049706 1.18016183 0.97776038 0.93873442 0.99710814 alta alta
0.0000000 0.98525484 0.79674951 0.82983252 0.83147556 alta alta
0.1049706 0.79034785 0.70624408 0.82983252 0.72795520 alta alta
0.1049706 0.59544086 0.61573864 0.72093061 0.58302669 alta alta
0.1049706 0.59544086 0.58557017 0.66647966 0.56232261 alta alta
0.2099412 0.40053387 0.52523321 0.61202871 0.52091447 alta alta
0.2099412 0.40053387 0.49506473 0.55757775 0.47950632 alta alta
0.2099412 0.40053387 0.49506473 0.50312680 0.45880225 alta alta
0.3149118 0.40053387 0.43472777 0.39422490 0.43809818 alta alta
0.3149118 0.40053387 0.37439082 0.39422490 0.33457781 alta alta
0.5248530 0.20562688 0.28388538 0.28532299 0.27246560 alta media
0.5248530 0.20562688 0.28388538 0.28532299 0.27246560 alta media
0.5248530 0.20562688 0.25371690 0.23087204 0.25176152 alta media
0.5248530 0.20562688 0.25371690 0.23087204 0.25176152 media media
0.6298236 0.20562688 0.25371690 0.23087204 0.23105745 media media
0.7347942 0.01071988 0.19337995 0.12197013 0.08612894 media media
0.7347942 0.01071988 0.19337995 0.12197013 0.08612894 media media
0.7347942 0.01071988 0.16321147 0.12197013 0.04472080 media media
0.8397648 0.01071988 0.01236908 0.01306823 -0.07950364 media media
0.8397648 0.01071988 0.01236908 0.01306823 -0.12091178 media media
0.8397648 -0.18418711 -0.01779940 -0.04138272 -0.12091178 media media
-0.6298236 -0.18418711 -0.10830484 -0.15028463 -0.20372808 media media
-0.6298236 -0.18418711 -0.13847332 -0.15028463 -0.22443215 media media
-0.6298236 -0.37909410 -0.16864179 -0.15028463 -0.24513622 media media
-0.6298236 -0.37909410 -0.25914723 -0.20473558 -0.30724844 media media
-0.7347942 -0.37909410 -0.28931571 -0.25918653 -0.32795251 media media
-0.7347942 -0.37909410 -0.28931571 -0.25918653 -0.32795251 media media
-0.7347942 -0.37909410 -0.28931571 -0.31363749 -0.32795251 media media
-0.7347942 -0.37909410 -0.31948419 -0.31363749 -0.34865658 media media
-0.9447354 -0.57400109 -0.40998962 -0.42253939 -0.49358509 media media
-0.9447354 -0.57400109 -0.44015810 -0.47699034 -0.49358509 media media
-1.0497060 -0.57400109 -0.50049506 -0.47699034 -0.49358509 media baixa
-1.1546766 -0.57400109 -0.50049506 -0.47699034 -0.55569731 baixa baixa
-1.1546766 -0.57400109 -0.50049506 -0.53144130 -0.55569731 baixa baixa
-1.3646178 -0.76890808 -0.65133745 -0.64034320 -0.74203396 baixa baixa
-1.3646178 -0.76890808 -0.65133745 -0.64034320 -0.74203396 baixa baixa
-1.4695884 -0.76890808 -0.77201136 -0.69479415 -0.80414618 baixa baixa
-1.6795295 -0.76890808 -0.86251680 -0.85814701 -0.84555433 baixa baixa
-1.6795295 -0.76890808 -0.89268528 -0.91259797 -0.86625840 baixa baixa
-1.8894707 -0.76890808 -0.92285375 -0.91259797 -0.90766655 baixa baixa
-2.2043825 -0.96381507 -0.98319071 -1.02149987 -1.01118691 baixa baixa
1.0497060 -0.96381507 -1.07369615 -1.13040178 -1.13541135 baixa baixa
1.0497060 -1.15872206 -1.16420158 -1.23930368 -1.19752356 baixa baixa
1.2596472 -1.15872206 -1.16420158 -1.23930368 -1.25963578 baixa baixa
1.4695884 -1.35362905 -1.40554941 -1.40265654 -1.44597244 baixa baixa
1.4695884 -1.54853604 -1.52622332 -1.56600940 -1.44597244 baixa baixa
1.8894707 -1.74344303 -1.88824506 -1.94716606 -1.71512538 baixa baixa
2.0994119 -2.13325702 -1.88824506 -2.00161702 -1.77723760 baixa baixa
2.2043825 -2.32816401 -2.70279398 -2.60057750 -2.00498240 baixa baixa
2.5192943 -2.52307100 -2.79329941 -2.70947940 -2.08779869 baixa baixa

Acurácia do modelo.

Code
# Acurária = Fração de acertos totais.
A <- sum(diag(ct))/sum(ct)*100
paste0(round(A, 1), "%")
[1] "93.4%"

O modelo obteve uma acurácia de 93.4%, ou seja, acertou 57 de 61 observações da base de teste.

Comparar diferentes k’s

Vamos considerar o critério da Acuária para escolher o melhor valor de \(k\), fazendo o ajuste do modelo para diferentes valores de \(k\) e comparando a acurácia obtida.

Code
# 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(train = df_train[,-6], 
                      df_test[,-6], 
                      cl = df_train[,6], 
                      k)
acuracia[k] = sum(Knn_Testes[[k]]==df_test[,6])/length(df_test[,6])*100
}
acuracia
 [1] 96.72131 95.08197 93.44262 93.44262 93.44262 93.44262 93.44262 93.44262
 [9] 93.44262 95.08197 98.36066 96.72131 95.08197 95.08197 91.80328 96.72131
[17] 95.08197 95.08197 95.08197 95.08197

Verificando graficmente

Code
# Comparacao grafica das acuracias
# Criando um data frame com os dados de k e acuracia
dt <- data.frame(k = 1:k, acuracia = acuracia)

# Gerando o gráfico
dt |> 
      ggplot(aes(x = k,
                 y = acuracia)) +
  geom_line(color = "blue") +       # Linha azul
  geom_point(color = "blue", size = 3) +  # Pontos azuis
  labs(title = "Acurácia para cada k", 
       x = "k", 
       y = "Acurácia") +
  theme_minimal()

Observemos que a acurácia é maior para o valor de \(k = 11\). Portanto, o melhor valor de \(k\) para este problema é 11. Podemos então colocar o modelo definitivo com \(k = 11\) em produção.

Previsão da classe para novos valores

Vamos considerar um novo conjunto com cinco novas amostras de solo para prever a classe de qualidade de sementes esperada.

Code
# Novos valores
novos_valores <- data.frame(pH = c(4.2, 7.4, 5.7, 5.8, 6.9),
                            MO = c(1.5, 3.6, 2.7, 4.8, 3.9),
                            P = c(18.5, 13.6, 22.7, 18.8, 35.9),
                            K = c(26.5, 28.6, 26.7, 30.8, 37.9),
                            Arg = c(17.5, 20.6, 30.7, 40.8, 41.9))
novos_valores
   pH  MO    P    K  Arg
1 4.2 1.5 18.5 26.5 17.5
2 7.4 3.6 13.6 28.6 20.6
3 5.7 2.7 22.7 26.7 30.7
4 5.8 4.8 18.8 30.8 40.8
5 6.9 3.9 35.9 37.9 41.9

Com os valores estão em escalas diferentes é necessário a transformação de escala para uma padronizada. Vamos então escalonar os novos valores, para média igual a zero e desvio padrão igual a 1 em relação aos dados da base original.

Code
# calculando as médias e desvios padrão de cada variável
medias <- colMeans(df[,1:5])
desv_pad <- apply(df[,1:5], 2, sd)

# padronizando os novos valores em relação aos dados da base original
novos_valores_p <- scale(novos_valores, 
                         center = medias, 
                         scale = desv_pad)
novos_valores_p
             pH         MO          P         K        Arg
[1,] -2.4143237 -1.9383500 -1.9184135 -2.056068 -1.6116050
[2,]  0.9447354  2.1546968 -3.3966690 -0.912598 -0.9697788
[3,] -0.8397648  0.4005339 -0.6513374 -1.947166  1.1213326
[4,] -0.7347942  4.4935807 -1.8279081  0.285323  3.2124439
[5,]  0.4198824  2.7394178  3.3309017  4.151341  3.4401887
attr(,"scaled:center")
     pH      MO       P       K     Arg 
 6.5000  2.4945 24.8590 30.2760 25.2840 
attr(,"scaled:scale")
       pH        MO         P         K       Arg 
0.9526477 0.5130652 3.3147181 1.8365152 4.8299676 

Como valor do \(K\) já foi otimizado, vamos considerar o valor de \(k = 11\) para prever a classe dos novos valores. No entanto, podemos utilizar todos os dados disponíveis para treinar o modelo, já que o modelos já foi validado e o parâmetro \(K\) otimizado.

Utilizando o valor de \(k = 11\) para prever a classe dos novos valores.

Code
Knn_K11_Predicao = knn(train = df_p[,-6], 
                       test = novos_valores_p,
                       cl = df_p[, 6], 
                       k = 11)
Knn_K11_Predicao
[1] baixa baixa media alta  alta 
Levels: alta media baixa

Agora temos a previsão da classe para os novos valores.

Algoritmo de Classificação - KNN

Neste tutorial vamos dar ênfase no processo de valiação cruzada, utilizando as funções do pacote caret KUHN, M. The caret Package. 2019 para treinar modelos de classificação usando o algoritmo K-Nearest Neighbors (KNN).

O pacote contém ferramentas para:
* divisão de dados
* pré-processamento
* seleção de recursos
* ajuste de modelo usando reamostragem
* estimativa de importância variável
bem como outras funcionalidades.

Carregando pacotes necessários para a execução do código.

Code
library(tidyverse)
library(caret)
Carregando pacotes exigidos: lattice

Anexando pacote: 'caret'
O seguinte objeto é mascarado por 'package:purrr':

    lift
Code
library(readxl)

Limpando a memória do R

Code
rm(list = ls())

Carregando os dados

Code
# Classes de sementes de soja
df <- read_excel("soja.xlsx")
glimpse(df)
Rows: 200
Columns: 6
$ pH     <dbl> 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1…
$ MO     <dbl> 3.8, 3.6, 3.6, 3.5, 3.5, 3.5, 3.4, 3.4, 3.4, 3.3, 3.3, 3.3, 3.3…
$ P      <dbl> 33.4, 32.7, 32.1, 31.8, 31.4, 30.9, 30.5, 30.5, 30.4, 30.2, 30.…
$ K      <dbl> 34.3, 34.1, 33.9, 33.8, 33.6, 33.6, 33.4, 33.3, 33.3, 33.2, 33.…
$ Arg    <dbl> 40.3, 39.3, 37.3, 36.1, 35.9, 34.8, 34.2, 34.0, 33.7, 33.4, 33.…
$ Classe <chr> "alta", "alta", "alta", "alta", "alta", "alta", "alta", "alta",…
Code
# Transformar a classe em fator na sequêcia: Alta, Média e Baixa. 
df$Classe <- factor(df$Classe, 
                    levels = c("alta", "media", "baixa"))
df$Classe
  [1] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [13] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [25] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [37] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [49] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [61] alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta  alta 
 [73] alta  alta  alta  alta  alta  alta  alta  alta  alta  media media media
 [85] media media media media media media media media media media media media
 [97] media media media media media media media media media media media media
[109] media media media media media media media media media media media media
[121] media media media media media media media media media media media media
[133] media media media media media media media media media media baixa baixa
[145] baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa
[157] baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa
[169] baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa
[181] baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa baixa
[193] baixa baixa baixa baixa baixa baixa baixa baixa
Levels: alta media baixa

Exemplo 2: KNN com pacote {caret}

Vejamos outro exemplo de aplicação do KNN.

Vamos dividir os dados em treino e teste, para isso vamos utilizar o pacote {caret}, usando a função createDataPartition.

Code
set.seed(678)
treino <- createDataPartition(y = df$Classe,
                               p = 0.7,
                               list = FALSE)

df_treino <- df[treino, ]
df_teste <- df[-treino, ]

Vamos verificar a proporção de treino e teste em cada classe.

Code
# Proporções das classes no treino e teste.
rbind(treino = prop.table(xtabs(~Classe, df_treino))*100,
      teste = prop.table(xtabs(~Classe, df_teste))*100,
      base = prop.table(xtabs(~Classe, df))*100) |> 
      round(1) |> 
      print()
       alta media baixa
treino 40.4  30.5  29.1
teste  40.7  30.5  28.8
base   40.5  30.5  29.0

Validação Cruzada

Code
# Parametriza a validação cruzada com 10 folds
trctrl <- trainControl(method = "cv", 
                       number = 10)

Define-se os parâmetros para a validação cruzada, onde:
* method = "cv" indica o tipo de validação cruzada que será realizada.
* number = 10 indica que a validação cruzada será realizada com 10 folds. Isso significa que o conjunto de dados será dividido em 10 partes (ou folds) e o modelo será treinado 10 vezes, em cada uma delas usando 9 folds para treinamento e 1 fold para teste. No final, as métricas de desempenho do modelo são calculadas como a média dos resultados das 10 iterações.

Treinando o modelo

Code
set.seed(678)
knn_fit <- train(Classe ~ .,
                 data = df_treino,
                 method = "knn",
                 preProcess = c("center", "scale"), # normalização dos dados
                 trControl = trctrl,
                 metric = "Accuracy",
                 tuneLength = 15)

Usando a função train do pacote {caret} para treinar o modelo, onde:
* Classe ~ . indica que a variável resposta é Classe e as variáveis preditoras são todas as outras variáveis do conjunto de dados, (\(.\)) indica todas as demais.
* data = df_treino indica o conjunto de dados de treino.
* method = "knn" indica que o algoritmo a ser utilizado é o KNN. Valores possíveis são encontrados usando names(getModelInfo()).
* preProcess = c("center", "scale") indica que os dados serão normalizados.
* trControl = trctrl indica que a validação cruzada será realizada com 10 folds.
* metric = "Accuracy" indica que a métrica de avaliação será a acurácia.
* tuneLength = 15 indica que o modelo será treinado com 15 valores de k diferentes. O melhor valor de k será escolhido com base no desempenho. O pacote caret tentará automaticamente diferentes valores de k (no caso do K-NN) e selecionará o que resulta na melhor métrica de desempenho.

Avaliando o modelo

Code
# Gráfico do desempenho dos modelos testados
plot(knn_fit) |> print()

Nota-se que o modelo com k = 9 obteve o melhor desempenho.

Uma variação do metodo “cv” é o method = "repeatedcv", que permite realizar validação cruzada repetida, o que pode aumentar a robustez do modelo, repetindo a validação cruzada várias vezes.

Code
# Parametriza a validação cruzada com 10 folds e 5 repetições
trctrl <- trainControl(method = "repeatedcv", 
                       number = 10,
                       repeats = 5)

Treinando o modelo com repetição da validação cruzada

Code
set.seed(678)
knn_fit <- train(Classe ~ .,
                 data = df_treino,
                 method = "knn",
                 preProcess = c("center", "scale"), # normalização dos dados
                 trControl = trctrl,
                 metric = "Accuracy",
                 tuneLength = 15)

Isso realiza 10 folds de validação cruzada repetidos 5 vezes.

Avaliando o resultado do modelo

Code
print(knn_fit)
k-Nearest Neighbors 

141 samples
  5 predictor
  3 classes: 'alta', 'media', 'baixa' 

Pre-processing: centered (5), scaled (5) 
Resampling: Cross-Validated (10 fold, repeated 5 times) 
Summary of sample sizes: 126, 128, 127, 127, 126, 127, ... 
Resampling results across tuning parameters:

  k   Accuracy   Kappa    
   5  0.9826081  0.9736544
   7  0.9852601  0.9777430
   9  0.9797363  0.9693889
  11  0.9812601  0.9717025
  13  0.9725788  0.9582380
  15  0.9713407  0.9563901
  17  0.9660220  0.9477806
  19  0.9544542  0.9301976
  21  0.9587546  0.9370853
  23  0.9469817  0.9191544
  25  0.9468718  0.9192541
  27  0.9339853  0.8998631
  29  0.9184469  0.8761842
  31  0.8818462  0.8202297
  33  0.8370403  0.7501879

Accuracy was used to select the optimal model using the largest value.
The final value used for the model was k = 7.

Mostra o desempenho do modelo (Acurácia e Kappa) para diferentes valores de k. No exemplo, foram testados k = 5 até k = 33 variando de 2 em 2, onde o k = 7 obtendo a maior acurácia.

O modelo com k = 7 teve a maior Acurácia (98%), a Acurácia (Accuracy): Mede a porcentagem de previsões corretas (verdadeiras positivas + verdadeiras negativas) em relação ao total de previsões. Uma acurácia de 0.98 significa que o modelo classificou corretamente 98% dos exemplos. O k = 7 também apresentou o maior valor de Kappa (97%), o Kappa é uma métrica que corrige a acurácia levando em consideração as previsões corretas feitas ao acaso. Um valor de Kappa próximo de 1 indica que o modelo está muito acima do acaso, enquanto valores próximos de 0 indicam que ele não é muito melhor que uma classificação aleatória.

Avaliando o modelo

Code
# Gráfico do desempenho dos modelos testados
plot(knn_fit) |> print()

Nota-se que o modelo com k = 7 obteve o melhor desempenho.

A interpretação dos resultados de um modelo K-NN treinado com validação cruzada usando o pacote caret envolve analisar as métricas de desempenho que são fornecidas ao final do treinamento.

Dado que já treinamos e validamos o modelo, podemos agora fazer previsões nos dados de teste.

Predição nos dados deixados de fora (dados de Teste).

Code
m0 <- predict(knn_fit, 
              newdata = df_teste)

Matriz de confusão.

Code
confusionMatrix(m0, factor(df_teste$Classe)) |> print()
Confusion Matrix and Statistics

          Reference
Prediction alta media baixa
     alta    23     0     0
     media    1    17     0
     baixa    0     1    17

Overall Statistics
                                          
               Accuracy : 0.9661          
                 95% CI : (0.8829, 0.9959)
    No Information Rate : 0.4068          
    P-Value [Acc > NIR] : < 2.2e-16       
                                          
                  Kappa : 0.9487          
                                          
 Mcnemar's Test P-Value : NA              

Statistics by Class:

                     Class: alta Class: media Class: baixa
Sensitivity               0.9583       0.9444       1.0000
Specificity               1.0000       0.9756       0.9762
Pos Pred Value            1.0000       0.9444       0.9444
Neg Pred Value            0.9722       0.9756       1.0000
Prevalence                0.4068       0.3051       0.2881
Detection Rate            0.3898       0.2881       0.2881
Detection Prevalence      0.3898       0.3051       0.3051
Balanced Accuracy         0.9792       0.9600       0.9881

Ao utilizar a função confusionMatrix() do pacote {caret} para avaliar um modelo com a base de teste, você obterá várias métricas que são essenciais para entender o desempenho do seu classificador. A matriz de confusão é uma tabela que mostra o desempenho do modelo em termos de previsões corretas e incorretas.

Como interpretar as métricas:

Acurácia: 0,9661 de acurácia significa que o modelo classificou corretamente 96,6% dos exemplos no conjunto de teste.

Kappa: Um valor de 0.9487 para o Kappa indica que o modelo está 94,87% melhor do que uma classificação feita ao acaso.

Sensibilidade ou Recall: 0.9583 significa que 95,83% dos exemplos positivos foram corretamente identificados para a classe alta.

Especificidade: 1.0000 significa que 100% dos exemplos negativos foram corretamente identificados.

Essas métricas são úteis para avaliar o desempenho do modelo e identificar áreas onde o modelo pode estar falhando, como baixa sensibilidade ou alta taxa de falsos positivos. Isso ajuda a ajustar o modelo e melhorar seu desempenho geral.

Conclusão

Neste tutorial, aprendemos a usar a classificação K-Nearest Neighbors (KNN) com o R. Abordamos o conceito básico de KNN e como ele funciona. Em seguida, aplicamos o algoritmo KNN a um conjunto de dados de exemplo para classificar sementes de soja com base em suas características de solo.
Você precisa entender que o algoritmo KNN não é perfeito, ele também tem algumas desvantagens, e é preciso levar em conta vários aspectos antes de selecioná-lo como modelo principal.
Neste tutorial, aprendemos a usar o pacote {caret} para treinar modelos de classificação usando o algoritmo K-Nearest Neighbors (KNN). Destacamos também, a importância da validação cruzada para avaliar a capacidade de generalização do modelo.

Atividade de fixação

Atividade: Classificação de Espécies de Flores com K-Nearest Neighbors (KNN)
Objetivo: Utilizar a base de dados iris para construir um modelo de classificação que seja capaz de prever a espécie de uma flor com base em suas características morfológicas. O algoritmo KNN será utilizado como modelo preditivo.

Descrição da Atividade:

Exploração da Base de Dados:
* Carregar e inspecionar a base de dados iris para entender suas variáveis.
* Verificar a distribuição das variáveis numéricas (Sepal.Length, Sepal.Width, Petal.Length, Petal.Width) e analisar a variável alvo Species.
* Realizar visualizações, como gráficos de dispersão, para investigar a separabilidade das espécies com base nas características.

Divisão dos Dados em Conjunto de Treinamento e Teste

  • Dividir a base de dados em conjunto de treinamento (70%) e conjunto de teste (30%) de forma aleatória.
  • Verificar se as proporções das espécies são semelhantes nos conjuntos de treinamento e teste.

Normalização das Variáveis

  • Aplicar normalização (ou padronização) nas variáveis numéricas, pois o KNN é sensível a escalas diferentes.
  • Explicar por que essa etapa é importante no contexto do KNN.

Ajuste do Modelo KNN

  • Treinar o modelo KNN utilizando o conjunto de treinamento, ajustando o valor de k (número de vizinhos).
  • Testar diferentes valores de k e observar o impacto na acurácia do modelo. (Sugere-se testar ao menos os valores k = 3, k = 5, e k = 7).

Avaliação do Modelo

  • Avaliar o modelo com o conjunto de teste, utilizando métricas como acurácia, matriz de confusão e f1-score.
  • Discutir possíveis erros de classificação e como o valor de k afeta o desempenho do modelo.

Interpretação dos Resultados

Elabore um breve relatório em RMarkdown, incluindo as seguintes seções:
* Introdução: Contextualização do problema de classificação.
* Metodologia: Explicação sobre o algoritmo KNN e a importância da normalização.
* Resultados: Apresentação das métricas de desempenho, gráficos e tabelas relevantes.
* Discussão e Conclusão: Interpretação dos resultados e possíveis melhorias para o modelo.