library(ggplot2)
library(tidyverse)
library(DT)
library(patchwork)
library(naivebayes)
library(caret)
O algoritmo Naive Bayes é um classificador probabilístico baseado no teorema de Bayes, que é utilizado para resolver problemas de classificação. O algoritmo é chamado de “naive” (ingênuo) porque ele assume que as variáveis preditoras são independentes, o que nem sempre é verdade. Apesar disso, o algoritmo é muito utilizado em problemas de classificação de texto, como análise de sentimentos e classificação de documentos.
O teorema de Bayes é uma fórmula que descreve a probabilidade de um evento, baseado em conhecimento prévio que pode estar relacionado ao evento. A fórmula é dada por:
\[
P\left(A \mid B\right) = \frac{P\left(B \mid A\right) \cdot
P\left(A\right)}{P\left(B\right)}
\]
seja \(x_i\) o conjunto de variáveis preditoras e \(y_j\) a variável resposta, de modo que \(y\) pertença a uma classe, resumindo: \(y_j \in \{y_1, y_2, \ldots, y_c\}\), onde \(c\) é o número de classes. Da fórmula de Bayes, temos que:
\[ P\left(y_j \mid \mathbf{x_i}\right) = \frac{ P\left(\mathbf{x_i} \mid y_j\right)\cdot P\left(y_j\right) }{P\left(\mathbf{x_i}\right)} \] Obserque o numerador da equação acima é a probabilidade conjunta de \(x_i\) e \(y_j\), então podemos reescrever o numerador da equação acima como: \[ \begin{aligned} P\left({x_i} \mid y_j\right) P\left(y_j\right) & =P\left({x_i}, y_j\right) \\ & =P\left(x_1, x_2, \ldots, x_p, y_j\right) \\ & =P\left(x_1 \mid x_2, x_3, \ldots, x_{\mathbf{p}}, y_{\dot{j}}\right) P\left(x_2, x_3, \ldots, x_p, y_j\right) \text { porque } P(a, b)=P(a \mid b) P(b) \\ & =P\left(x_1 \mid x_2, x_3, \ldots, x_{\mathbf{p}}, y_{\dot{j}}\right) P\left(x_2 \mid x_3, x_4, \ldots, x_p, y_j\right) P\left(x_3, x_4, \ldots, x_p, y_j\right) \\ & =P\left(x_1 \mid x_2, x_3, \ldots, x_p, y_j\right) P\left(x_2 \mid x_3, x_4, \ldots, x_p, y_j\right) \cdots P\left(x_p \mid y_j\right) P\left(y_j\right) \end{aligned} \] Assumindo que as variáveis preditoras \((x_i)\) são independentes, temos que \(P(x_1|x_2,x_3,...,x_p,y_j) = P(x_1|y_j)\). Assumir que as variáveis preditoras são independentes é uma simplificação, por isso o algoritmo é chamado de “naive” (ingênuo), na maioria dos casos as variáveis preditoras não são independentes, mas o algoritmo ainda é eficaz em muitos casos. Sendo assim a probabilidade conjunta de \(x\) e \(y_j\) é:
\[ P(x|y_j)P(y_j) = P(x_1|y_j)P(x_2|y_j)P(x_3|y_j)...P(x_p|y_j)P(y_j) \\ = \prod_{k=1}^{p} P(x_k|y_j)P(y_j) \] Substituindo o numerador da equação de Bayes, temos: \[ P(y_j | {x}) = \frac{ \prod_{k=1}^p P(x_k | y_j)P(y_j)}{P(x)} \] Perceba que o denominador da equação acima é constante para todas as classes.
Por fim temos o nosso classificador de Naive Bayes (classificador ingênuo de Bayes):
\[ \hat{y} = \arg \max_{y_j} \prod_{k=1}^p P(x_k | y_j)P(y_j) \] Quando temos interesse em classificar um novo dado, calculamos a probabilidade de cada classe e escolhemos a classe com maior probabilidade, essa regra é chamada de Máxima a Posteriori (MAP), onde a classe com a maior probabilidade é chamada de classe máxima a posteriori.
O conjunto de dados iris é um conjunto de dados clássico que contém informações sobre 150 flores de íris, sendo 50 flores de cada uma das três espécies de íris (setosa, versicolor e virginica). O conjunto de dados contém quatro variáveis preditoras (comprimento da sépala, largura da sépala, comprimento da pétala e largura da pétala) e uma variável resposta (espécie da íris).
Dados<-iris
datatable(Dados,
class = "row-border hover",
options = list(
scrollX = TRUE,
dom = 'ltipr'
))
Como o conjunto de dados possui 4 variáveis, podemos fazer 2 biplots para visualizar os dados. O primeiro biplot apresenta o comprimento e largura da sépala e o segundo biplot apresenta o comprimento e largura da pétala, de maneira que as espécies de flores são representadas por cores diferentes.
G1<-ggplot(Dados, aes(x = Sepal.Length, y = Sepal.Width, color = Species))+
geom_point(size = 2)+
scale_color_manual(values=c("#cd201f", "#1b6ca8","#3aaf85"))+
theme_light()+
labs(x = "Comprimento da Sépala", y = "Largura da Sépala", color = "Espécies")
G2<-ggplot(Dados, aes(x = Petal.Length, y = Petal.Width, color = Species))+
geom_point(size = 2)+
scale_color_manual(values=c("#cd201f", "#1b6ca8","#3aaf85"))+
theme_light()+
labs(x = "Comprimento da Pétala", y = "Largura da Pétala", color = "Espécies")
G1+G2
A função a seguir divide o conjunto de dados em um conjunto de treinamento (70% dos dados) e um conjunto de teste (30% dos dados).
treino <- iris$Species %>%
createDataPartition(p = 0.7, list = F)
train <- iris[treino, ]
test <- iris[-treino, ]
Como a saída da função naive_bayes é bem grande, ela
basicamente solta uma tabela para cada variável independente para cada
classe, então para facilitar a visualização, irei plotar os gráficos de
densidade para cada variável independente com cada classe de espécie de
uma cor diferente, que é basicamente o que as tabelas iriam tentar
representar.
modelo <- naive_bayes(Species ~ ., data = train, usekernel = T)
G3<-ggplot(Dados,aes(x= Sepal.Length, group = Species))+
geom_density(aes(fill = Species), alpha = 0.75)+
theme_light()+
scale_fill_manual(values=c("#cd201f", "#1b6ca8","#3aaf85"))+
labs(x = "Comprimento da Sépala", y = "Densidade", fill = "")+
theme(legend.position = "bottom")
G4<-ggplot(Dados,aes(x= Sepal.Width, group = Species))+
geom_density(aes(fill = Species), alpha = 0.75)+
theme_light()+
scale_fill_manual(values=c("#cd201f", "#1b6ca8","#3aaf85"))+
labs(x = "Largura da Sépala", y = "Densidade", fill = "")+
theme(legend.position = "bottom")
G3+G4
G5<-ggplot(Dados,aes(x= Petal.Length, group = Species))+
geom_density(aes(fill = Species), alpha = 0.75)+
theme_light()+
scale_fill_manual(values=c("#cd201f", "#1b6ca8","#3aaf85"))+
labs(x = "Comprimento da Pétala", y = "Densidade", fill = "")+
theme(legend.position = "bottom")
G6<-ggplot(Dados,aes(x= Petal.Width, group = Species))+
geom_density(aes(fill = Species), alpha = 0.75)+
theme_light()+
scale_fill_manual(values=c("#cd201f", "#1b6ca8","#3aaf85"))+
labs(x = "Largura da Pétala", y = "Densidade", fill = "")+
theme(legend.position = "bottom")
G5+G6
Testando o modelo com o conjunto de teste.
pred <- predict(modelo, test)
confusionMatrix(pred, test$Species)
## Confusion Matrix and Statistics
##
## Reference
## Prediction setosa versicolor virginica
## setosa 15 0 0
## versicolor 0 14 1
## virginica 0 1 14
##
## Overall Statistics
##
## Accuracy : 0.956
## 95% CI : (0.849, 0.995)
## No Information Rate : 0.333
## P-Value [Acc > NIR] : <2e-16
##
## Kappa : 0.933
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: setosa Class: versicolor Class: virginica
## Sensitivity 1.000 0.933 0.933
## Specificity 1.000 0.967 0.967
## Pos Pred Value 1.000 0.933 0.933
## Neg Pred Value 1.000 0.967 0.967
## Prevalence 0.333 0.333 0.333
## Detection Rate 0.333 0.311 0.311
## Detection Prevalence 0.333 0.333 0.333
## Balanced Accuracy 1.000 0.950 0.950
O algoritmo teve uma precisão de 97.8% no conjunto de teste, o que é um resultado muito bom e também teve a mesma precisão que o algoritmo de KNN, que é outro algoritmo de classificação muito utilizado.