sitio personal de Rodrigo Garcia Saenz.

Clasificación mensajes correo debian parte 3

permalink.

Despliegue de modelos de clasificación mensajes de correo electrónico de la lista de Debian

Actualizado - 23 July 2023

Continuando desde la segunda parte donde ya hemos entrenado y obtenido modelos para la clasificación de mensaje ahora continuaremos a "exportarlos" para poder usarlos:

Machine learning d2

Aplicaremos nuevos mensajes de texto al modelo ya generado y este va a devolver predicciones. En este caso cuando introduzcamos un mensaje de texto, usando el modelo se predice a qué categoría de mensajes de la lista de correos de debian pertenece ese mensaje de texto.

Exportando el modelo

En el notebook de la parte 2 (debian-2015-2019-NaiveBayes-RandomForest.ipynb) hay una parte que guarda guarda tres cosas:

  • El modelo generado aplicando la técnica.
  • La matriz CountVectorizer con el conteo de palabras y ocurrencias.
  • El diccionario de categorías y su valor numérico tal y como lo manejamos para entrenar el modelo.

Con estos objetos ya obtenidos al hacer el entrenamiento, usaremos la biblioteca python pickle que serializa objetos python y los guarda en archivos binarios, esos archivos luego se pueden leer desde otro programa o script python y se puede recuperar el objeto python original.

El proceso de guardado se hace en el con:

import pickle
pickle.dump(model_multinomialNB, open('./model_multinomialNB.pkl', "wb"))
pickle.dump(cv_multinomialNB, open('./cv_multinomialNB.pkl', "wb"))
pickle.dump(labelsEncodedNB, open('./labelsEncodedNB.pkl', "wb"))

pickle.dump(model_randomForest4, open('./model_randomForest.pkl', "wb"))
pickle.dump(cv_randomForest4, open('./cv_randomForest.pkl', "wb"))
pickle.dump(labelsEncodedRf4, open('./labelsEncodedRf.pkl', "wb"))

Que guarda en archivos con extensión .pkl. Algo interesante es que los archivos guardados tienen tamaños variables:

2,3M       cv_multinomialNB.pkl
2,3M       cv_randomForest.pkl
514        labelsEncodedNB.pkl
514        labelsEncodedRf.pkl
256K       model_multinomialNB.pkl
106M       model_randomForest.pkl

El archivo serializado model_multinomialNB.pkl tiene un tamaño de 256KB que corresponde a la técnica Miultinomial Naive Bayes, y el archivo model_randomForest.pkl de la técnica Random Forest tiene un tamaño de 106MB. El modelo generado por random Forest es como 40 veces más grande y esto se debe a que durante el entrenamiento para el Random Forest se usaron un total de 80 árboles binarios que tomo un tiempo considerablemente mayor en entrenar que la técnica Multinomial Naive Bayes.

Cargando los modelos exportados

Ahora vamos a cargar estos modelos generados en otro notebook jupyter, este se puede revisar por completo:

jupyter notebook: debian-2015-2019-model-application.ipynb

En las primeras partes volvemos a usar pickle para importar los modelos guardados.

# cargando los modelos y otros datos generados anteriormente
import pickle
model_multinomialNB = pickle.load(open('./model_multinomialNB.pkl', 'rb'))
cv_multinomialNB = pickle.load(open('./cv_multinomialNB.pkl', 'rb'))
labelsEncodedNB = pickle.load(open('./labelsEncodedNB.pkl', 'rb'))

model_randomForest = pickle.load(open('./model_randomForest.pkl', 'rb'))
cv_randomForest = pickle.load(open('./cv_randomForest.pkl', 'rb'))
labelsEncodedRf = pickle.load(open('lablesEncodedRf.pkl', 'rb'))

Aplicando mensajes y generando nuevas predicciones

Se definen algunos mensajes de texto nuevos y los unimos en una lista python:

