Aplicação de Redes Neurais no R: Um Estudo com o Dataset Iris

Author

Gabriel Cardoso

Para começar, vamos considerar a perspectiva de Steven Pinker no livro Como a Mente Funciona, em que ele apresenta uma síntese interessante dos elementos envolvidos no pensamento e sua relação com a lógica para alcançar objetivos por meio de estratégias. Ele explica que “crenças são registros na memória, desejos são inscrições de objetivos, pensar é computação, percepções são inscrições ativadas por sensores, tentar é executar operações impulsionadas por um objetivo” (Pinker, Editora Schwarcz, 2018, p. 90).

Essa visão de que “pensar é computação” é especialmente relevante quando se trata da criação de redes neurais que tentam imitar o funcionamento do cérebro humano, algo que sempre me fascinou — e que, acredito, desperta curiosidade em muitos ao ouvir sobre inteligência artificial.

Este trabalho, como o título sugere, é uma introdução prática ao uso de redes neurais na linguagem e ambiente de programação R.

O R é uma ferramenta poderosa para manipulação de dados, cálculos estatísticos, e visualização gráfica. Reconhecido como uma das melhores plataformas para essas finalidades, ele conta com uma ampla gama de bibliotecas padrão, disponíveis na instalação do R-base, e outras criadas por contribuições externas, conhecidas como contributed packages, que estão disponíveis no repositório CRAN.

Para esta introdução ao uso de redes neurais, utilizaremos dois pacotes do CRAN. O primeiro é o caret, que oferece uma série de funções para treinamento e visualização de modelos de classificação e regressão. O segundo pacote, neuralnet, será usado para o treinamento da rede neural.

A seguir, detalhamos o fluxo que seguiremos para construir a rede neural. O primeiro passo será dividir os dados em conjuntos de treino e teste. Precisaremos também de uma base completa, com variáveis de entrada e uma saída esperada, que servirá como rótulo. A rede neural resultante será treinada para classificar três espécies da planta conhecida como “íris”.

1 DataSet Iris

O dataset “Iris” é amplamente utilizado para testar modelos clássicos de classificação, sendo uma referência básica nesse tipo de tarefa. Este conjunto de dados é baseado nas características de diferentes espécies da flor íris, e o objetivo é prever a qual das três espécies uma amostra pertence: Setosa, Versicolor ou Virginica.

O dataset contém 150 observações, divididas igualmente entre as três espécies mencionadas, com 50 amostras para cada uma delas. Essas amostras incluem medições específicas das flores, como comprimento e largura das pétalas e sépalas, que servirão como características para os modelos de classificação, conforme ilustrado na imagem abaixo.

De cada uma delas mediu-se quatro variáveis morfológicas: comprimento (Length) e largura (Width) da sépala e comprimento e largura da pétala. O objetivo original é quantificar a variação morfológica em relação a essas espécies com bases nas quatro variáveis de interesse.

head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

Para iniciar, copiaremos o dataset iris para uma variável interna, que chamaremos de dataset_iris. Como o dataset iris já faz parte do R e está disponível por padrão, não é necessário importá-lo de uma fonte externa. Basta copiá-lo para a nova variável, facilitando o manuseio durante o desenvolvimento do modelo.

dataset_iris = iris

Em seguida, criaremos três novas colunas em dataset_iris, que servirão como variáveis de saída para a rede neural, indicando a espécie da flor. Cada coluna será nomeada de acordo com uma das espécies (Setosa, Versicolor, e Virginica) e conterá valores lógicos (TRUE ou FALSE) para indicar se a amostra pertence ou não a cada espécie. Essas colunas serão utilizadas como saída no treinamento e nos testes da rede neural.

dataset_iris = cbind(dataset_iris,dataset_iris$Species=='setosa')
dataset_iris = cbind(dataset_iris,dataset_iris$Species=='versicolor')
dataset_iris = cbind(dataset_iris,dataset_iris$Species=='virginica')

