El algoritmo Naive Bayes en Python con Scikit-Learn

    Al estudiar probabilidad y estad铆stica, uno de los primeros y m谩s importantes teoremas que aprenden los estudiantes es el Teorema de Bayes. Este teorema es la base del razonamiento deductivo, que se centra en determinar la probabilidad de que ocurra un evento bas谩ndose en el conocimiento previo de las condiciones que podr铆an estar relacionadas con el evento.

    los Clasificador ingenuo de Bayes lleva el poder de este teorema al Machine Learning, construyendo un clasificador muy simple pero poderoso. En este art铆culo, veremos una descripci贸n general sobre c贸mo funciona este clasificador, qu茅 aplicaciones adecuadas tiene y c贸mo usarlo en solo unas pocas l铆neas de Python y la biblioteca Scikit-Learn.

    Teor铆a detr谩s del teorema de Bayes

    Si estudiaste Inform谩tica, Matem谩ticas o cualquier otro campo relacionado con la estad铆stica, es muy probable que en alg煤n momento te hayas topado con la siguiente f贸rmula:

    P(H|E) = (P(E|H) * P(H)) / P(E)
    

    d贸nde

    • P(H|E) es la probabilidad de hip贸tesis H dado el evento E, una probabilidad posterior.
    • P(E|H) es la probabilidad de evento E dado que la hip贸tesis H es verdad.
    • P(H) es la probabilidad de hip贸tesis H siendo cierto (independientemente de cualquier evento relacionado), o probabilidad previa de H.
    • P(E) es la probabilidad de que ocurra el evento (independientemente de la hip贸tesis).

    Este es el teorema de Bayes. A primera vista, puede ser dif铆cil encontrarle sentido, pero es muy intuitivo si lo exploramos a trav茅s de un ejemplo:

    Digamos que nos interesa saber si un correo electr贸nico que contiene la palabra sexo (evento) es spam (hip贸tesis). Si volvemos a la descripci贸n del teorema, este problema se puede formular como:

    P(class=SPAM|contains="sex") = (P(contains="sex"|class=SPAM) * P(class=SPAM)) / P(contains="sex")
    

    que en un lenguaje sencillo es: La probabilidad de que un correo electr贸nico que contenga la palabra sexo sea spam es igual a la proporci贸n de correos electr贸nicos SPAM que contienen la palabra sexo multiplicada por la proporci贸n de correos electr贸nicos que son spam y dividida por la proporci贸n de correos electr贸nicos correos electr贸nicos que contienen la palabra sexo.

    Analicemos esta pieza por pieza:

    • P(class=SPAM|contains="sex") es la probabilidad de que un correo electr贸nico sea SPAM dado que este correo electr贸nico contiene la palabra sexo. Esto es lo que nos interesa predecir.
    • P(contains="sex"|class=SPAM) es la probabilidad de que un correo electr贸nico contenga la palabra sexo dado que este correo electr贸nico ha sido reconocido como SPAM. Estos son nuestros datos de entrenamiento, que representan la correlaci贸n entre un correo electr贸nico que se considera SPAM y el correo electr贸nico que contiene la palabra sexo.
    • P(class=SPAM) es la probabilidad de que un correo electr贸nico sea SPAM (sin conocimiento previo de las palabras que contiene). Esta es simplemente la proporci贸n de correos electr贸nicos que son SPAM en todo nuestro conjunto de capacitaci贸n. Multiplicamos por este valor porque nos interesa saber qu茅 tan significativa es la informaci贸n relativa a los correos electr贸nicos no deseados. Si este valor es bajo, la importancia de cualquier evento relacionado con los correos electr贸nicos no deseados tambi茅n ser谩 baja.
    • P(contains="sex") es la probabilidad de que un correo electr贸nico contenga la palabra sexo. Esta es simplemente la proporci贸n de correos electr贸nicos que contienen la palabra sexo en todo nuestro conjunto de entrenamiento. Dividimos por este valor porque cuanto m谩s exclusiva es la palabra sexo, m谩s importante es el contexto en el que aparece. As铆, si este n煤mero es bajo (la palabra aparece muy raramente), puede ser un gran indicador de que en los casos en que s铆 aparece, es una caracter铆stica relevante para analizar.

    En resumen, el Teorema de Bayes nos permite realizar una deducci贸n razonada de los eventos que ocurren en el mundo real en base al conocimiento previo de las observaciones que puedan implicarlo. Para aplicar este teorema a cualquier problema, necesitamos calcular los dos tipos de probabilidades que aparecen en la f贸rmula.

    Probabilidades de clase

    En el teorema, P(A) representa las probabilidades de cada evento. En el Clasificador Naive Bayes, podemos interpretar estas Probabilidades de Clase simplemente como la frecuencia de cada instancia del evento dividida por el n煤mero total de instancias. Por ejemplo, en el ejemplo anterior de detecci贸n de spam, P(class=SPAM) representa el n煤mero de correos electr贸nicos clasificados como spam dividido por la suma de todas las instancias (esto es spam + not spam)

    P(class=SPAM) = count(class=SPAM) / (count(class=notSPAM) + count(class=SPAM))
    

    Probabilidades condicionales

    En el teorema, P(A|B) representa las probabilidades condicionales de un evento A dado otro evento B. En el clasificador Naive Bayes, estos codifican la probabilidad posterior de A ocurriendo cuando B es verdad.

    Para el ejemplo del spam, P(class=SPAM|contains="sex") representa el n煤mero de casos en los que un correo electr贸nico se considera spam y contiene la palabra sexo, dividido por el n煤mero total de mensajes de correo electr贸nico que contienen la palabra sexo:

    P(class=SPAM|contains="sex") = count(class=SPAM & contains=sex) / count(contains=sex)
    

    Aplicaciones

    La aplicaci贸n del Clasificador Naive Bayes se ha mostrado exitosa en diferentes escenarios. Un caso de uso cl谩sico es la clasificaci贸n de documentos: determinar si un documento dado corresponde a determinadas categor铆as. Sin embargo, esta t茅cnica tiene sus ventajas y limitaciones.

    Ventajas

    • Naive Bayes es un algoritmo simple y f谩cil de implementar. Debido a esto, podr铆a superar a modelos m谩s complejos cuando la cantidad de datos es limitada.
    • Naive Bayes funciona bien con datos num茅ricos y categ贸ricos. Tambi茅n se puede utilizar para realizar regresiones mediante Gaussian Naive Bayes.

    Limitaciones

    • Dada la construcci贸n del teorema, no funciona bien cuando falta cierta combinaci贸n de valores en los datos de entrenamiento. En otras palabras, si no tiene apariciones de una etiqueta de clase y un determinado valor de atributo juntos (por ejemplo, clase = “spam”, contiene = “$$$”) entonces la estimaci贸n de probabilidad basada en la frecuencia ser谩 cero. Dada la suposici贸n de independencia condicional de Naive-Bayes, cuando se multiplican todas las probabilidades obtendr谩 cero.
    • Naive Bayes funciona bien siempre que las categor铆as se mantengan simples. Por ejemplo, funciona bien para problemas que involucran palabras clave como caracter铆sticas (por ejemplo, detecci贸n de spam), pero no funciona cuando la relaci贸n entre palabras es importante (por ejemplo, an谩lisis de sentimientos).

    Demo en Scikit-Learn

    隆Es hora de la demostraci贸n! Usaremos Python 3 junto con Scikit-Learn para construir un detector de SPAM muy simple para mensajes SMS (para aquellos de ustedes que son j贸venes, esto es lo que usamos para la mensajer铆a en la Edad Media). Puede buscar y descargar el conjunto de datos desde este enlace.

    Necesitaremos tres bibliotecas que facilitar谩n mucho nuestra codificaci贸n: scikit-learn, pandas y nltk. Puedes usar pip o conda para instalar estos.

    Cargando los datos

    SMS Spam Collection v.1 es un conjunto de mensajes SMS etiquetados que se han recopilado para la investigaci贸n de SMS Spam. Contiene un conjunto de mensajes SMS en ingl茅s de 5.574 mensajes, etiquetados seg煤n sea ham (leg铆timo) o spam. La distribuci贸n es de un total de 4.827 mensajes SMS leg铆timos (86,6%) y un total de 747 (13,4%) mensajes de spam.

    Si abrimos el conjunto de datos, veremos que tiene el formato [label] [tab] [message], que se parece a esto:

    ham	Go until jurong point, crazy.. Available only in bugis n great world la e buffet... Cine there got amore wat...
    
    ham	Ok lar... Joking wif u oni...
    
    spam	Free entry in 2 a wkly comp to win FA Cup final tkts 21st May 2005. Text FA to 87121 to receive entry question(std txt rate)T&C's apply 08452810075over18's
    
    ham	U dun say so early hor... U c already then say...
    

    Para cargar los datos, podemos usar el Dataframe de Pandas read_table m茅todo. Esto nos permite definir un separador (en este caso, una pesta帽a) y cambiar el nombre de las columnas en consecuencia:

    import pandas as pd
    
    df = pd.read_table('SMSSpamCollection',
                       sep='t', 
                       header=None,
                       names=['label', 'message'])
    

    Preprocesamiento

    Una vez que tengamos nuestros datos listos, es hora de hacer un preprocesamiento. Nos centraremos en eliminar las variaciones in煤tiles para nuestra tarea. Primero, tenemos que convertir las etiquetas de cadenas a valores binarios para nuestro clasificador:

    df['label'] = df.label.map({'ham': 0, 'spam': 1})
    

    En segundo lugar, convierta todos los caracteres del mensaje a min煤sculas:

    df['message'] = df.message.map(lambda x: x.lower())
    

    En tercer lugar, elimine cualquier puntuaci贸n:

    df['message'] = df.message.str.replace('[^ws]', '')
    

    Cuarto, convierta los mensajes en una sola palabra usando nltk. Primero, tenemos que importar y descargar el tokenizador desde la consola:

    import nltk
    nltk.download()
    

    Aparecer谩 una ventana de instalaci贸n. Vaya a la pesta帽a “Modelos” y seleccione “punkt” en la columna “Identificador”. Luego haga clic en “Descargar” e instalar谩 los archivos necesarios. 隆Entonces deber铆a funcionar! Ahora podemos aplicar la tokenizaci贸n:

    df['message'] = df['message'].apply(nltk.word_tokenize)
    

    Quinto, realizaremos algunos derivaci贸n de palabras. La idea de derivar es normalizar nuestro texto para que todas las variaciones de palabras tengan el mismo significado, independientemente del tiempo verbal. Uno de los algoritmos de derivaci贸n m谩s populares es el Porter Stemmer:

    from nltk.stem import PorterStemmer
    
    stemmer = PorterStemmer()
     
    df['message'] = df['message'].apply(lambda x: [stemmer.stem(y) for y in x])
    

    Finalmente, transformaremos los datos en ocurrencias, que ser谩n las caracter铆sticas que alimentaremos a nuestro modelo:

    from sklearn.feature_extraction.text import CountVectorizer
    
    # This converts the list of words into space-separated strings
    df['message'] = df['message'].apply(lambda x: ' '.join(x))
    
    count_vect = CountVectorizer()
    counts = count_vect.fit_transform(df['message'])
    

    Podr铆amos dejarlo como el simple recuento de palabras por mensaje, pero es mejor usar T茅rmino Frecuencia Frecuencia inversa del documento, m谩s conocido como tf-idf:

    from sklearn.feature_extraction.text import TfidfTransformer
    
    transformer = TfidfTransformer().fit(counts)
    
    counts = transformer.transform(counts)
    

    Entrenando el modelo

    Ahora que hemos realizado la extracci贸n de caracter铆sticas de nuestros datos, es hora de construir nuestro modelo. Comenzaremos dividiendo nuestros datos en conjuntos de prueba y entrenamiento:

    from sklearn.model_selection import train_test_split
    
    X_train, X_test, y_train, y_test = train_test_split(counts, df['label'], test_size=0.1, random_state=69)
    

    Luego, todo lo que tenemos que hacer es inicializar el Clasificador Naive Bayes y ajustar los datos. Para problemas de clasificaci贸n de texto, el clasificador multinomial Naive Bayes es adecuado:

    from sklearn.naive_bayes import MultinomialNB
    
    model = MultinomialNB().fit(X_train, y_train)
    

    Evaluaci贸n del modelo

    Una vez que hemos armado nuestro clasificador, podemos evaluar su desempe帽o en el conjunto de pruebas:

    import numpy as np
    
    predicted = model.predict(X_test)
    
    print(np.mean(predicted == y_test))
    

    隆Felicidades! Nuestro sencillo clasificador Naive Bayes tiene una precisi贸n del 98,2% con este equipo de prueba espec铆fico. Pero no es suficiente con solo proporcionar la precisi贸n, ya que nuestro conjunto de datos est谩 desequilibrado en lo que respecta a las etiquetas (86,6% leg铆timo en contraste con 13,4% de spam). Puede suceder que nuestro clasificador sobrepase la clase leg铆tima mientras ignora la clase de spam. Para resolver esta incertidumbre, echemos un vistazo a la matriz de confusi贸n:

    from sklearn.metrics import confusion_matrix
    
    print(confusion_matrix(y_test, predicted))
    

    los confusion_matrix El m茅todo imprimir谩 algo como esto:

    [[478   4]
    [   6  70]]
    

    Como podemos ver, la cantidad de errores est谩 bastante equilibrada entre leg铆timos y spam, con 4 mensajes leg铆timos clasificados como spam y 6 mensajes spam clasificados como leg铆timos. En general, estos son muy buenos resultados para nuestro clasificador simple.

    Conclusi贸n

    En este art铆culo, hemos visto un curso intensivo sobre teor铆a y pr谩ctica del Clasificador Naive Bayes. Hemos creado un clasificador Bayes ingenuo multimodal simple que logra una precisi贸n del 98,2% en la detecci贸n de spam para mensajes SMS.

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *