Naive Gaussian Bayes, explicado: una guía visual con ejemplos de código para principiantes | de Samy Baladram | octubre 2024

Naive Gaussian Bayes, explicado: una guía visual con ejemplos de código para principiantes | de Samy Baladram | octubre 2024

ALGORITMO DE CLASIFICACIÓN

Supuestos en forma de campana para mejores predicciones

⛳️ More CLASSIFICATION ALGORITHM, explained:
· Dummy Classifier
· K Nearest Neighbor Classifier
· Bernoulli Naive Bayes
▶ Gaussian Naive Bayes
· Decision Tree Classifier
· Logistic Regression
· Support Vector Classifier
· Multilayer Perceptron (soon!)

Basándonos en nuestro artículo anterior sobre Bernoulli Naive Bayes, que maneja datos binarios, ahora exploramos Gaussian Naive Bayes para datos continuos. A diferencia del enfoque binario, este algoritmo supone que cada característica sigue una distribución normal (gaussiana).

Aquí veremos cómo el ingenuo Bayes gaussiano maneja datos continuos en forma de campana, lo que da como resultado predicciones precisas. sin entrar en cálculos complejos del teorema de Bayes.

Todas las imágenes: creadas por el autor usando Canva Pro. Optimizado para dispositivos móviles; Puede parecer de gran tamaño en el escritorio.

Al igual que otras variantes de Naive Bayes, Gaussian Naive Bayes asume la suposición «ingenua» de independencia de características. Se supone que las características son condicionalmente independientes dada la etiqueta de clase.

Sin embargo, mientras Bernoulli Naive Bayes es adecuado para conjuntos de datos con características binarias, Gaussian Naive Bayes supone que las características siguen una normal continua (gaussiana) distribución. Aunque esta suposición no siempre es cierta en la realidad, simplifica los cálculos y a menudo conduce a resultados sorprendentemente precisos.

Bernoulli NB asume datos binarios, Multinomial NB trabaja con recuentos discretos y Gaussian NB maneja datos continuos asumiendo una distribución normal.

A lo largo de este artículo, utilizaremos este conjunto de datos de golf artificial (creado por el autor) como ejemplo. Este conjunto de datos predice si una persona jugará golf en función de las condiciones climáticas.

Columnas: «Cantidad de lluvia» (en mm), «Temperatura» (en grados Celsius), «Humedad» (en %), «Velocidad del viento» (en km/h) y «Reproducción» (Sí/No, característica del objetivo)
# IMPORTING DATASET #
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd
import numpy as np

dataset_dict = {
'Rainfall': [0.0, 2.0, 7.0, 18.0, 3.0, 3.0, 0.0, 1.0, 0.0, 25.0, 0.0, 18.0, 9.0, 5.0, 0.0, 1.0, 7.0, 0.0, 0.0, 7.0, 5.0, 3.0, 0.0, 2.0, 0.0, 8.0, 4.0, 4.0],
'Temperature': [29.4, 26.7, 28.3, 21.1, 20.0, 18.3, 17.8, 22.2, 20.6, 23.9, 23.9, 22.2, 27.2, 21.7, 27.2, 23.3, 24.4, 25.6, 27.8, 19.4, 29.4, 22.8, 31.1, 25.0, 26.1, 26.7, 18.9, 28.9],
'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0, 90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0, 65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
'WindSpeed': [2.1, 21.2, 1.5, 3.3, 2.0, 17.4, 14.9, 6.9, 2.7, 1.6, 30.3, 10.9, 3.0, 7.5, 10.3, 3.0, 3.9, 21.9, 2.6, 17.3, 9.6, 1.9, 16.0, 4.6, 3.2, 8.3, 3.2, 2.2],
'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}
df = pd.DataFrame(dataset_dict)

# Set feature matrix X and target vector y
X, y = df.drop(columns='Play'), df['Play']

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)
print(pd.concat([X_train, y_train], axis=1), end='\n\n')
print(pd.concat([X_test, y_test], axis=1))

Gaussian Naive Bayes trabaja con datos continuos, asumiendo que cada característica sigue una distribución gaussiana (normal).

  1. Calcule la probabilidad de cada clase en los datos de entrenamiento.
  2. Para cada característica y clase, estime la media y la varianza de los valores de las características dentro de esa clase.
  3. Para una nueva instancia:
    A. Para cada clase, calcule la función de densidad de probabilidad (PDF) de cada valor de característica bajo la distribución gaussiana de esa característica dentro de la clase.
    b. Multiplique la probabilidad de clase por el producto de los valores de PDF para todas las características.
  4. Predice la clase con la probabilidad resultante más alta.
Gaussian Naive Bayes utiliza la distribución normal para modelar la probabilidad de diferentes valores de características para cada clase. Luego combina estas probabilidades para hacer una predicción.

Transformación de datos distribuidos no gaussianos.