m1 = "We are looking for a GNU/Linux System Administrator in Charlotte, North Carolina. Other locations near the EST timezone will"
m2 = '''Traceback (most recent call last): 
File ""/tmp/autopkgtest-lxc.5a99fnj6/downtmp/autopkgtest_tmp/tests/test_core/test_sequence.py'''
m3 = '''Actually, the GPL only mandates stating *who* made changes and *when*,but not *what* changed. As I see, 
just adding something like ""Modified by John Doe on 2019.07.25"" on the comment header where the GPL copyright notice lies 
would suffice"'''
m4 = '''E: pybuild pybuild:336: test: plugin distutils failed with: exit code=1: 
cd /build/snakemake-4.8.0/.pybuild/cpython3_3.6_snakemake/build; 
python3.6 -m nose tests dh_auto_test: pybuild --test --test-nose -i python{version} -p 3.6 returned exit code 13 make: 
*** [debian/rules:17: build] Error 25 dpkg-buildpackage: error: debian/rules build subprocess returned exit status 2 I: 
copying local configuration E: Failed autobuilding of package 
I: user script /var/cache/pbuilder/build/cow.11501/tmp/hooks/C99_failed_build starting root:/# echo $PATH'''
m5 = """I'd take option 2.There ought to be no packages using python-dput (like, srly…), and I see no real reason for anybody
 to keep using the py2 version after the switch."""
m6 = """Nothing can be done without previous voting phase, we are talking about somewhat important
 issues that must be taken into considereation before finally giving them a certain direction. Regards BlueBon."""
m7 = """I would be happy to teach anyone, including you, how to sync between weblate and salsa 
(which mostly involve 'git pull weblate master && git push' with a few clicks on the Weblate admin page to reduce 
the chance of any git conflict in between)"""

# uniendo
testMsjs = pd.Series([m1,m2,m3,m4,m5,m6,m7])

Ahora agregamos las palabras nuevas a las matrices de conteo de palabras del entrenamiento anterior como se muestra en [1]:

vect = cv_multinomialNB.transform(testMsjs).toarray()

Usamos el modelo para generar nuevas predicciones:

predictions = model_multinomialNB.predict(vect)

Finalmente vamos a ver a qué categorías corresponden las predicciones.

# mostrando resultados
for i in range(len(predictions)):
    print('m' + str(i+1), '-->', labelsEncodedNB[predictions[i]])

Que muestra:

m1 --> debian-mentors
m2 --> debian-python
m3 --> debian-legal
m4 --> debian-python
m5 --> debian-python
m6 --> debian-vote
m7 --> debian-science

Haciendo lo mismo con el modelo de la técnica Random Forest:

vect = cv_randomForest.transform(testMsjs).toarray()
predictions = model_randomForest.predict(vect)

for i in range(len(predictions)):
    print('m' + str(i+1), '-->', labelsEncodedRf[predictions[i]])

Resulta:

m1 --> debian-mentors
m2 --> debian-mentors
m3 --> debian-legal
m4 --> debian-python
m5 --> debian-python
m6 --> debian-mentors
m7 --> debian-mentors

Comentarios finales

Ambos modelos han clasificado bien la mayoría de los mensajes de pruebas, con algunas diferencias:

  • El mensaje m2 que es un texto con un mensaje de error de python, lo ha clasificado correctamente Naive Bayes pero no Random Forest
  • El mensaje m6 que es texto que habla de la necesidad de un proceso de votación antes de decidir algo, lo ha clasificado correctamente el Naive Bayes pero no Random Forest.
  • El mensaje m7 se parece más a un mensaje de alguien que se ofrece a enseñar algo, la técnica Random Forest lo ha clasificado correctamente en la categoría debian-mentors, y la técnica Naive Bayes lo considera de la categoría debian-science.

Usando mas allá

Lo bueno es que ya tenemos la forma sencilla de importar en cualquier otro programa los modelos generados en el entrenamiento anterior.

Las aplicaciones son muchas por ejemplo como se muestra en [1] se puede desplegar una aplicación web con un formulario donde se introduzca texto y este es clasificado como spam o no spam. También se podría aplicar a un programa clasificador automático de mensajes cuando alguien escribe un correo electrónico cuando en caso de detectar un mensaje que no pertenece a la categoría a la que se esta escribiendo, el programa le avise que podría estar enviando su mensaje a una categoría equivocada.

La clasificación de textos es un área de estudio del aprendizaje automático muy interesante y estas técnicas que usamos demuestran ser muy útiles. Seguramente existen otras técnicas y la combinación de estas que se ajustan a distintos casos.

Referencias

  1. https://towardsdatascience.com/develop-a-nlp-model-in-python-deploy-it-with-flask-step-by-step-744f3bdd7776
Consejo del día

Cuando no estés usando el WiFi por ejemplo para dormir apágalo. Hay estudios que sugieren que el WiFi provoca dificultad para dormir y podría causar estrés cardíaco entre otros (más información).