names(dataset_iris)[6] <- 'setosa'
names(dataset_iris)[7] <- 'versicolor'
names(dataset_iris)[8] <- 'virginica'

head(dataset_iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species setosa versicolor
1          5.1         3.5          1.4         0.2  setosa   TRUE      FALSE
2          4.9         3.0          1.4         0.2  setosa   TRUE      FALSE
3          4.7         3.2          1.3         0.2  setosa   TRUE      FALSE
4          4.6         3.1          1.5         0.2  setosa   TRUE      FALSE
5          5.0         3.6          1.4         0.2  setosa   TRUE      FALSE
6          5.4         3.9          1.7         0.4  setosa   TRUE      FALSE
  virginica
1     FALSE
2     FALSE
3     FALSE
4     FALSE
5     FALSE
6     FALSE

Para o treinamento do modelo, vamos dividir nosso dataset em duas partes: 70% dos dados serão utilizados para treino (dataset_treino), e os 30% restantes serão reservados para testes (dataset_teste).

Observação: Caso o pacote caret ainda não esteja instalado no seu R, ele pode ser instalado com o comando install.packages("caret", dependencies = TRUE). Esse comando está comentado no código abaixo, caso precise executá-lo.

library(caret)
particao = createDataPartition(1:dim(dataset_iris)[1],p=.7)
dataset_treino = dataset_iris[particao$Resample1,]
dataset_teste = dataset_iris[- particao$Resample1,]

2 Criação da rede neural

Observação: Caso o pacote neuralnet ainda não esteja instalado no seu R, ele pode ser adicionado com o comando install.packages("neuralnet"). Esse comando está comentado no código abaixo para uso, se necessário.

library(neuralnet)
modelo = neuralnet( setosa  + versicolor  +  virginica  ~ Sepal.Length + Sepal.Width +  Petal.Length + Petal.Width , dataset_treino, hidden=c(5,4), act.fct = "logistic")

Função de Ativação - Função Logística: A função logística é usada para transformar a saída de um neurônio, ajustando-a para que o sinal possa ser transmitido para a próxima camada da rede.

\[ f(x) = \frac{1}{1+e^{-x}} \]

2.1 Função logística

logistica <- function(z) {
    
    1 / (1 + exp(-z))
}

Gráfico da Função logística

x <- c(-10:10)
plot(x, logistica(x), type = "l", col = "orange")

2.2 Plotagem da rede neural criada

plot(modelo, rep="best")

Para realizar os testes da rede neural, vamos utilizar apenas o registro de índice [25] da base de testes (dataset_teste). A visualização completa da base de teste está comentada; caso queira examinar todos os dados, basta descomentar essa linha.

dataset_teste[25,1:5]
   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
96          5.7           3          4.2         1.2 versicolor
teste = compute(modelo,dataset_teste[25,1:4])

resultado = as.data.frame(teste$net.result)

2.3 Tratando o resultado do teste para exibir no nome da flor

names(resultado)[1] <- 'setosa'
names(resultado)[2] <- 'versicolor'
names(resultado)[3] <- 'virginica'

resultado$class = colnames(resultado[,1:3])[max.col(resultado[,1:3], ties.method = 'first')]

resultado$class
[1] "versicolor"

2.4 Realizando teste com toda a base de teste [dataset_teste]. E exibindo a matriz de confusão e seu percentual de acerto no teste.

teste = compute(modelo,dataset_teste[,1:4])

resultado = as.data.frame(teste$net.result)

names(resultado)[1] <- 'setosa'
names(resultado)[2] <- 'versicolor'
names(resultado)[3] <- 'virginica'

resultado$class = colnames(resultado[,1:3])[max.col(resultado[,1:3], ties.method = 'first')]

confusao = table(resultado$class,dataset_teste$Species)

confusao
            
             setosa versicolor virginica
  setosa         15          0         0
  versicolor      0          9         0
  virginica       0          2        18

Percentual de acertos: 95,45%.