¿Recuerda que este algoritmo supone ingenuamente que todas las características de entrada tienen una distribución gaussiana/normal?

Dado que no estamos realmente seguros de la distribución de nuestros datos, especialmente para características que claramente no siguen una distribución gaussiana, puede ser beneficioso aplicar una transformación de potencia (como Box-Cox) antes de usar Bayes ingenuo gaussiano. Este enfoque puede ayudar a que los datos sean más gaussianos, lo que se ajusta mejor a las suposiciones del algoritmo.

Todas las columnas se escalan mediante transformación de potencia (transformación Box-Cox) y luego se estandarizan.
from sklearn.preprocessing import PowerTransformer

# Initialize and fit the PowerTransformer
pt = PowerTransformer(standardize=True) # Standard Scaling already included
X_train_transformed = pt.fit_transform(X_train)
X_test_transformed = pt.transform(X_test)

Ahora estamos listos para entrenar.

1. Cálculo de probabilidad de clase: Para cada clase, calcule su probabilidad: (Número de instancias en esta clase) / (Número total de instancias)

from fractions import Fraction

def calc_target_prob(attr):
total_counts = attr.value_counts().sum()
prob_series = attr.value_counts().apply(lambda x: Fraction(x, total_counts).limit_denominator())
return prob_series

print(calc_target_prob(y_train))

2. Cálculo de probabilidad de características : Para cada característica y cada clase, calcule la media (μ) y la desviación estándar (σ) de los valores de las características dentro de esa clase utilizando los datos de entrenamiento. A continuación, calcule la probabilidad utilizando la fórmula de la función de densidad de probabilidad gaussiana (PDF).

Para cada condición climática, determine la media y la desviación estándar para los casos «SÍ» y «NO». Luego calcule su PDF usando la fórmula PDF para la distribución normal/gaussiana.
El mismo proceso se aplica a todas las demás funciones.
def calculate_class_probabilities(X_train_transformed, y_train, feature_names):
classes = y_train.unique()
equations = pd.DataFrame(index=classes, columns=feature_names)

for cls in classes:
X_class = X_train_transformed[y_train == cls]
mean = X_class.mean(axis=0)
std = X_class.std(axis=0)
k1 = 1 / (std * np.sqrt(2 * np.pi))
k2 = 2 * (std ** 2)

for i, column in enumerate(feature_names):
equation = f"{k1[i]:.3f}·exp(-(x-({mean[i]:.2f}))²/{k2[i]:.3f})"
equations.loc[cls, column] = equation

return equations

# Use the function with the transformed training data
equation_table = calculate_class_probabilities(X_train_transformed, y_train, X.columns)

# Display the equation table
print(equation_table)

3. Suavizado: Gaussian Naive Bayes utiliza un enfoque de suavizado único. A diferencia del suavizado de Laplace en otras variaciones, agrega un valor pequeño (0,000000001 veces la varianza más grande) a todas las varianzas. Esto evita la inestabilidad numérica debido a la división por cero o números muy pequeños.

Dada una nueva instancia con funcionalidad continua:

1. Colección de probabilidad:
Para cada clase posible:
· Comience con la probabilidad de que ocurra esta clase (probabilidad de clase).
· Para cada característica en la nueva instancia, calcule la función de densidad de probabilidad de esa característica dentro de la clase.

Para ID 14, calculamos el PDF de cada característica para las instancias «SÍ» y «NO».

2. Cálculo y predicción de puntuaciones.:
Para cada clase:
· Multiplica todos los valores PDF recopilados juntos.
· El resultado es la puntuación de esa clase.
· La clase con mayor puntuación es predicción.

from scipy.stats import norm

def calculate_class_probability_products(X_train_transformed, y_train, X_new, feature_names, target_name):
classes = y_train.unique()
n_features = X_train_transformed.shape[1]

# Create column names using actual feature names
column_names = [target_name] + list(feature_names) + ['Product']

probability_products = pd.DataFrame(index=classes, columns=column_names)

for cls in classes:
X_class = X_train_transformed[y_train == cls]
mean = X_class.mean(axis=0)
std = X_class.std(axis=0)

prior_prob = np.mean(y_train == cls)
probability_products.loc[cls, target_name] = prior_prob

feature_probs = []
for i, feature in enumerate(feature_names):
prob = norm.pdf(X_new[0, i], mean[i], std[i])
probability_products.loc[cls, feature] = prob
feature_probs.append(prob)

product = prior_prob * np.prod(feature_probs)
probability_products.loc[cls, 'Product'] = product

return probability_products

# Assuming X_new is your new sample reshaped to (1, n_features)
X_new = np.array([-1.28, 1.115, 0.84, 0.68]).reshape(1, -1)

# Calculate probability products
prob_products = calculate_class_probability_products(X_train_transformed, y_train, X_new, X.columns, y.name)

# Display the probability product table
print(prob_products)

