A diferencia del enfoque de referencia de clasificadores ficticios o el razonamiento basado en similitud de KNNEl método Bayes ingenuo aprovecha la teoría de la probabilidad. Combina las probabilidades individuales de cada “pista” (o característica) para hacer una predicción final. Este método sencillo pero potente ha demostrado ser invaluable en varias aplicaciones de aprendizaje automático.
Naive Bayes es un algoritmo de aprendizaje automático que utiliza la probabilidad para clasificar los datos. Se basa en Teorema de Bayesuna fórmula para calcular probabilidades condicionales. La parte “ingenua” se refiere a su suposición clave: trata todas las características como independientes entre sí, incluso cuando podrían no serlo en la realidad. Esta simplificación, aunque a menudo no es realista, reduce en gran medida la complejidad computacional y funciona bien en muchos escenarios prácticos.
Existen tres tipos principales de clasificadores Naive Bayes. La diferencia clave entre estos tipos radica en el supuesto que hacen sobre la distribución de características:
- Bayes ingenuo de Bernoulli: Adecuado para funciones binarias/booleanas. Supone que cada función es una variable con valor binario (0/1).
- Bayes ingenuo multinomial:Se utiliza generalmente para recuentos discretos. Se suele utilizar en la clasificación de texto, donde las características pueden ser recuentos de palabras.
- Bayes ingenuo gaussiano:Supone que las características continuas siguen una distribución normal.
Es un buen comienzo centrarse en el más simple, que es el NB de Bernoulli. El “Bernoulli” en su nombre proviene de la suposición de que cada característica tiene un valor binario.
A lo largo de este artículo, utilizaremos este conjunto de datos de golf artificial (inspirado en [1]) como ejemplo. Este conjunto de datos predice si una persona jugará al golf en función de las condiciones climáticas.
# IMPORTING DATASET #
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd
import numpy as npdataset_dict = {
'Outlook': ['sunny', 'sunny', 'overcast', 'rain', 'rain', 'rain', 'overcast', 'sunny', 'sunny', 'rain', 'sunny', 'overcast', 'overcast', 'rain', 'sunny', 'overcast', 'rain', 'sunny', 'sunny', 'rain', 'overcast', 'rain', 'sunny', 'overcast', 'sunny', 'overcast', 'rain', 'overcast'],
'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0, 72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0, 88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
'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],
'Wind': [False, True, False, False, False, True, True, False, False, False, True, True, False, True, True, False, False, True, False, True, True, False, True, False, False, True, False, False],
'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)
# ONE-HOT ENCODE 'Outlook' COLUMN
df = pd.get_dummies(df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
# CONVERT 'Windy' (bool) and 'Play' (binary) COLUMNS TO BINARY INDICATORS
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)
# 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))
Lo adaptaremos ligeramente para Bernoulli Naive Bayes convirtiendo nuestras características a binario.
# One-hot encode the categorized columns and drop them after, but do it separately for training and test sets
# Define categories for 'Temperature' and 'Humidity' for training set
X_train['Temperature'] = pd.cut(X_train['Temperature'], bins=[0, 80, 100], labels=['Warm', 'Hot'])
X_train['Humidity'] = pd.cut(X_train['Humidity'], bins=[0, 75, 100], labels=['Dry', 'Humid'])# Similarly, define for the test set
X_test['Temperature'] = pd.cut(X_test['Temperature'], bins=[0, 80, 100], labels=['Warm', 'Hot'])
X_test['Humidity'] = pd.cut(X_test['Humidity'], bins=[0, 75, 100], labels=['Dry', 'Humid'])
# One-hot encode the categorized columns
one_hot_columns_train = pd.get_dummies(X_train[['Temperature', 'Humidity']], drop_first=True, dtype=int)
one_hot_columns_test = pd.get_dummies(X_test[['Temperature', 'Humidity']], drop_first=True, dtype=int)
# Drop the categorized columns from training and test sets
X_train = X_train.drop(['Temperature', 'Humidity'], axis=1)
X_test = X_test.drop(['Temperature', 'Humidity'], axis=1)
# Concatenate the one-hot encoded columns with the original DataFrames
X_train = pd.concat([one_hot_columns_train, X_train], axis=1)
X_test = pd.concat([one_hot_columns_test, X_test], axis=1)
print(pd.concat([X_train, y_train], axis=1), '\n')
print(pd.concat([X_test, y_test], axis=1))
El método Naive Bayes de Bernoulli opera con datos donde cada característica es 0 o 1.
- Calcular la probabilidad de cada clase en los datos de entrenamiento.
- Para cada característica y clase, calcule la probabilidad de que la característica sea 1 y 0 dada la clase.
- Para una nueva instancia: para cada clase, multiplique su probabilidad por la probabilidad de cada valor de característica (0 o 1) para esa clase.
- Predecir la clase con la probabilidad resultante más alta.
El proceso de entrenamiento para Bernoulli Naive Bayes implica el cálculo de probabilidades a partir de los datos de entrenamiento:
- 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 Fractiondef 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:
- (Número de instancias donde la característica es 0 en esta clase) / (Número de instancias en esta clase)
- (Número de instancias en las que la característica es 1 en esta clase) / (Número de instancias en esta clase)
from fractions import Fractiondef sort_attr_label(attr, lbl):
return (pd.concat([attr, lbl], axis=1)
.sort_values([attr.name, lbl.name])
.reset_index()
.rename(columns={'index': 'ID'})
.set_index('ID'))
def calc_feature_prob(attr, lbl):
total_classes = lbl.value_counts()
counts = pd.crosstab(attr, lbl)
prob_df = counts.apply(lambda x: [Fraction(c, total_classes[x.name]).limit_denominator() for c in x])
return prob_df
print(sort_attr_label(y_train, X_train['sunny']))
print(calc_feature_prob(X_train['sunny'], y_train))
for col in X_train.columns:
print(calc_feature_prob(X_train[col], y_train), "\n")
3. Suavizado (opcional):Agregue un valor pequeño (generalmente 1) al numerador y al denominador de cada cálculo de probabilidad para evitar probabilidades cero
# In sklearn, all processes above is summarized in this 'fit' method:
from sklearn.naive_bayes import BernoulliNB
nb_clf = BernoulliNB(alpha=1)
nb_clf.fit(X_train, y_train)
4. Resultados de la tienda:Guarda todas las probabilidades calculadas para usarlas durante la clasificación.
Dada una nueva instancia con características que son 0 o 1:
- Colección de probabilidades:Para cada clase posible:
- Comience con la probabilidad de que ocurra esta clase (probabilidad de clase).
- Para cada característica en la nueva instancia, recopile la probabilidad de que esta característica sea 0/1 para esta clase.
2. Cálculo y predicción de la puntuación:Para cada clase:
- Multiplica todas las probabilidades recopiladas juntas
- El resultado es la puntuación para esta clase.
- La clase con la puntuación más alta es la predicción.
y_pred = nb_clf.predict(X_test)
print(y_pred)
# Evaluate the classifier
print(f"Accuracy: {accuracy_score(y_test, y_pred)}")
El método Naive Bayes de Bernoulli tiene algunos parámetros importantes:
- Alfa (α): Este es el parámetro de suavizado. Agrega un pequeño recuento a cada característica para evitar probabilidades cero. El valor predeterminado suele ser 1,0 (suavizado de Laplace), como se mostró anteriormente.
- Binarizar:Si sus características aún no son binarias, este umbral las convierte. Cualquier valor por encima de este umbral se convierte en 1 y cualquier valor por debajo se convierte en 0.
3. Ajuste previo:Si aprender probabilidades previas de clase o asumir probabilidades previas uniformes (50/50).
Como cualquier algoritmo de aprendizaje automático, Bernoulli Naive Bayes tiene sus fortalezas y limitaciones.
- Sencillez:Fácil de implementar y comprender.
- Eficiencia:Rápido de entrenar y predecir, funciona bien con grandes espacios de características.
- Rendimiento con conjuntos de datos pequeños:Puede funcionar bien incluso con datos de entrenamiento limitados.
- Maneja datos de alta dimensión:Funciona bien con muchas funciones, especialmente en la clasificación de texto.
- Asunción de la Independencia:Supone que todas las características son independientes, lo que a menudo no es cierto en los datos del mundo real.
- Limitado a funciones binarias:En su forma pura, sólo funciona con datos binarios.
- Sensibilidad a los datos de entrada:Puede ser sensible a cómo se binarizan las características.
- Problema de frecuencia cero:Sin suavizado, las probabilidades cero pueden afectar fuertemente las predicciones.
El clasificador Bernoulli Naive Bayes es un algoritmo de aprendizaje automático simple pero potente para la clasificación binaria. Se destaca en el análisis de texto y la detección de spam, donde las características son típicamente binarias. Este modelo probabilístico, conocido por su velocidad y eficiencia, funciona bien con conjuntos de datos pequeños y espacios de alta dimensión.
A pesar de su suposición ingenua de independencia de las características, a menudo rivaliza con modelos más complejos en cuanto a precisión. El método Bayes ingenuo de Bernoulli sirve como una excelente herramienta de clasificación de referencia y en tiempo real.
# Import needed libraries
import pandas as pd
from sklearn.naive_bayes import BernoulliNB
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split# Load the dataset
dataset_dict = {
'Outlook': ['sunny', 'sunny', 'overcast', 'rainy', 'rainy', 'rainy', 'overcast', 'sunny', 'sunny', 'rainy', 'sunny', 'overcast', 'overcast', 'rainy', 'sunny', 'overcast', 'rainy', 'sunny', 'sunny', 'rainy', 'overcast', 'rainy', 'sunny', 'overcast', 'sunny', 'overcast', 'rainy', 'overcast'],
'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0, 72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0, 88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
'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],
'Wind': [False, True, False, False, False, True, True, False, False, False, True, True, False, True, True, False, False, True, False, True, True, False, True, False, False, True, False, False],
'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
df = pd.get_dummies(df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)
# Split data into training and testing sets
X, y = df.drop(columns='Play'), df['Play']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)
# Scale numerical features (for automatic binarization)
scaler = StandardScaler()
float_cols = X_train.select_dtypes(include=['float64']).columns
X_train[float_cols] = scaler.fit_transform(X_train[float_cols])
X_test[float_cols] = scaler.transform(X_test[float_cols])
# Train the model
nb_clf = BernoulliNB()
nb_clf.fit(X_train, y_train)
# Make predictions
y_pred = nb_clf.predict(X_test)
# Check accuracy
print(f"Accuracy: {accuracy_score(y_test, y_pred)}")