Bayes ingenuos en variables continuas

8

Permítame hacer una pregunta básica. Entiendo la mecánica de Naive Bayes para variables discretas, y puedo rehacer los cálculos "a mano". (código de HouseVotes84 hasta el final por debajo).

Sin embargo, me cuesta ver cómo funcionan los mecanismos para las variables continuas (código de ejemplo a continuación). ¿Cómo calcula el paquete las probabilidades condicionales [, 1]y [, 2]en la tabla a continuación? Como cualquier valor X individual es único, crea un rango alrededor de cada punto y calcula las frecuencias relativas dentro de estos rangos (por ejemplo, si el punto es +0.311, evalúa la incidencia de puntos azules y naranjas en, por ejemplo, un rango de 0.1 y +0.5?) Esta podría ser una pregunta básica: disculpas si es así.

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
fuente

Respuestas:

5

Desde el paquete R (e1071) y la función naiveBayes que está utilizando:

El clasificador ingenuo estándar de Bayes (al menos esta implementación) supone la independencia de las variables predictoras y la distribución gaussiana (dada la clase objetivo) de los predictores métricos. Para los atributos con valores perdidos, las entradas de la tabla correspondiente se omiten para la predicción.

Es bastante estándar para las variables continuas en un Bayes ingenuo que se considere una distribución normal para estas variables y luego se pueda calcular una media y una desviación estándar y luego se pueden estimar las probabilidades de cada una de sus variables continuas utilizando cada cálculo de la tabla z estándar. el ingenuo clasificador de Bayes. Pensé que era posible cambiar el supuesto de distribución en este paquete, pero aparentemente estoy equivocado.

Hay otro paquete R (klaR) donde puede cambiar el núcleo de densidad. (la función es NaiveBayes). Del paquete:

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

usekernel

si es VERDADERO, se usa una estimación de densidad del núcleo (densidad) para la estimación de la densidad. Si es FALSO, se estima una densidad normal.

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

Estaba trabajando en un proyecto no hace mucho tiempo para el que necesitaba calcular un ingenuo clasificador bayes (desde cero). Comencé en R, pero una vez que terminé el proceso, moví el código a Python. Aquí está mi código con el que comencé. No esperes que sea pulido. En su mayor parte, seguí el ejemplo de Wikipedia ( https://en.wikipedia.org/wiki/Naive_Bayes_classifier#Examples ).

Los pasos son simples:

  1. calcular las probabilidades a priori que son la proporción de clases

  2. Para sus datos continuos, suponga una distribución normal y calcule la media y la desviación estándar.

  3. Para clasificar las observaciones, tome la nueva entrada x, calcule de dnorm(x, mu, sigma)dónde provienen mu y sigma del paso 2.

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

En este punto, log(dnorm(...))debería contener dos valores de registro (en mi ejemplo). La probabilidad de que pertenezcan a la clase 0 y la probabilidad de que pertenezcan a la clase 1. Este es el punto que Eric Peterson hace en su segundo párrafo.

  1. Calcule las probabilidades posteriores

También comparé mis resultados con la biblioteca R e1071. Mis resultados de probabilidad no se alinean con los de ellos para este caso simple , aunque la clasificación sí. En su predict.naiveBayesfunción, tienen algo parecido a lo log(apriori) + apply(log(sapply(...compute dnorm code here...)), 1, sum)que devuelve, lo log(apriori) + log(1) = log(apriori)cual es un error, por lo que su clasificación se basa únicamente en las probabilidades a priori (en realidad, usan recuentos, no las probabilidades).

De todos modos, espero que esto te ayude (y a cualquier otra persona) a ver lo que hay debajo del capó, ya que tampoco estaba claro para mí.

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
fuente