Naive Bayes em variáveis ​​contínuas

8

Por favor, permita-me fazer uma pergunta básica. Entendo a mecânica de Naive Bayes para variáveis ​​discretas e posso refazer os cálculos "à mão". (código de HouseVotes84 todo o caminho abaixo).

No entanto - estou lutando para ver como a mecânica funciona para variáveis ​​contínuas (código de exemplo abaixo). Como o pacote calcula as probabilidades condicionais [, 1]e [, 2]na tabela abaixo? Como qualquer valor X individual é único, ele cria um intervalo em torno de cada ponto e calcula frequências relativas dentro desses intervalos (por exemplo, se o ponto for +0,311, avalia a incidência de manchas azuis e laranja em, por exemplo, um intervalo de 0,1 e +0,5?) Isso pode ser uma pergunta básica - desculpas se sim.

Mesa

A-priori probabilities:
Y
  blue orange 
   0.5    0.5 

Conditional probabilities:
        values
Y              [,1]      [,2]
  blue   0.08703793 0.9238799
  orange 1.33486433 0.9988389

Código

blue=rep("blue",50); orange=rep("orange",50); colour=c(blue,orange); values1=rnorm(50,0,1); values2=rnorm(50,1,1); values=c(values1,values2)
df=data.frame(colour,values)

(model <- naiveBayes(colour ~ ., data = df))
(predict(model, df[1:10,]))
(predict(model, df[1:10,], type = "raw"))
(pred <- predict(model, df))
table(pred, df$colour)

## Categorical data only:
library(e1071)
data(HouseVotes84, package = "mlbench")
HouseVotes84=HouseVotes84[,1:3]
(model <- naiveBayes(Class ~ ., data = HouseVotes84))
(predict(model, HouseVotes84[1:10,]))
(predict(model, HouseVotes84[1:10,], type = "raw"))
(pred <- predict(model, HouseVotes84))
table(pred, HouseVotes84$Class)
Wouter
fonte

Respostas:

5

No pacote R (e1071) e na função naiveBayes que você está usando:

O classificador Bayes ingênuo padrão (pelo menos essa implementação) assume independência das variáveis ​​preditivas e distribuição Gaussiana (dada a classe de destino) dos preditores métricos. Para atributos com valores ausentes, as entradas da tabela correspondentes são omitidas para previsão.

É bastante padrão para variáveis ​​contínuas em um Bayes ingênuo que uma distribuição normal seja considerada para essas variáveis ​​e uma média e desvio padrão possam ser calculados e, em seguida, usando alguns cálculos de tabela z padrão, as probabilidades podem ser estimadas para cada uma de suas variáveis ​​contínuas fazer o classificador ingênuo de Bayes. Eu pensei que era possível mudar a suposição distributiva neste pacote, mas aparentemente estou errado.

Há outro pacote R (klaR) onde você pode alterar o kernel de densidade. (a função é NaiveBayes). Do pacote:

NaiveBayes(x, grouping, prior, usekernel = FALSE, fL = 0, ...)

usekernel

se TRUE, uma estimativa de densidade de kernel (densidade) é usada para estimativa de densidade. Se FALSE, uma densidade normal é estimada.

density(x, bw = "nrd0", adjust = 1,
        kernel = c("gaussian", "epanechnikov", "rectangular",
                   "triangular", "biweight",
                   "cosine", "optcosine")
Eric Peterson
fonte
0

Eu estava trabalhando em um projeto não muito tempo atrás, para o qual eu precisava calcular um classificador ingênuo de bayes (do zero). Comecei no R, mas depois que o processo foi encerrado, mudei o código para Python. Aqui está o meu código que eu comecei. Não espere que seja polido. Na maioria das vezes, segui o exemplo da Wikipedia ( https://en.wikipedia.org/wiki/Naive_Bayes_classifier#Examples ).

Os passos são simples:

  1. calcular as probabilidades a priori, que são a proporção de classes

  2. Para seus dados contínuos, assuma uma distribuição normal e calcule a média e o desvio padrão.

  3. Para classificar as observações, pegue a nova entrada x, calcule de dnorm(x, mu, sigma)onde vem mu e sigma da etapa 2.

  4. Resumir log (a priori) + log (dnorm (...)).

Neste ponto, log(dnorm(...))deve conter dois valores de log (no meu exemplo). A probabilidade de pertencerem à classe 0 e a probabilidade de pertencerem à classe 1. Esse é o ponto que Eric Peterson destaca em seu segundo parágrafo.

  1. Calcular as probabilidades posteriores

Também comparei meus resultados com a biblioteca R e1071. Meus resultados de probabilidade não se alinham com os deles neste caso simples , embora a classificação o faça. Em sua predict.naiveBayesfunção, eles têm algo parecido com o log(apriori) + apply(log(sapply(...compute dnorm code here...)), 1, sum)que retorna, o log(apriori) + log(1) = log(apriori)que é um erro; portanto, sua classificação é baseada apenas nas probabilidades a priori (na verdade, eles usam contagens e não as probabilidades).

De qualquer forma, espero que isso ajude você (e qualquer outra pessoa) a ver o que há sob o capô, pois também não ficou claro para mim.

n=30 ## samples
set.seed(123)
x = c(rnorm(n/2, 10, 2), rnorm(n/2, 0, 2))
y = as.factor(c(rep(0, 20), rep(1, 10)))
y


#library(e1071)
#nb = naiveBayes(x, y, laplace = 0)
#nb

#nb_predictions = predict(nb, x[1], type='raw')
#nb_predictions



library(dplyr)

nbc <- function(x, y){
  df <- as.data.frame(cbind(x,y))
  a_priori <- table(y) #/length(y)

  cond_probs <- df %>% group_by(y) %>% summarise(means = mean(x), var = sd(x))

  print("A Priori Probabilities")
  print(a_priori/sum(a_priori))

  print("conditional probabilities \n")
  print(cond_probs)

  return(list(apriori = a_priori, tables = cond_probs))
}



predict_nbc <- function(model, new_x){
  apriori = as.matrix(model$apriori)
  a = log(apriori/sum(apriori))
  msd = as.matrix(model$tables)[,c(2,3)] ## creates 3 columsn; first is junk
  probs = sapply(new_x, function(v) dnorm(x = v, mean = msd[,1], sd = msd[,2]))
  b = log(probs)
  #L = a + b ## works for 1 new obs
  L = apply(X = b, MARGIN = 2, FUN = function(v) a + v)

  results <- apply(X = L, MARGIN = 2, function(x){
                   sapply(x, function(lp){ 1/sum(exp(x - lp)) }) ## numerically stable
  })
  return(results)
}



fit = nbc(x,y)

fit ## my naive bayes classifier model

myres = predict_nbc(fit, new_x = x[1:4])
myres
Jon
fonte