Para este conjunto de datos en particular, esta precisión se considera bastante buena.
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score

# Initialize and train the Gaussian Naive Bayes model
gnb = GaussianNB()
gnb.fit(X_train_transformed, y_train)

# Make predictions on the test set
y_pred = gnb.predict(X_test_transformed)

# Calculate the accuracy
accuracy = accuracy_score(y_test, y_pred)

# Print the accuracy
print(f"Accuracy: {accuracy:.4f}")

GaussianNB es conocido por su simplicidad y eficiencia. Lo principal que debe recordar sobre su configuración es:

  1. antecedentes: Este es el parámetro más notable, similar a Bernoulli Naive Bayes. En la mayoría de los casos, no es necesario configurarlo manualmente. De forma predeterminada, se calcula a partir de los datos de tu entrenamiento, lo que suele funcionar bien.
  2. var_smoothing: Esta es una configuración de estabilidad que rara vez es necesario ajustar. (el valor predeterminado es 0,000000001)

La conclusión es que este algoritmo está diseñado para funcionar de inmediato. En la mayoría de situaciones, puedes usarlo sin preocuparte por ajustar la configuración.

Beneficios :

  1. Sencillez: Mantiene el rasgo fácil de implementar y comprender.
  2. Eficiencia: Sigue siendo rápido en términos de entrenamiento y predicción, lo que lo hace adecuado para aplicaciones a gran escala con funcionalidad continua.
  3. Flexibilidad con datos: Maneja bien conjuntos de datos pequeños y grandes, adaptándose a la escala del problema en cuestión.
  4. Gestión continua de funciones: Prospera con características continuas y de valor real, lo que lo hace ideal para tareas como predecir resultados de valor real o trabajar con datos que varían en características en un continuo.

Desventajas:

  1. Hipótesis de independencia: Siempre supone que las características son condicionalmente independientes dada la clase, lo que podría no ser válido en todos los escenarios del mundo real.
  2. Supuesto de distribución gaussiana: Funciona mejor cuando los valores de las características siguen realmente una distribución normal. Las distribuciones no normales pueden conducir a un rendimiento subóptimo (pero se pueden corregir con la transformación de potencia que comentamos)
  3. Sensibilidad a los valores atípicos: Puede verse afectado significativamente por valores atípicos en los datos de entrenamiento, ya que distorsionan los cálculos de media y varianza.

Gaussian Naive Bayes se presenta como un clasificador eficaz para una amplia gama de aplicaciones que involucran datos continuos. Su capacidad para manejar características de valor real extiende su uso más allá de las tareas de clasificación binaria, lo que la convierte en una opción convincente para muchas aplicaciones.

Aunque hace ciertas suposiciones sobre los datos (independencia de características y distribución normal), cuando se cumplen estas condiciones, ofrece un rendimiento sólido, lo que lo convierte en el favorito tanto entre los principiantes como entre los científicos de datos experimentados por su equilibrio entre simplicidad y potencia.

import pandas as pd
from sklearn.naive_bayes import GaussianNB
from sklearn.preprocessing import PowerTransformer
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

# Load the dataset
dataset_dict = {
'Rainfall': [0.0, 2.0, 7.0, 18.0, 3.0, 3.0, 0.0, 1.0, 0.0, 25.0, 0.0, 18.0, 9.0, 5.0, 0.0, 1.0, 7.0, 0.0, 0.0, 7.0, 5.0, 3.0, 0.0, 2.0, 0.0, 8.0, 4.0, 4.0],
'Temperature': [29.4, 26.7, 28.3, 21.1, 20.0, 18.3, 17.8, 22.2, 20.6, 23.9, 23.9, 22.2, 27.2, 21.7, 27.2, 23.3, 24.4, 25.6, 27.8, 19.4, 29.4, 22.8, 31.1, 25.0, 26.1, 26.7, 18.9, 28.9],
'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0, 90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0, 65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
'WindSpeed': [2.1, 21.2, 1.5, 3.3, 2.0, 17.4, 14.9, 6.9, 2.7, 1.6, 30.3, 10.9, 3.0, 7.5, 10.3, 3.0, 3.9, 21.9, 2.6, 17.3, 9.6, 1.9, 16.0, 4.6, 3.2, 8.3, 3.2, 2.2],
'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}

df = pd.DataFrame(dataset_dict)

# Prepare data for model
X, y = df.drop('Play', axis=1), (df['Play'] == 'Yes').astype(int)

# Split data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, shuffle=False)

# Apply PowerTransformer
pt = PowerTransformer(standardize=True)
X_train_transformed = pt.fit_transform(X_train)
X_test_transformed = pt.transform(X_test)

# Train the model
nb_clf = GaussianNB()
nb_clf.fit(X_train_transformed, y_train)

# Make predictions
y_pred = nb_clf.predict(X_test_transformed)

# Check accuracy
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.4f}")