Capítulo 4. Clasificación de textos

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

Organizar es lo que haces antes de hacer algo,
para que cuando lo hagas no esté todo mezclado.

A.A. Milne

Todos comprobamos el correo electrónico todos los días, posiblemente varias veces. Una función útil de la mayoría de los proveedores de servicios de correo electrónico es la capacidad de separar automáticamente los correos basura de los correos normales. Este es un caso de uso de una popular tarea de PNL conocida como clasificación de textos, que es el tema central de este capítulo. La clasificación de textos es la tarea de asignar una o más categorías a un texto determinado a partir de un conjunto más amplio de categorías posibles. En el ejemplo del identificador de spam de correo electrónico, tenemos dos categorías -spam y no spam- y cada correo electrónico entrante se asigna a una de estas categorías. Esta tarea de categorizar textos basándose en algunas propiedades tiene una amplia gama de aplicaciones en diversos ámbitos, como las redes sociales, el comercio electrónico, la sanidad, el derecho y el marketing, por nombrar algunos. Aunque la finalidad y la aplicación de la clasificación de textos pueden variar de un dominio a otro, el problema abstracto subyacente sigue siendo el mismo. Esta invariabilidad del problema central y sus aplicaciones en infinidad de dominios hacen que la clasificación de textos sea, con diferencia, la tarea de PNL más utilizada en la industria y la más investigada en el mundo académico. En este capítulo, hablaremos de la utilidad de la clasificación de textos y de cómo construir clasificadores de textos para nuestros casos de uso, junto con algunos consejos prácticos para escenarios del mundo real.

En el aprendizaje automático, la clasificación es el problema de categorizar una instancia de datos en una o más clases conocidas. El punto de datos puede tener originalmente distintos formatos, como texto, voz, imagen o numérico. La clasificación de textos es un caso especial del problema de clasificación, en el que los datos de entrada son texto y el objetivo es clasificar el texto en una o varias categorías (llamadas clases) de entre un conjunto de categorías (clases) predefinidas. El "texto" puede tener una longitud arbitraria: un carácter, una palabra, una frase, un párrafo o un documento completo. Considera un escenario en el que queremos clasificar todas las opiniones de los clientes de un producto en tres categorías: positivas, negativas y neutras. El reto de la clasificación de textos es "aprender" esta categorización a partir de una colección de ejemplos para cada una de estas categorías y predecir las categorías para nuevos productos no vistos y nuevas reseñas de clientes. Sin embargo, esta categorización no tiene por qué dar siempre como resultado una única categoría, y puede haber cualquier número de categorías disponibles. Echemos un vistazo rápido a la taxonomía de la clasificación de textos para entender esto.

Cualquier enfoque de clasificación supervisada, incluida la clasificación de textos, puede distinguirse a su vez en tres tipos en función del número de categorías implicadas: clasificación binaria, multiclase y multietiqueta. Si el número de clases es dos, se denomina clasificación binaria. Si el número de clases es superior a dos, se denomina clasificación multiclase. Así, clasificar un correo electrónico como spam o no-spam es un ejemplo de clasificación binaria. Clasificar el sentimiento de una opinión de un cliente como negativo, neutral o positivo es un ejemplo de clasificación multiclase. Tanto en la clasificación binaria como en la multiclase, cada documento pertenece exactamente a una clase de C, donde C es el conjunto de todas las clases posibles. En la clasificación multietiqueta, un documento puede tener asociadas una o más etiquetas/clases. Por ejemplo, una noticia sobre un partido de fútbol puede pertenecer a más de una categoría, como "deportes" y "fútbol", simultáneamente, mientras que otra noticia sobre las elecciones en EE.UU. puede tener las etiquetas "política", "EE.UU." y "elecciones". Así, cada documento tiene etiquetas que son un subconjunto de C. Cada artículo puede no pertenecer a ninguna clase, exactamente a una clase, a varias clases o a todas las clases. A veces, el número de etiquetas del conjunto C puede ser muy grande (lo que se conoce como "clasificación extrema"). En otros casos, podemos tener un sistema de clasificación jerárquico, lo que puede dar lugar a que cada texto reciba etiquetas diferentes en distintos niveles de la jerarquía. En este capítulo, nos centraremos sólo en la clasificación binaria y multiclase, ya que son los casos de uso más comunes de la clasificación de textos en la industria.

La clasificación de textos a veces también se denomina clasificación de temas, categorización de textos, o categorización de documentos. Para el resto de este libro, nos ceñiremos al término "clasificación de textos". Ten en cuenta que la clasificación de temas es diferente de la detección de temas, que se refiere al problema de descubrir o extraer "temas" de los textos, que estudiaremos en el Capítulo 7.

En este capítulo, examinaremos más de cerca la clasificación de textos y construiremos clasificadores de textos utilizando distintos enfoques. Nuestro objetivo es ofrecer una visión general de algunas de las técnicas más aplicadas, junto con consejos prácticos sobre cómo manejar los distintos escenarios y las decisiones que hay que tomar al construir sistemas de clasificación de textos en la práctica. Empezaremos presentando algunas aplicaciones comunes de la clasificación de textos, luego hablaremos de cómo es una canalización de PNL para la clasificación de textos e ilustraremos el uso de esta canalización para entrenar y probar clasificadores de textos utilizando distintos enfoques, que van desde los métodos tradicionales hasta el estado del arte. A continuación, abordaremos el problema de la recopilación/escasez de datos de entrenamiento y los distintos métodos para abordarlo. Terminaremos el capítulo resumiendo lo que hemos aprendido en todas estas secciones, junto con algunos consejos prácticos y un caso práctico.

Ten en cuenta que, en este capítulo, sólo trataremos el aspecto del entrenamiento y la evaluación de los clasificadores de texto. Las cuestiones relacionadas con la implementación de los sistemas de PNL en general y la realización de la garantía de calidad se tratarán en el Capítulo 11.

Aplicaciones

La clasificación de textos ha sido de interés en una serie de escenarios de aplicación, que van desde la identificación del autor de un texto desconocido en el siglo XIX hasta los esfuerzos de USPS en la década de 1960 para realizar el reconocimiento óptico de caracteres en direcciones y códigos postales [1]. En la década de 1990, los investigadores empezaron a aplicar con éxito algoritmos de ML para la clasificación de textos en grandes conjuntos de datos. El filtrado de correo electrónico, conocido popularmente como "clasificación de spam", es uno de los primeros ejemplos de clasificación automática de texto, que repercute en nuestras vidas hasta el día de hoy. Desde los análisis manuales de documentos de texto hasta los enfoques puramente estadísticos basados en ordenadores y las redes neuronales profundas de última generación, hemos recorrido un largo camino con la clasificación de textos. Analicemos brevemente algunas de las aplicaciones más populares antes de sumergirnos en los distintos enfoques para realizar la clasificación de textos. Estos ejemplos también serán útiles para identificar los problemas que pueden resolverse utilizando métodos de clasificación de textos en tu organización.

Clasificación y organización de los contenidos

Se refiere a la tarea de clasificar/etiquetar grandes cantidades de datos textuales. Esto, a su vez, se utiliza para potenciar casos de uso como la organización de contenidos, los motores de búsqueda y los sistemas de recomendación, por nombrar algunos. Ejemplos de estos datos son los sitios web de noticias, los blogs, las estanterías de libros en línea, las reseñas de productos, los tweets, etc.; etiquetar las descripciones de los productos en un sitio web de comercio electrónico; dirigir las solicitudes de atención al cliente en una empresa al equipo de asistencia adecuado; y organizar los correos electrónicos en personales, sociales y promociones en Gmail son ejemplos de uso de la clasificación de textos para la clasificación y organización de contenidos.

Atención al cliente

Los clientes suelen utilizar las redes sociales para expresar sus opiniones y experiencias sobre productos o servicios. La clasificación de textos se utiliza a menudo para identificar los tweets a los que las marcas deben responder (es decir, los que son procesables) y los que no requieren una respuesta (es decir, el ruido) [2, 3]. Para ilustrarlo, considera los tres tweets sobre la marca Macy's que se muestran en la Figura 4-1.

Aunque los tres tweets mencionan explícitamente la marca Macy's, sólo el primero requiere una respuesta del equipo de atención al cliente de Macy's.

Tweets reaching out to brands. The one is actionable, the other two are noise.
Figura 4-1. Tweets que llegan a las marcas: uno es procesable, los otros dos son ruido
Comercio electrónico

Los clientes dejan opiniones sobre una serie de productos en los sitios web de comercio electrónico como Amazon, eBay, etc. Un ejemplo de uso de la clasificación de textos en este tipo de escenarios es comprender y analizar la percepción que tienen los clientes de un producto o servicio basándose en sus comentarios. Esto se conoce comúnmente como "análisis de sentimiento". Lo utilizan mucho las marcas de todo el mundo para comprender mejor si se están acercando o alejando de sus clientes. En lugar de categorizar las opiniones de los clientes simplemente como positivas, negativas o neutras, durante un periodo de tiempo, el análisis de sentimientos ha evolucionado hacia un paradigma más sofisticado: el análisis de sentimientos basado en "aspectos". Para entenderlo, considera la opinión de un cliente sobre un restaurante que se muestra en la Figura 4-2.

A review that praises some aspects and criticizes few
Figura 4-2. Una crítica que elogia algunos aspectos y critica pocos

¿Dirías que la reseña de la Figura 4-2 es negativa, positiva o neutra? Es difícil responder a esto: la comida era estupenda, pero el servicio era malo. Los profesionales y las marcas que trabajan con análisis de sentimiento se han dado cuenta de que muchos productos o servicios tienen múltiples facetas. Para entender el sentimiento general, es importante comprender todas y cada una de las facetas. La clasificación de textos desempeña un papel fundamental en la realización de este análisis detallado de las opiniones de los clientes. Trataremos esta aplicación específica en detalle en el Capítulo 9.

Otras aplicaciones

Aparte de las áreas mencionadas, la clasificación de textos también se utiliza en otras aplicaciones de diversos ámbitos:

  • La clasificación de textos se utiliza en la identificación de idiomas, como la identificación del idioma de nuevos tweets o posts. Por ejemplo, Google Translate tiene una función de identificación automática de idiomas.

  • La atribución de autoría, o identificación de los autores desconocidos de los textos a partir de un conjunto de autores, es otro caso de uso popular de la clasificación de textos, y se utiliza en diversos campos, desde el análisis forense a los estudios literarios.

  • La clasificación de textos se ha utilizado recientemente para clasificar mensajes en un foro de ayuda en línea para servicios de salud mental [4]. En la comunidad de la PNL se celebran concursos anuales (por ejemplo, clpsych.org) para resolver este tipo de problemas de clasificación de textos originados en la investigación clínica.

  • En el pasado reciente, también se ha utilizado la clasificación de textos para segregar las noticias falsas de de las noticias reales.

Ten en cuenta que esta sección sólo sirve como ilustración de la amplia gama de aplicaciones de la clasificación de textos, y que la lista no es exhaustiva, pero esperamos que te proporcione suficientes antecedentes para identificar los problemas de clasificación de textos en tus proyectos laborales cuando te encuentres con ellos. Veamos ahora cómo construir esos modelos de clasificación de textos.

Un proceso para crear sistemas de clasificación de textos

En el Capítulo 2, hablamos de algunos de los conductos habituales de la PNL. La tubería de clasificación de textos comparte algunos de sus pasos con las tuberías que aprendimos en ese capítulo.

Normalmente se siguen estos pasos cuando se construye un sistema de clasificación de textos:

  1. Recoge o crea un conjunto de datos etiquetados adecuado para la tarea.

  2. Divide el conjunto de datos en dos (entrenamiento y prueba) o tres partes: conjuntos de entrenamiento, validación (es decir, desarrollo) y prueba, y luego decide la(s) métrica(s) de evaluación.

  3. Transforma el texto en bruto en vectores de características.

  4. Entrena un clasificador utilizando los vectores de características y las etiquetas correspondientes del conjunto de entrenamiento.

  5. Utilizando la(s) métrica(s) de evaluación del Paso 2, evalúa el rendimiento del modelo en el conjunto de pruebas.

  6. Implementa el modelo para que sirva al caso de uso del mundo real y monitorea su rendimiento.

La Figura 4-3 muestra estos pasos típicos en la construcción de un sistema de clasificación de textos.

Flowchart of a text classification pipeline
Figura 4-3. Diagrama de flujo de un proceso de clasificación de textos

Los pasos 3 a 5 se repiten para explorar distintas variantes de características y algoritmos de clasificación y sus parámetros, y para ajustar los hiperparámetros antes de proceder al paso 6, la implementación del modelo óptimo en producción.

Algunos de los pasos individuales relacionados con la recogida de datos y el preprocesamiento se trataron en capítulos anteriores. Por ejemplo, los Pasos 1 y 2 se trataron en detalle en el Capítulo 2. El Capítulo 3 se centró por completo en el Paso 3. En este capítulo nos centraremos en los Pasos 4 a 5. Hacia el final de este capítulo, volveremos sobre el Paso 1 para tratar cuestiones específicas de la clasificación de textos. Trataremos el Paso 6 en el Capítulo 11. Para poder realizar los Pasos 4 a 5 (es decir, para evaluar el rendimiento de un modelo o comparar varios clasificadores), necesitamos la(s) medida(s) de evaluación adecuada(s). En el Capítulo 2 se analizaron varias métricas generales utilizadas en la evaluación de los sistemas de PNL. Para evaluar clasificadores específicamente, entre las métricas introducidas en el Capítulo 2, las que se utilizan con más frecuencia son las siguientes: exactitud de la clasificación, precisión, recuperación, puntuación F1 y área bajo la curva ROC. En este capítulo, utilizaremos algunas de estas medidas para evaluar nuestros modelos y también examinaremos las matrices de confusión para comprender en detalle el rendimiento del modelo.

Aparte de éstos, cuando los sistemas de clasificación se implementan en aplicaciones del mundo real, también se utilizan indicadores clave de rendimiento (KPI) específicos de un caso de uso empresarial determinado para evaluar su impacto y el rendimiento de la inversión (ROI). A menudo, éstas son las métricas que preocupan a los equipos empresariales. Por ejemplo, si estamos utilizando la clasificación de texto para enrutar automáticamente las solicitudes de atención al cliente, un posible KPI podría ser la reducción del tiempo de espera antes de que se responda a la solicitud, en comparación con el enrutamiento manual. En este capítulo, nos centraremos en las medidas de evaluación de la PNL. En la Parte III del libro, donde trataremos casos de uso de la PNL específicos de sectores verticales, presentaremos algunos KPI que se utilizan a menudo en esos sectores verticales.

Antes de empezar a ver cómo construir clasificadores de texto utilizando la canalización que acabamos de comentar, echemos un vistazo a los escenarios en los que esta canalización no es en absoluto necesaria o en los que no es posible utilizarla.

Un clasificador sencillo sin la tubería de clasificación de textos

Cuando hablamos de la tubería de clasificación de textos, nos referimos a un escenario de aprendizaje automático supervisado. Sin embargo, es posible construir un clasificador sencillo sin aprendizaje automático y sin esta tubería. Considera el siguiente escenario de problema: se nos da un corpus de tweets en el que cada tweet está etiquetado con su sentimiento correspondiente: negativo o positivo. Por ejemplo, un tweet que dice: "¡La nueva película de James Bond es genial!" expresa claramente un sentimiento positivo, mientras que un tweet que dice: "¡No volvería a visitar este restaurante, es un sitio horrible!!" tiene un sentimiento negativo. Queremos construir un sistema de clasificación que prediga el sentimiento de un tuit no visto utilizando sólo el texto del tuit. Una solución sencilla podría ser crear listas de palabras positivas y negativas en inglés, es decir, palabras que tengan un sentimiento positivo o negativo. Luego comparamos el uso de palabras positivas y negativas en el tuit de entrada y hacemos una predicción basada en esta información. Otras mejoras de este enfoque pueden consistir en crear diccionarios más sofisticados con grados de sentimiento positivo, negativo y neutro de las palabras o formular heurísticas específicas (por ejemplo, el uso de ciertos emoticonos indica un sentimiento positivo) y utilizarlas para hacer predicciones. Este enfoque se denomina análisis del sentimiento basado en léxicos.

Evidentemente, esto no implica ningún "aprendizaje" de la clasificación de textos; es decir, se basa en un conjunto de heurísticas o reglas y en recursos construidos a medida, como diccionarios de palabras con sentimiento. Aunque este enfoque puede parecer demasiado simple para funcionar razonablemente bien en muchos escenarios del mundo real, puede permitirnos desplegar rápidamente un producto mínimo viable (MVP). Y lo que es más importante, este modelo sencillo puede llevarnos a comprender mejor el problema y darnos una línea de base sencilla para nuestra métrica y velocidad de evaluación. Por nuestra experiencia, siempre es bueno empezar con estos enfoques más sencillos al abordar un nuevo problema de PNL, siempre que sea posible. Sin embargo, con el tiempo, necesitaremos métodos de ML que puedan inferir más conocimientos a partir de grandes colecciones de datos de texto y obtener mejores resultados que el enfoque de referencia.

Utilizar las API existentes de clasificación de textos

Otro escenario en el que puede que no tengamos que "aprender" un clasificador o seguir esta canalización es cuando nuestra tarea es de naturaleza más genérica, como identificar una categoría general de un texto (por ejemplo, si es sobre tecnología o música). En tales casos, podemos utilizar las API existentes, como Google Cloud Natural Language [5], que proporcionan modelos de clasificación de contenidos listos para usar que pueden identificar cerca de 700 categorías diferentes de texto. Otra tarea de clasificación popular es el análisis de sentimientos. Todos los principales proveedores de servicios (por ejemplo, Google, Microsoft y Amazon) ofrecen API de análisis de sentimientos [5, 6, 7] con distintas estructuras de pago. Si se nos encarga construir un clasificador de sentimientos, puede que no tengamos que construir nuestro propio sistema si una API existente satisface nuestras necesidades empresariales.

Sin embargo, muchas tareas de clasificación podrían ser específicas de las necesidades empresariales de nuestra organización. En el resto de este capítulo, abordaremos el escenario de construir nuestro propio clasificador teniendo en cuenta la canalización descrita anteriormente en esta sección.

Una tubería, muchos clasificadores

Veamos ahora cómo construir clasificadores de texto alterando los pasos 3 a 5 de la canalización y manteniendo constantes los pasos restantes. Un buen conjunto de datos es un requisito previo para empezar a utilizar la canalización. Cuando decimos "buen" conjunto de datos, nos referimos a un conjunto de datos que sea una representación real de los datos que probablemente veamos en producción. A lo largo de este capítulo, utilizaremos algunos de los conjuntos de datos disponibles públicamente para la clasificación de textos. En Internet hay una amplia gama de conjuntos de datos relacionados con la PNL, incluidos los de clasificación de textos [8]. Además, la Figura Ocho [9] contiene una colección de conjuntos de datos de crowdsourcing, algunos de los cuales son relevantes para la clasificación de textos. El Repositorio de Aprendizaje Automático de la UCI [10] también contiene algunos conjuntos de datos de clasificación de textos. Google ha lanzado recientemente un sistema de búsqueda específico de conjuntos de datos para el aprendizaje automático [11]. Utilizaremos varios conjuntos de datos a lo largo de este capítulo en lugar de ceñirnos a uno solo para ilustrar cualquier problema específico de los conjuntos de datos que puedas encontrar.

Ten en cuenta que nuestro objetivo en este capítulo es darte una visión general de los distintos enfoques. No se conoce ningún enfoque que funcione universalmente bien en todos los tipos de datos y en todos los problemas de clasificación. En el mundo real, experimentamos con múltiples enfoques, los evaluamos y elegimos un enfoque final para implementarlo en la práctica.

Para el resto de esta sección, utilizaremos el conjunto de datos "Tono y relevancia de los artículos de noticias económicas" de la Figura Ocho para demostrar la clasificación de textos. Consta de 8.000 artículos de noticias anotados con si son relevantes o no para la economía de EE.UU. (es decir, una clasificación binaria sí/no). El conjunto de datos también está desequilibrado, con ~1.500 artículos relevantes y ~6.500 no relevantes, lo que plantea el reto de evitar el aprendizaje de un sesgo hacia la categoría mayoritaria (en este caso, los artículos no relevantes). Está claro que aprender qué es un artículo relevante es más difícil con este conjunto de datos que aprender qué es irrelevante. Después de todo, ¡simplemente adivinar que todo es irrelevante ya nos da un 80% de precisión!

Exploremos cómo se puede utilizar una representación BoW (introducida en el Capítulo 3) con este conjunto de datos, siguiendo el proceso descrito anteriormente en este capítulo. Construiremos clasificadores utilizando tres algoritmos bien conocidos: Naive Bayes, regresión logística y máquinas de vectores de soporte. El cuaderno relacionado con esta sección(Ch4/OnePipeline_ManyClassifiers.ipynb) muestra el proceso paso a paso de seguir nuestro pipeline utilizando estos tres algoritmos. Discutiremos algunos de los aspectos importantes en esta sección.

Clasificador Naive Bayes

Naive Bayes es un clasificador probabilístico que utiliza el teorema de Bayes para clasificar textos basándose en las pruebas observadas en los datos de entrenamiento. Estima la probabilidad condicional de cada característica de un texto dado para cada clase basándose en la aparición de esa característica en esa clase y multiplica las probabilidades de todas las características de un texto dado para calcular la probabilidad final de clasificación de cada clase. Por último, elige la clase con la máxima probabilidad. Una explicación detallada paso a paso del clasificador queda fuera del alcance de este libro. Sin embargo, el lector interesado en Naive Bayes con una explicación detallada en el contexto de la clasificación de textos puede consultar el Capítulo 4 de Jurafsky y Martin [12]. Aunque es sencillo, Naive Bayes se utiliza habitualmente como algoritmo de referencia en los experimentos de clasificación.

Vamos a recorrer los pasos clave de una implementación de la canalización descrita anteriormente para nuestro conjunto de datos. Para ello, utilizamos una implementación de Naive Bayes en scikit-learn. Una vez cargado el conjunto de datos, los dividimos en datos de entrenamiento y datos de prueba, como se muestra en el siguiente fragmento de código:

#Step 1: train-test split
X = our_data.text 
#the column text contains textual data to extract features from.
y = our_data.relevance 
#this is the column we are learning to predict.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
#split X and y into training and testing sets. By default, 
it splits 75% #training and 25% test. random_state=1 for reproducibility.

El siguiente paso es preprocesar los textos y convertirlos en vectores de características. Aunque hay muchas formas distintas de hacer el preprocesamiento, digamos que queremos hacer lo siguiente: minúsculas y eliminación de signos de puntuación, dígitos y cualquier cadena personalizada, y palabras vacías. El fragmento de código siguiente muestra este preprocesamiento y la conversión de los datos de entrenamiento y prueba en vectores de características utilizando CountVectorizer en scikit-learn, que es la implementación del enfoque BoW que comentamos en el Capítulo 3:

#Step 2-3: Pre-process and Vectorize train and test data
vect = CountVectorizer(preprocessor=clean) 
#clean is a function we defined for pre-processing, seen in the notebook.
X_train_dtm = vect.fit_transform(X_train)
X_test_dtm = vect.transform(X_test)
print(X_train_dtm.shape, X_test_dtm.shape)

Cuando ejecutemos esto en el cuaderno, veremos que acabamos teniendo un vector de características con ¡más de 45.000 características! Ahora tenemos los datos en el formato que queremos: vectores de características. Así que el siguiente paso es entrenar y evaluar un clasificador. El siguiente fragmento de código muestra cómo entrenar y evaluar un clasificador Naive Bayes con las características que hemos extraído anteriormente:

nb = MultinomialNB() #instantiate a Multinomial Naive Bayes classifier
nb.fit(X_train_dtm, y_train)#train the mode 
y_pred_class = nb.predict(X_test_dtm)#make class predictions for test data

La Figura 4-4 muestra la matriz de confusión de este clasificador con datos de prueba.

Confusion matrix for Naive Bayes classifier
Figura 4-4. Matriz de confusión para el clasificador Naive Bayes

Como se ve en la Figura 4-4, el clasificador identifica bastante bien los artículos no relevantes, ya que sólo comete errores el 14% de las veces. Sin embargo, no obtiene buenos resultados en comparación con la segunda categoría: la relevancia. Esta categoría sólo se identifica correctamente el 42% de las veces. Una idea obvia puede ser recopilar más datos. Es correcto y, a menudo, el enfoque más gratificante. Pero en aras de abarcar otros enfoques, suponemos que no podemos cambiarlo ni recoger datos adicionales. No es una suposición descabellada: en la industria, a menudo no podemos permitirnos el lujo de recopilar más datos; tenemos que trabajar con lo que tenemos. Se nos ocurren algunas posibles razones de este rendimiento y formas de mejorar este clasificador. Éstas se resumen en la Tabla 4-1, y examinaremos algunas de ellas a medida que avancemos en este capítulo.

Tabla 4-1. Razones potenciales del bajo rendimiento del clasificador
Motivo 1 Como extrajimos todas las características posibles, acabamos con un vector de características grande y disperso, en el que la mayoría de las características son demasiado raras y acaban siendo ruido. Un conjunto de características disperso también dificulta el entrenamiento.
Razón 2 Hay muy pocos ejemplos de artículos relevantes (~20%) en comparación con los artículos no relevantes (~80%) del conjunto de datos. Este desequilibrio de clases hace que el proceso de aprendizaje esté sesgado hacia la categoría de artículos no relevantes, ya que hay muy pocos ejemplos de artículos "relevantes".
Razón 3 Quizá necesitemos un algoritmo de aprendizaje mejor.
Razón 4 Quizá necesitemos un mecanismo mejor de preprocesamiento y extracción de rasgos.
Razón 5 Quizá debamos intentar ajustar los parámetros del clasificador y los hiperparámetros.

Veamos cómo mejorar nuestro rendimiento en la clasificación abordando algunas de sus posibles razones. Una forma de abordar la Razón 1 es reducir el ruido en los vectores de características. El enfoque del ejemplo de código anterior tenía cerca de 40.000 características (consulta el cuaderno Jupyter para más detalles). Un gran número de características introduce escasez; es decir, la mayoría de las características del vector de características son cero, y sólo unos pocos valores son distintos de cero. Esto, a su vez, afecta a la capacidad de aprendizaje del algoritmo de clasificación de textos. Veamos qué ocurre si lo restringimos a 5.000 y volvemos a ejecutar el proceso de entrenamiento y evaluación. Para ello, debemos cambiar la instanciación CountVectorizer en el proceso, como se muestra en el fragmento de código siguiente, y repetir todos los pasos:

vect = CountVectorizer(preprocessor=clean, max_features=5000) #Step-1
X_train_dtm = vect.fit_transform(X_train)#combined step 2 and 3
X_test_dtm = vect.transform(X_test)
nb = MultinomialNB() #instantiate a Multinomial Naive Bayes model
%time nb.fit(X_train_dtm, y_train)
#train the model(timing it with an IPython "magic command")
y_pred_class = nb.predict(X_test_dtm)
#make class predictions for X_test_dtm
print("Accuracy: ", metrics.accuracy_score(y_test, y_pred_class))

La Figura 4-5 muestra la nueva matriz de confusión con este ajuste.

Ahora, claramente, aunque el rendimiento medio parece menor que antes, la identificación correcta de artículos relevantes aumentó más de un 20%. Llegados a este punto, cabe preguntarse si esto es lo que queremos. La respuesta a esa pregunta depende del problema que intentemos resolver. Si nos importa hacerlo razonablemente bien con la identificación de artículos no relevantes y hacerlo lo mejor posible con la identificación de artículos relevantes, o hacerlo igual de bien con ambas, podríamos concluir que reducir el tamaño del vector de características con el clasificador Naive Bayes fue útil para este conjunto de datos.

Improved classification performance with Naive Bayes and feature selection
Figura 4-5. Mejora del rendimiento de la clasificación con Naive Bayes y selección de características
Consejo

Considera reducir el número de características si son demasiadas para reducir la dispersión de datos.

La razón 2 de nuestra lista era el problema de la inclinación de los datos hacia la clase mayoritaria. Hay varias formas de abordar este problema. Dos enfoques típicos son el sobremuestreo de las instancias pertenecientes a clases minoritarias o el submuestreo de la clase mayoritaria para crear un conjunto de datos equilibrado. Imbalanced-Learn [13] es una biblioteca de Python que incorpora algunos de los métodos de muestreo para abordar este problema. Aunque no profundizaremos aquí en los detalles de esta biblioteca, los clasificadores también tienen un mecanismo incorporado para abordar estos conjuntos de datos desequilibrados. Veremos cómo utilizarlo tomando otro clasificador, la regresión logística, en el siguiente subapartado.

Consejo

El desequilibrio de clases es una de las razones más comunes para que un clasificador no funcione bien. Debemos comprobar siempre si éste es el caso de nuestra tarea y abordarlo.

Para abordar la Razón 3, probemos a utilizar otros algoritmos, empezando por la regresión logística.

Regresión logística

Cuando describimos el clasificador Naive Bayes, mencionamos que aprende la probabilidad de un texto para cada clase y elige la de máxima probabilidad. Un clasificador de este tipo se denomina clasificador generativo. En cambio, hay un clasificador discriminativo que pretende aprender la distribución de probabilidad sobre todas las clases. La regresión logística es un ejemplo de clasificador discriminativo y se utiliza habitualmente en la clasificación de textos, como línea de base en investigación y como MVP en escenarios industriales del mundo real.

A diferencia de Naive Bayes, que estima las probabilidades basándose en la aparición de características en las clases, la regresión logística "aprende" los pesos de las características individuales basándose en lo importantes que son para tomar una decisión de clasificación. El objetivo de la regresión logística es aprender un separador lineal entre clases en los datos de entrenamiento con el fin de maximizar la probabilidad de los datos. Este "aprendizaje" de las ponderaciones de las características y de la distribución de probabilidad sobre todas las clases se realiza mediante una función llamada "logística", y (de ahí su nombre) regresión logística [14].

Tomemos el vector de características de 5.000 dimensiones del último paso del ejemplo de Naive Bayes y entrenemos un clasificador de regresión logística en lugar de Naive Bayes. El fragmento de código siguiente muestra cómo utilizar la regresión logística para esta tarea:

from sklearn.linear_model import LogisticRegression 
logreg = LogisticRegression(class_weight="balanced")
logreg.fit(X_train_dtm, y_train) 
y_pred_class = logreg.predict(X_test_dtm)
print("Accuracy: ", metrics.accuracy_score(y_test, y_pred_class))

El resultado es un clasificador con una precisión del 73,7%. La Figura 4-6 muestra la matriz de confusión con este enfoque.

Nuestra instanciación del clasificador de regresión logística tiene un argumento class_weight, al que se le da un valor “balanced”. Esto indica al clasificador que aumente las ponderaciones de las clases en proporción inversa al número de muestras de esa clase. Así, esperamos ver un mejor rendimiento para las clases menos representadas. Podemos experimentar con este código eliminando ese argumento y volviendo a entrenar al clasificador, para observar una caída (de aproximadamente un 5%) en la celda inferior derecha de la matriz de confusión. Sin embargo, la regresión logística parece funcionar claramente peor que Naive Bayes en este conjunto de datos.

La razón 3 de nuestra lista era: "Quizá necesitemos un algoritmo de aprendizaje mejor". Esto da lugar a la pregunta "¿Qué es un algoritmo de aprendizaje mejor?" Una regla general cuando se trabaja con enfoques de ML es que no hay un algoritmo que aprenda bien en todos los conjuntos de datos. Un enfoque habitual es experimentar con varios algoritmos y compararlos.

Classification performance with logistic regression
Figura 4-6. Rendimiento de la clasificación con regresión logística

Veamos si esta idea nos ayuda sustituyendo la regresión logística por otro conocido algoritmo de clasificación que demostró ser útil para varias tareas de clasificación de textos, llamado "máquina de vectores de soporte".

Máquina de vectores de apoyo

Hemos descrito la regresión logística como un clasificador discriminativo que aprende los pesos de las características individuales y predice una distribución de probabilidad sobre las clases. Una máquina de vectores de soporte (SVM), inventada a principios de los años 60, es un clasificador discriminativo como la regresión logística. Sin embargo, a diferencia de la regresión logística, su objetivo es buscar un hiperplano óptimo en un espacio de mayor dimensión, que pueda separar las clases de los datos con un margen máximo posible. Además, las SVM son capaces de aprender incluso separaciones no lineales entre clases, a diferencia de la regresión logística. Sin embargo, también pueden tardar más en entrenarse.

Las SVM existen en varios sabores en sklearn. Veamos cómo se utiliza uno de ellos manteniendo todo lo demás igual y modificando las características máximas a 1.000 en lugar de las 5.000 del ejemplo anterior. Restringimos a 1.000 las características, teniendo en cuenta el tiempo que tarda en entrenarse un algoritmo SVM. El fragmento de código siguiente muestra cómo hacerlo, y la Figura 4-7 muestra la matriz de confusión resultante:

from sklearn.svm import LinearSVC
vect = CountVectorizer(preprocessor=clean, max_features=1000) #Step-1
X_train_dtm = vect.fit_transform(X_train)#combined step 2 and 3
X_test_dtm = vect.transform(X_test)
classifier = LinearSVC(class_weight='balanced') #notice the “balanced” option
classifier.fit(X_train_dtm, y_train) #fit the model with training data
y_pred_class = classifier.predict(X_test_dtm)
print("Accuracy: ", metrics.accuracy_score(y_test, y_pred_class))
Confusion matrix for classification with SVM
Figura 4-7. Matriz de confusión para la clasificación con SVM

En comparación con la regresión logística, las SVM parecen haber obtenido mejores resultados con la categoría de artículos relevantes, aunque, entre este pequeño conjunto de experimentos que hicimos, Naive Bayes, con el conjunto más pequeño de características, parece ser el mejor clasificador para este conjunto de datos.

Todos los ejemplos de esta sección demuestran cómo los cambios en los distintos pasos afectaron al rendimiento de la clasificación y cómo interpretar los resultados. Evidentemente, excluimos muchas otras posibilidades, como explorar otros algoritmos de clasificación de textos, cambiar distintos parámetros de varios clasificadores, idear mejores métodos de preprocesamiento, etc. Las dejamos como ejercicios adicionales para el lector, utilizando el cuaderno como patio de recreo. Un proyecto de clasificación de textos del mundo real implica explorar múltiples opciones como ésta, empezando por el enfoque más sencillo en términos de modelado, implementación y escalado, y aumentando gradualmente la complejidad. Nuestro objetivo final es construir el clasificador que mejor satisfaga nuestras necesidades empresariales dadas todas las demás limitaciones.

Consideremos ahora una parte de la Razón 4 de la Tabla 4-1: una mejor representación de las características. Hasta ahora, en este capítulo, hemos utilizado características BoW. Veamos cómo podemos utilizar otras técnicas de representación de rasgos que vimos en el Capítulo 3 para la clasificación de textos.

Uso de incrustaciones neuronales en la clasificación de textos

En la segunda mitad del Capítulo 3, analizamos las técnicas de ingeniería de rasgos mediante redes neuronales, como las incrustaciones de palabras, de caracteres y de documentos. La ventaja de utilizar características basadas en incrustaciones es que crean una representación de características densa y de baja dimensión, en lugar de la estructura dispersa y de alta dimensión de BoW/TF-IDF y otras características similares. Hay distintas formas de diseñar y utilizar características basadas en incrustaciones neuronales. En esta sección, vamos a ver algunas formas de utilizar dichas representaciones de incrustación para la clasificación de textos .

Incrustación de palabras

Las palabras y los n-gramas se han utilizado principalmente como características en la clasificación de textos durante mucho tiempo. Se han propuesto diferentes formas de vectorizar las palabras, y en la última sección hemos utilizado una de estas representaciones, CountVectorizer. En los últimos años, las arquitecturas basadas en redes neuronales se han hecho populares para "aprender" representaciones de palabras, que se conocen como "incrustaciones de palabras". En el Capítulo 3 estudiamos algunas de las intuiciones que hay detrás de esto. Veamos ahora cómo utilizar las incrustaciones de palabras como características para la clasificación de textos. Utilizaremos el conjunto de datos de frases etiquetadas con sentimientos del repositorio de la UCI, que consta de 1.500 frases con sentimientos positivos y 1.500 con sentimientos negativos de Amazon, Yelp e IMDB. Todos los pasos se detallan en el cuaderno Ch4/Word2Vec_Example.ipynb. Repasemos los pasos importantes y en qué difiere este enfoque de los procedimientos de la sección anterior.

Cargar y preprocesar los datos de texto sigue siendo un paso habitual. Sin embargo, en lugar de vectorizar los textos utilizando características basadas en BoW, ahora nos basaremos en modelos neuronales de incrustación. Como ya hemos dicho, utilizaremos un modelo de incrustación preentrenado. Word2vec es un algoritmo popular que ya comentamos en el Capítulo 3 para entrenar modelos de incrustación de palabras. Hay varios modelos Word2vec preentrenados y entrenados con grandes corpus disponibles en Internet. Aquí utilizaremos el de Google [15]. El siguiente fragmento de código muestra cómo cargar este modelo en Python utilizando gensim:

data_path= "/your/folder/path"
path_to_model = os.path.join(data_path,'GoogleNews-vectors-negative300.bin')
training_data_path = os.path.join(data_path, "sentiment_sentences.txt")
#Load W2V model. This will take some time.
w2v_model = KeyedVectors.load_word2vec_format(path_to_model, binary=True)
print('done loading Word2Vec')

Se trata de un gran modelo que puede verse como un diccionario en el que las claves son palabras del vocabulario y los valores son sus representaciones de incrustación aprendidas. Dada una palabra de consulta, si la incrustación de la palabra está presente en el diccionario, devolverá lo mismo. ¿Cómo utilizamos esta incrustación preaprendida para representar características? Como vimos en el Capítulo 3, hay varias formas de hacerlo. Un método sencillo consiste en promediar las incrustaciones de las palabras individuales del texto. El fragmento de código siguiente muestra una función sencilla para hacerlo:

# Creating a feature vector by averaging all embeddings for all sentences
def embedding_feats(list_of_lists):
    DIMENSION = 300
    zero_vector = np.zeros(DIMENSION)
    feats = []
    for tokens in list_of_lists:
          feat_for_this =  np.zeros(DIMENSION)
          count_for_this = 0
          for token in tokens:
                     if token in w2v_model:
                          feat_for_this += w2v_model[token]
                          count_for_this +=1
          feats.append(feat_for_this/count_for_this)         
    return feats

train_vectors = embedding_feats(texts_processed)
print(len(train_vectors))

Ten en cuenta que sólo utiliza incrustaciones para las palabras que están presentes en el diccionario. Ignora las palabras para las que no hay incrustaciones. Además, ten en cuenta que el código anterior dará un único vector con componentes DIMENSION(=300). Tratamos el vector de incrustación resultante como el vector de características que representa todo el texto. Una vez realizada esta ingeniería de características, el paso final es similar al que hicimos en la sección anterior: utilizar estas características y entrenar un clasificador. Lo dejamos como ejercicio para el lector (consulta el cuaderno para ver el código completo).

Cuando se entrenaron con un clasificador de regresión logística, estas características dieron una precisión de clasificación del 81% en nuestro conjunto de datos (para más detalles, consulta el cuaderno). Teniendo en cuenta que sólo utilizamos un modelo de incrustación de palabras existente y que sólo seguimos unos pasos básicos de preprocesamiento, ¡es un gran modelo para tener como referencia! En el Capítulo 3 vimos que hay otros enfoques de incrustación preentrenados, como GloVe, con los que se puede experimentar para este enfoque. Gensim, que hemos utilizado en este ejemplo, también permite entrenar nuestras propias incrustaciones de palabras si es necesario. Si estamos trabajando en un dominio personalizado cuyo vocabulario es muy diferente del de las incrustaciones de noticias preentrenadas que hemos utilizado aquí, tendría sentido entrenar nuestras propias incrustaciones para extraer características.

Para decidir si entrenar nuestras propias incrustaciones o utilizar incrustaciones preentrenadas, una buena regla general es calcular el solapamiento del vocabulario. Si el solapamiento entre el vocabulario de nuestro dominio personalizado y el de las incrustaciones de palabras preentrenadas es superior al 80%, las incrustaciones de palabras preentrenadas tienden a dar buenos resultados en la clasificación de textos.

Un factor importante que hay que tener en cuenta al implementar modelos con enfoques de extracción de características basados en la incrustación es que los modelos de incrustación aprendidos o preentrenados tienen que almacenarse y cargarse en la memoria mientras se utilizan estos enfoques. Si el modelo en sí es voluminoso (por ejemplo, el modelo preentrenado que utilizamos ocupa 3,6 GB), debemos tenerlo en cuenta en nuestras necesidades de implementación.

Incrustación de subpalabras y texto rápido

Las incrustaciones de palabras, como su nombre indica, tratan sobre representaciones de palabras. Incluso las incrustaciones estándar parecen funcionar bien en tareas de clasificación, como hemos visto antes. Sin embargo, si una palabra de nuestro conjunto de datos no estaba presente en el vocabulario del modelo preentrenado, ¿cómo obtendremos una representación para esa palabra? Este problema se conoce popularmente como fuera de vocabulario (OOV). En nuestro ejemplo anterior, nos limitamos a ignorar esas palabras de la extracción de características. ¿Hay alguna forma mejor?

Ya hablamos de las incrustaciones fastText [16] en el Capítulo 3. Se basan en la idea de enriquecer las incrustaciones de palabras con información a nivel de subpalabra. Así, la representación de incrustación de cada palabra se representa como una suma de las representaciones de n-gramas de caracteres individuales. Aunque esto pueda parecer un proceso más largo en comparación con la mera estimación de las incrustaciones a nivel de palabra, tiene dos ventajas:

  • Este enfoque puede manejar palabras que no aparecen en los datos de entrenamiento (OOV).

  • La aplicación facilita un aprendizaje extremadamente rápido incluso en corpus muy grandes .

Aunque fastText es una biblioteca de uso general para aprender las incrustaciones, también es compatible con la clasificación de texto estándar, ya que proporciona entrenamiento y prueba del clasificador de extremo a extremo; es decir, no tenemos que manejar la extracción de características por separado. El resto de esta subsección muestra cómo utilizar el clasificador fastText [17] para la clasificación de textos. Trabajaremos con el conjunto de datos DBpedia [18]. Se trata de un conjunto de datos equilibrado que consta de 14 clases, con 40.000 ejemplos de entrenamiento y 5.000 de prueba por clase. Por tanto, el tamaño total del conjunto de datos es de 560.000 puntos de datos de entrenamiento y 70.000 de prueba. Claramente, se trata de un conjunto de datos mucho mayor que el que vimos antes. ¿Podemos construir un modelo de entrenamiento rápido utilizando fastText? ¡Vamos a comprobarlo!

Los conjuntos de entrenamiento y prueba se proporcionan como archivos CSV en este conjunto de datos. Por tanto, el primer paso consiste en leer estos archivos en tu entorno Python y limpiar el texto para eliminar caracteres extraños, de forma similar a lo que hicimos en los pasos de preprocesamiento para los otros ejemplos de clasificadores que hemos visto hasta ahora. Una vez hecho esto, el proceso para utilizar fastText es bastante sencillo. El fragmento de código siguiente muestra un modelo fastText sencillo. El proceso paso a paso se detalla en el cuaderno Jupyter asociado(Ch4/FastText_Example.ipynb):

## Using fastText for feature extraction and training
from fasttext import supervised
"""fastText expects and training file (csv), a model name as input arguments.
label_prefix refers to the prefix before label string in the dataset.
default is __label__. In our dataset, it is __class__.
There are several other parameters which can be seen in:
https://pypi.org/project/fasttext/
"""
model = supervised(train_file, 'temp', label_prefix="__class__")
results = model.test(test_file)
print(results.nexamples, results.precision, results.recall)

Si ejecutamos este código en el cuaderno, nos daremos cuenta de que, a pesar de que se trata de un conjunto de datos enorme y de que le hemos dado al clasificador el texto en bruto y no el vector de características, el entrenamiento tarda sólo unos segundos, ¡y obtenemos cerca de un 98% de precisión y recuperación! Como ejercicio, intenta construir un clasificador utilizando el mismo conjunto de datos pero con características BoW o de incrustación de palabras y algoritmos como la regresión logística. ¡Fíjate en cuánto tardan los pasos individuales de extracción de características y aprendizaje de la clasificación!

Cuando disponemos de un gran conjunto de datos y el aprendizaje parece inviable con los métodos descritos hasta ahora, fastText es una buena opción para establecer una base de trabajo sólida. Sin embargo, hay que tener en cuenta una preocupación al utilizar fastText, como en el caso de las incrustaciones de Word2vec: utiliza incrustaciones de n-gramas de caracteres preentrenados. Por tanto, cuando guardamos el modelo entrenado, lleva consigo todo el diccionario de incrustación de n-gramas de caracteres. Esto da lugar a un modelo voluminoso y puede provocar problemas de ingeniería. Por ejemplo, el modelo guardado con el nombre "temp" en el fragmento de código anterior tiene un tamaño cercano a 450 MB. Sin embargo, la implementación de fastText también incluye opciones para reducir la huella de memoria de sus modelos de clasificación con una reducción mínima del rendimiento de la clasificación [19]. Para ello, realiza una poda del vocabulario y utiliza algoritmos de compresión. Explorar estas posibilidades podría ser una buena opción en los casos en que el gran tamaño de los modelos sea una limitación.

Consejo

fastText es extremadamente rápido de entrenar y muy útil para establecer líneas de base sólidas. El inconveniente es el tamaño del modelo.

Esperamos que esta discusión ofrezca una buena visión general de la utilidad de fastText para la clasificación de textos. Lo que mostramos aquí es un modelo de clasificación por defecto sin ningún ajuste de los hiperparámetros. La documentación de fastText contiene más información sobre las distintas opciones para ajustar tu clasificador y sobre cómo entrenar representaciones de incrustación personalizadas para el conjunto de datos que desees. Sin embargo, las dos representaciones de incrustación que hemos visto hasta ahora aprenden una representación de palabras y caracteres y las reúnen para formar una representación del texto. Veamos cómo aprender directamente la representación de un documento utilizando el enfoque Doc2vec que comentamos en el Capítulo 3.

Incrustación de documentos

En el esquema de incrustación Doc2vec, aprendemos una representación directa para todo el documento (frase/párrafo) en lugar de para cada palabra. Al igual que utilizamos la incrustación de palabras y caracteres como características para realizar la clasificación de textos, también podemos utilizar Doc2vec como mecanismo de representación de características. Como no existen modelos preentrenados que funcionen con la última versión de Doc2vec [20], vamos a ver cómo construir nuestro propio modelo Doc2vec y utilizarlo para la clasificación de textos.

Utilizaremos un conjunto de datos llamado "Análisis de Sentimiento: Emotion in Text" de figure-eight.com [9], que contiene 40.000 tweets etiquetados con 13 etiquetas que significan diferentes emociones. Tomemos las tres etiquetas más frecuentes de este conjunto de datos -neutral, preocupación, felicidad- y construyamos un clasificador de texto para clasificar los nuevos tweets en una de estas tres clases. El cuaderno de esta subsección(Ch4/Doc2Vec_Example.ipynb) te guía por los pasos necesarios para utilizar Doc2vec en la clasificación de textos y te proporciona el conjunto de datos.

Tras cargar el conjunto de datos y tomar un subconjunto de las tres etiquetas más frecuentes, un paso importante a tener en cuenta aquí es el preprocesamiento de los datos. ¿Qué hay de diferente aquí en comparación con los ejemplos anteriores? ¿Por qué no podemos seguir el mismo procedimiento que antes? Hay algunas cosas que son diferentes en los tweets en comparación con los artículos de noticias u otros textos similares, como ya comentamos brevemente en el Capítulo 2 cuando hablamos del preprocesamiento de textos. En primer lugar, son muy cortos. En segundo lugar, puede que nuestros tokenizadores tradicionales no funcionen bien con los tweets, ya que dividen los emoticonos, los hashtags, los handles de Twitter, etc., en múltiples tokens. Estas necesidades especializadas han dado lugar a una gran cantidad de investigación en PNL para Twitter en el pasado reciente, que ha dado lugar a varias opciones de preprocesamiento para los tweets. Una de estas soluciones es TweetTokenizer , implementada en la biblioteca NLTK [21] en Python. Hablaremos más sobre este tema en el Capítulo 8. Por ahora, veamos cómo podemos utilizar un TweetTokenizer en el siguiente fragmento de código:

tweeter = TweetTokenizer(strip_handles=True,preserve_case=False)
mystopwords = set(stopwords.words("english"))

#Function to pre-process and tokenize tweets
def preprocess_corpus(texts):
    def remove_stops_digits(tokens):
    #Nested function to remove stopwords and digits
          return [token for token in tokens if token not in mystopwords 
                  and not token.isdigit()]
    return [remove_stops_digits(tweeter.tokenize(content)) for content in texts]

mydata = preprocess_corpus(df_subset['content'])
mycats = df_subset['sentiment']

El siguiente paso en este proceso es entrenar un modelo Doc2vec para aprender las representaciones de los tweets. Lo ideal sería que cualquier gran conjunto de datos de tweets sirviera para este paso. Sin embargo, como no disponemos de un corpus de este tipo, dividiremos nuestro conjunto de datos en entrenamiento-prueba y utilizaremos los datos de entrenamiento para aprender las representaciones Doc2vec. La primera parte de este proceso consiste en convertir los datos a un formato legible por la aplicación Doc2vec, lo que puede hacerse utilizando la clase TaggedDocument . Se utiliza para representar un documento como una lista de tokens, seguida de una "etiqueta", que en su forma más simple puede ser simplemente el nombre de archivo o ID del documento. Sin embargo, Doc2vec por sí mismo también puede utilizarse como clasificador del vecino más próximo para problemas de clasificación multiclase y multietiqueta utilizando . Dejaremos esto como ejercicio exploratorio para el lector. Veamos ahora cómo entrenar un clasificador Doc2vec para tweets mediante el fragmento de código que aparece a continuación:

#Prepare training data in doc2vec format:
d2vtrain = [TaggedDocument((d),tags=[str(i)]) for i, d in enumerate(train_data)]
#Train a doc2vec model to learn tweet representations. Use only training data!!
model = Doc2Vec(vector_size=50, alpha=0.025, min_count=10, dm =1, epochs=100)
model.build_vocab(d2vtrain)
model.train(d2vtrain, total_examples=model.corpus_count, epochs=model.epochs)
model.save("d2v.model")
print("Model Saved")

El entrenamiento de Doc2vec implica elegir varios parámetros, como se ve en la definición del modelo en el fragmento de código anterior. vector_size se refiere a la dimensionalidad de las incrustaciones aprendidas; alpha es la tasa de aprendizaje; min_count es la frecuencia mínima de palabras que permanecen en el vocabulario; dm, que significa memoria distribuida, es uno de los aprendices de representación implementados en Doc2vec (el otro es dbow, o bolsa distribuida de palabras); y epochs es el número de iteraciones de entrenamiento. Hay algunos parámetros más que se pueden personalizar. Aunque existen algunas directrices sobre la elección de los parámetros óptimos para el entrenamiento de los modelos Doc2vec [22], éstas no están validadas exhaustivamente, y no sabemos si las directrices funcionan para los tweets.

La mejor forma de abordar esta cuestión es explorar una serie de valores para los que nos importan (por ejemplo, dm frente a dbow, tamaños de vector, velocidad de aprendizaje) y comparar varios modelos. ¿Cómo comparamos estos modelos, ya que sólo aprenden la representación del texto? Una forma de hacerlo es empezar a utilizar estas representaciones aprendidas en una tarea posterior: en este caso, la clasificación de textos. La función infer_vector de Doc2vec puede utilizarse para inferir la representación vectorial de un texto dado utilizando un modelo preentrenado. Dado que existe cierto grado de aleatoriedad debido a la elección de los hiperparámetros, los vectores inferidos difieren cada vez que los extraemos. Por eso, para obtener una representación estable, la ejecutamos varias veces (denominadas pasos) y agregamos los vectores. Utilicemos el modelo aprendido para inferir características para nuestros datos y entrenar un clasificador de regresión logística:

#Infer the feature representation for training and test data using 
#the trained model
model= Doc2Vec.load("d2v.model")
#Infer in multiple steps to get a stable representation
train_vectors =  [model.infer_vector(list_of_tokens, steps=50)
              for list_of_tokens in train_data]
test_vectors = [model.infer_vector(list_of_tokens, steps=50)
              for list_of_tokens in test_data]
myclass = LogisticRegression(class_weight="balanced") 
#because classes are not balanced
myclass.fit(train_vectors, train_cats)
preds = myclass.predict(test_vectors)
print(classification_report(test_cats, preds))

Ahora bien, el rendimiento de este modelo parece bastante pobre, ya que obtiene una puntuación F1 de 0,51 en un corpus razonablemente grande, con sólo tres clases. Hay un par de interpretaciones para este pobre resultado. En primer lugar, a diferencia de los artículos de noticias completos o incluso de las frases bien formadas, los tweets contienen muy pocos datos por instancia. Además, la gente escribe con una gran variedad ortográfica y sintáctica cuando tuitea. Hay muchos emoticonos de distintas formas. Nuestra representación de características debe ser capaz de captar estos aspectos. Aunque afinar los algoritmos buscando el mejor modelo en un amplio espacio de parámetros puede ser útil, una alternativa podría ser explorar representaciones de rasgos específicas para cada problema, como comentamos en el Capítulo 3. Veremos cómo hacer esto para los tweets en el Capítulo 8. Un punto importante a tener en cuenta al utilizar Doc2vec es el mismo que para fastText: si tenemos que utilizar Doc2vec para la representación de rasgos, tenemos que almacenar el modelo que aprendió la representación. Aunque no suele ser tan voluminoso como fastText, tampoco es tan rápido de entrenar. Hay que tener en cuenta y comparar estas ventajas y desventajas antes de tomar una decisión de implementación.

Hasta ahora, hemos visto una serie de representaciones de características y cómo desempeñan un papel en la clasificación de textos mediante algoritmos de ML. Pasemos ahora a una familia de algoritmos que se hizo popular en los últimos años, conocida como "aprendizaje profundo".

Aprendizaje profundo para la clasificación de textos

Como comentamos en el Capítulo 1, el aprendizaje profundo es una familia de algoritmos de aprendizaje automático en los que el aprendizaje se produce a través de diferentes tipos de arquitecturas de redes neuronales multicapa. En los últimos años, ha mostrado notables mejoras en tareas estándar de aprendizaje automático, como la clasificación de imágenes, el reconocimiento del habla y la traducción automática. Esto ha provocado un interés generalizado en el uso del aprendizaje profundo para diversas tareas, incluida la clasificación de textos. Hasta ahora, hemos visto cómo entrenar diferentes clasificadores de aprendizaje automático, utilizando BoW y diferentes tipos de representaciones de incrustación. Ahora vamos a ver cómo utilizar arquitecturas de aprendizaje profundo para la clasificación de textos.

Dos de las arquitecturas de redes neuronales más utilizadas para la clasificación de textos son las redes neuronales convolucionales (CNN) y las redes neuronales recurrentes (RNN). Las redes de memoria a corto plazo (LSTM) son una forma popular de RNN. Los enfoques recientes también implican empezar con grandes modelos lingüísticos preentrenados y ajustarlos para la tarea en cuestión. En esta sección, aprenderemos a entrenar CNN y LSTM y a ajustar un modelo lingüístico preentrenado para la clasificación de textos utilizando el conjunto de datos de clasificación de sentimientos IMDB [23]. Ten en cuenta que una discusión detallada sobre cómo funcionan las arquitecturas de redes neuronales está fuera del alcance de este libro. Los lectores interesados pueden leer el libro de texto de Goodfellow et al. [24] para una discusión teórica general y el libro de Goldberg [25] para usos específicos de la PNL de las arquitecturas de redes neuronales. El libro de Jurafsky y Martin [12] también ofrece una breve pero concisa visión general de los distintos métodos de redes neuronales para la PNL.

El primer paso para entrenar cualquier modelo ML o DL es definir una representación de características. Este paso ha sido relativamente sencillo en los enfoques que hemos visto hasta ahora, con vectores BoW o incrustados. Sin embargo, para las redes neuronales, necesitamos un procesamiento adicional de los vectores de entrada, como vimos en el Capítulo 3. Recapitulemos rápidamente los pasos necesarios para convertir los datos de entrenamiento y de prueba en un formato adecuado para las capas de entrada de la red neuronal:

  1. Tokeniza los textos y conviértelos en vectores de índices de palabras.

  2. Rellena las secuencias de texto para que todos los vectores de texto tengan la misma longitud.

  3. Asigna cada índice de palabra a un vector de incrustación. Lo hacemos multiplicando los vectores de índice de palabras por la matriz de incrustación. La matriz de incrustación puede rellenarse utilizando incrustaciones preentrenadas o puede entrenarse para incrustaciones en este corpus.

  4. Utiliza la salida del Paso 3 como entrada de una arquitectura de red neuronal.

Una vez hecho esto, podemos proceder a la especificación de arquitecturas de redes neuronales y al entrenamiento de clasificadores con ellas. El cuaderno Jupyter asociado a esta sección(Ch4/DeepNN_Example.ipynb) te guiará por todo el proceso, desde el preprocesamiento del texto hasta el entrenamiento y la evaluación de la red neuronal. Utilizaremos Keras, una biblioteca de DL basada en Python. El fragmento de código siguiente ilustra los pasos 1 y 2:

#Vectorize these text samples into a 2D integer tensor using Keras Tokenizer.
#Tokenizer is fit on training data only, and that is used to tokenize both train 
#and test data.
tokenizer = Tokenizer(num_words=MAX_NUM_WORDS)
tokenizer.fit_on_texts(train_texts)
train_sequences = tokenizer.texts_to_sequences(train_texts) 
test_sequences = tokenizer.texts_to_sequences(test_texts)
word_index = tokenizer.word_index
print('Found %s unique tokens.' % len(word_index))
#Converting this to sequences to be fed into neural network. Max seq. len is 
#1000 as set earlier. Initial padding of 0s, until vector is of 
#size MAX_SEQUENCE_LENGTH
trainvalid_data = pad_sequences(train_sequences, maxlen=MAX_SEQUENCE_LENGTH)
test_data = pad_sequences(test_sequences, maxlen=MAX_SEQUENCE_LENGTH)
trainvalid_labels = to_categorical(np.asarray(train_labels))
test_labels = to_categorical(np.asarray(test_labels))

Paso 3: Si queremos utilizar incrustaciones preentrenadas para convertir los datos de entrenamiento y de prueba en una matriz de incrustación, como hicimos en los ejemplos anteriores con Word2vec y fastText, tenemos que descargarlas y utilizarlas para convertir nuestros datos en el formato de entrada para las redes neuronales. El siguiente fragmento de código muestra un ejemplo de cómo hacerlo utilizando las incrustaciones GloVe, que se presentaron en el Capítulo 3. Las incrustaciones GloVe vienen con múltiples dimensionalidades, y aquí elegimos 100 como nuestra dimensión. El valor de la dimensionalidad es un hiperparámetro, y también podemos experimentar con otras dimensiones:i

embeddings_index = {}
with open(os.path.join(GLOVE_DIR, 'glove.6B.100d.txt')) as f:
    for line in f:
          values = line.split()
          word = values[0]
          coefs = np.asarray(values[1:], dtype='float32')
          embeddings_index[word] = coefs

num_words = min(MAX_NUM_WORDS, len(word_index)) + 1
embedding_matrix = np.zeros((num_words, EMBEDDING_DIM))
for word, i in word_index.items():
    if i > MAX_NUM_WORDS:
          continue
    embedding_vector = embeddings_index.get(word)
    if embedding_vector is not None:
          embedding_matrix[i] = embedding_vector

Paso 4: ¡Ya estamos listos para entrenar modelos DL para la clasificación de textos! Las arquitecturas DL constan de una capa de entrada, una capa de salida y varias capas ocultas entre ambas. Dependiendo de la arquitectura, se utilizan distintas capas ocultas. La capa de entrada para la entrada textual suele ser una capa oculta. La capa de salida, especialmente en el contexto de la clasificación de textos, es una capa softmax con salida categórica. Si queremos entrenar la capa de entrada en lugar de utilizar incrustaciones preentrenadas, la forma más sencilla es llamar a la clase de capa Embedding en Keras, especificando las dimensiones de entrada y salida. Sin embargo, como queremos utilizar incrustaciones preentrenadas, debemos crear una capa de incrustación personalizada que utilice la matriz de incrustación que acabamos de construir. El siguiente fragmento de código muestra cómo hacerlo:

embedding_layer = Embedding(num_words, EMBEDDING_DIM,
                        embeddings_initializer=Constant(embedding_matrix),
                        input_length=MAX_SEQUENCE_LENGTH,
                        trainable=False)
print("Preparing of embedding matrix is done")

Esto servirá como capa de entrada para cualquier red neuronal que queramos utilizar (CNN o LSTM). Ahora que sabemos cómo preprocesar la entrada y definir una capa de entrada, pasemos a especificar el resto de la arquitectura de la red neuronal utilizando CNNs y LSTMs.

CNN para la clasificación de textos

Veamos ahora cómo definir, entrenar y evaluar un modelo CNN para la clasificación de textos. Las CNN suelen constar de una serie de capas de convolución y agrupación como capas ocultas. En el contexto de la clasificación de textos, se puede considerar que las CNN aprenden las características más útiles de la bolsa de palabras/gramas, en lugar de tomar toda la colección de palabras/gramas como características, como hicimos anteriormente en este capítulo. Como nuestro conjunto de datos sólo tiene dos clases -positiva y negativa-, la capa de salida tiene dos salidas, con la función de activación softmax. Definiremos una CNN con tres capas de convolución utilizando la clase de modelo Sequential en Keras, que nos permite especificar modelos DL como una pila secuencial de capas, una tras otra. Una vez especificadas las capas y sus funciones de activación, la siguiente tarea consiste en definir otros parámetros importantes, como el optimizador, la función de pérdida y la métrica de evaluación para afinar los hiperparámetros del modelo. Una vez hecho todo esto, el siguiente paso es entrenar y evaluar el modelo. El siguiente fragmento de código muestra una forma de especificar una arquitectura CNN para esta tarea utilizando la biblioteca Keras de Python e imprime los resultados con el conjunto de datos IMDB para este modelo:

print('Define a 1D CNN model.')
cnnmodel = Sequential()
cnnmodel.add(embedding_layer)
cnnmodel.add(Conv1D(128, 5, activation='relu'))
cnnmodel.add(MaxPooling1D(5))
cnnmodel.add(Conv1D(128, 5, activation='relu'))
cnnmodel.add(MaxPooling1D(5))
cnnmodel.add(Conv1D(128, 5, activation='relu'))
cnnmodel.add(GlobalMaxPooling1D())
cnnmodel.add(Dense(128, activation='relu'))
cnnmodel.add(Dense(len(labels_index), activation='softmax'))
cnnmodel.compile(loss='categorical_crossentropy',
                    optimizer='rmsprop',
                    metrics=['acc'])
cnnmodel.fit(x_train, y_train,
          batch_size=128,
          epochs=1, validation_data=(x_val, y_val))
score, acc = cnnmodel.evaluate(test_data, test_labels)
print('Test accuracy with CNN:', acc)

Como puedes ver, tomamos muchas decisiones al especificar el modelo, como las funciones de activación, las capas ocultas, el tamaño de las capas, la función de pérdida, el optimizador, las métricas, las épocas y el tamaño del lote. Aunque hay algunas opciones comúnmente recomendadas, no hay consenso sobre una combinación que funcione mejor para todos los conjuntos de datos y problemas. Un buen enfoque mientras construyes tus modelos es experimentar con diferentes ajustes (es decir, hiperparámetros). Ten en cuenta que todas estas decisiones conllevan algún coste asociado. Por ejemplo, en la práctica, el número de épocas es de 10 o más. Pero eso también aumenta el tiempo necesario para entrenar el modelo. Otra cosa a tener en cuenta es que, si quieres entrenar una capa de incrustación en lugar de utilizar incrustaciones preentrenadas en este modelo, lo único que cambia es la línea cnnmodel.add(embedding_layer). En su lugar, podemos especificar una nueva capa de incrustación como, por ejemplo, cnnmodel.add(Embedding(Param1, Param2)). El fragmento de código siguiente muestra el código y el rendimiento del modelo para lo mismo:

print("Defining and training a CNN model, training embedding layer on the fly 
      instead of using pre-trained embeddings")
cnnmodel = Sequential()
cnnmodel.add(Embedding(MAX_NUM_WORDS, 128))

...
cnnmodel.fit(x_train, y_train,
          batch_size=128,
          epochs=1, validation_data=(x_val, y_val))
score, acc = cnnmodel.evaluate(test_data, test_labels)
print('Test accuracy with CNN:', acc)

Si ejecutamos este código en el cuaderno, observaremos que, en este caso, entrenar la capa de incrustación en nuestro propio conjunto de datos parece dar como resultado una mejor clasificación en los datos de prueba. Sin embargo, si los datos de entrenamiento fueran sustancialmente pequeños, sería mejor ceñirse a las incrustaciones preentrenadas o utilizar las técnicas de adaptación al dominio que veremos más adelante en este capítulo. Veamos cómo entrenar modelos similares utilizando un LSTM.

LSTMs para la clasificación de textos

Como vimos brevemente en el Capítulo 1, las LSTM y otras variantes de las RNN en general se han convertido en los últimos años en la forma preferida de hacer modelado neural del lenguaje. Esto se debe principalmente a que el lenguaje es secuencial por naturaleza y las RNN están especializadas en trabajar con datos secuenciales. La palabra actual de la frase depende de su contexto: las palabras anteriores y posteriores. Sin embargo, cuando modelamos texto utilizando CNNs, este hecho crucial no se tiene en cuenta. Las RNN funcionan según el principio de utilizar este contexto al aprender la representación lingüística o un modelo del lenguaje. De ahí que se sepa que funcionan bien para tareas de PNL. También hay variantes de CNN que pueden tener en cuenta dicho contexto, y las CNN frente a las RNN siguen siendo un área de debate abierta. En esta sección, veremos un ejemplo de uso de RNN para la clasificación de textos. Ahora que ya hemos visto una red neuronal en acción, ¡es relativamente fácil entrenar otra! Sólo tienes que sustituir las partes convolucional y de agrupación por una LSTM en los dos ejemplos de código anteriores. El siguiente fragmento de código muestra cómo entrenar un modelo LSTM utilizando el mismo conjunto de datos IMDB para la clasificación de texto:

print("Defining and training an LSTM model, training embedding layer on the fly")
rnnmodel = Sequential()
rnnmodel.add(Embedding(MAX_NUM_WORDS, 128))
rnnmodel.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2))
rnnmodel.add(Dense(2, activation='sigmoid'))
rnnmodel.compile(loss='binary_crossentropy',
               optimizer='adam',
               metrics=['accuracy'])
print('Training the RNN')
rnnmodel.fit(x_train, y_train,
          batch_size=32,
          epochs=1,
          validation_data=(x_val, y_val))
score, acc = rnnmodel.evaluate(test_data, test_labels,
                          batch_size=32)
print('Test accuracy with RNN:', acc)

Observa que este código tardó mucho más en ejecutarse que el ejemplo de la CNN. Aunque las LSTM son más potentes a la hora de utilizar la naturaleza secuencial del texto, están mucho más hambrientas de datos que las CNN. Por tanto, el menor rendimiento relativo de la LSTM en un conjunto de datos no tiene por qué interpretarse necesariamente como un defecto del propio modelo. Es posible que la cantidad de datos de que disponemos no sea suficiente para aprovechar todo el potencial de una LSTM. Como en el caso de las CNN, varios parámetros e hiperparámetros desempeñan papeles importantes en el rendimiento del modelo, y siempre es una buena práctica explorar varias opciones y comparar distintos modelos antes de decantarse por uno.

Clasificación de textos con modelos lingüísticos grandes y preentrenados

En los dos últimos años, se han producido grandes mejoras en el uso de representaciones textuales basadas en redes neuronales para tareas de PNL. Hablamos de algunas de ellas en "Representaciones universales del texto". Estas representaciones se han utilizado con éxito para la clasificación de textos en el pasado reciente, ajustando los modelos preentrenados a la tarea y al conjunto de datos dados. BERT, que se mencionó en el Capítulo 3, es un modelo popular utilizado de este modo para la clasificación de textos. Veamos cómo utilizar BERT para la clasificación de textos utilizando el conjunto de datos IMDB que hemos usado antes en esta sección. El código completo está en el cuaderno correspondiente(Ch4/BERT_Clasificación_Sentimientos_IMDB.ipynb).

Utilizaremos ktrain, una envoltura ligera para entrenar y utilizar modelos DL preentrenados utilizando la biblioteca Keras de TensorFlow. ktrain proporciona un proceso sencillo para todos los pasos, desde la obtención del conjunto de datos y el BERT preentrenado hasta el ajuste fino para la tarea de clasificación. Veamos primero cómo cargar el conjunto de datos mediante el fragmento de código siguiente:

dataset = tf.keras.utils.get_file(
fname="aclImdb.tar.gz",   
origin="http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz",
 extract=True,)

Una vez cargado el conjunto de datos, el siguiente paso es descargar el modelo BERT y preprocesar el conjunto de datos según los requisitos de BERT. El siguiente fragmento de código muestra cómo hacerlo con las funciones de ktrain:

(x_train, y_train), (x_test, y_test), preproc = 
                       text.texts_from_folder(IMDB_DATADIR,maxlen=500,                                                                   
   preprocess_mode='bert',train_test_names=['train','test'],

El siguiente paso es cargar el modelo BERT preentrenado y ajustarlo para este conjunto de datos. Aquí tienes el fragmento de código para hacerlo:

model = text.text_classifier('bert', (x_train, y_train), preproc=preproc)
learner=ktrain.get_learner(model,train_data=(x_train,y_train),    
                          val_data=(x_test, y_test), batch_size=6)
learner.fit_onecycle(2e-5, 4)

Estas tres líneas de código entrenarán un clasificador de texto utilizando el modelo preentrenado BERT. Al igual que con otros ejemplos que hemos visto hasta ahora, necesitaríamos ajustar los parámetros y experimentar mucho para elegir el modelo que mejor funcione. Lo dejamos como ejercicio para el lector.

En esta sección, hemos introducido la idea de utilizar DL para la clasificación de textos mediante dos arquitecturas de red neuronal -CNN y LSTM- y hemos mostrado cómo podemos ajustar un modelo lingüístico preentrenado de última generación (BERT) para un conjunto de datos y una tarea de clasificación determinados. Existen diversas variantes de estas arquitecturas, y los investigadores en PNL proponen nuevos modelos cada día. Hemos visto cómo utilizar un modelo lingüístico preentrenado, el BERT. Existen otros modelos de este tipo, y éste es un campo en constante evolución en la investigación en PNL; el estado de la técnica cambia cada pocos meses (¡o incluso semanas!). Sin embargo, según nuestra experiencia como profesionales del sector, varias tareas de PNL, especialmente la clasificación de textos, siguen utilizando ampliamente varios de los enfoques no basados en LD que hemos descrito anteriormente en el capítulo. Dos razones principales son la falta de grandes cantidades de datos de entrenamiento específicos de la tarea que exigen las redes neuronales y los problemas relacionados con los costes informáticos y de implementación.

Consejo

Los clasificadores de texto basados en DL a menudo no son más que representaciones condensadas de los datos con los que fueron entrenados. Estos modelos suelen ser tan buenos como el conjunto de datos de entrenamiento. En estos casos, seleccionar el conjunto de datos adecuado es aún más importante.

Terminaremos esta sección reiterando lo que ya dijimos al hablar de la cadena de clasificación de textos: en la mayoría de los entornos industriales, siempre tiene sentido empezar con un enfoque más sencillo y fácil de implementar como MVP, e ir incrementando a partir de ahí, teniendo en cuenta las necesidades del cliente y la viabilidad.

Hasta ahora hemos visto varios enfoques para construir modelos de clasificación de textos. A diferencia de los enfoques basados en la heurística, en los que las predicciones pueden justificarse rastreando las reglas aplicadas a la muestra de datos, los modelos de ML se tratan como una caja negra mientras hacen predicciones. Sin embargo, en los últimos tiempos, el tema del ML interpretable ha empezado a cobrar importancia, y ya existen programas que pueden "explicar" las predicciones de un modelo ML. Echemos un vistazo rápido a su aplicación para la clasificación de textos.

Interpretar los modelos de clasificación de textos

En las secciones anteriores, hemos visto cómo entrenar clasificadores de texto utilizando múltiples enfoques. En todos estos ejemplos, tomamos las predicciones del clasificador tal cual, sin buscar explicaciones. De hecho, la mayoría de los casos de uso de la clasificación de textos en el mundo real pueden ser similares: simplemente consumimos la salida del clasificador y no cuestionamos sus decisiones. Por ejemplo, la clasificación del spam: generalmente no buscamos explicaciones de por qué un determinado correo electrónico se clasifica como spam o correo electrónico normal. Sin embargo, puede haber situaciones en las que esas explicaciones sean necesarias.

Consideremos un escenario en el que desarrollamos un clasificador que identifica los comentarios abusivos en un sitio web de foros de discusión. El clasificador identifica los comentarios que son censurables/abusivos y realiza el trabajo de un moderador humano borrándolos o haciéndolos invisibles para los usuarios. Sabemos que los clasificadores no son perfectos y pueden cometer errores. ¿Qué ocurre si el comentarista cuestiona esta decisión de moderación y pide una explicación? En estos casos puede ser útil algún método para "explicar" la decisión de clasificación, señalando qué característica ha provocado dicha decisión. Un método de este tipo también es útil para proporcionar algunas ideas sobre el modelo y cómo puede funcionar con datos del mundo real (en lugar de conjuntos de entrenamiento/prueba), lo que puede dar lugar a modelos mejores y más fiables en el futuro.

A medida que los modelos de ML empezaron a implementarse en aplicaciones del mundo real, creció el interés por la interpretabilidad de los modelos. Investigaciones recientes [26, 27] dieron lugar a herramientas utilizables [28, 29] para interpretar las predicciones de los modelos (especialmente para la clasificación). Lime [28] es una de esas herramientas que intenta interpretar un modelo de clasificación de caja negra aproximándolo con un modelo lineal localmente alrededor de una instancia de entrenamiento dada. La ventaja de esto es que dicho modelo lineal se expresa como una suma ponderada de sus características y es fácil de interpretar para los humanos. Por ejemplo, si hay dos características, f1 y f2, para una instancia de prueba dada de un clasificador binario con las clases A y B, un modelo lineal Lime alrededor de esta instancia podría ser algo así como -0,3 × f1 + 0,4 × f2 con una predicción B. Esto indica que la presencia de la característica f1 afectará negativamente a esta predicción (en 0,3) y la inclinará hacia A. [26] explica esto con más detalle. Veamos ahora cómo puede utilizarse Cal [28] para comprender las predicciones de un clasificador de texto.

Explicar las predicciones del clasificador con cal

Tomemos un modelo que ya construimos anteriormente en este capítulo y veamos cómo la Cal puede ayudarnos a interpretar sus predicciones. El siguiente fragmento de código utiliza el modelo de regresión logística que construimos anteriormente utilizando el conjunto de datos "Tono y relevancia de los artículos de noticias de economía", que clasifica un artículo de noticias determinado como relevante o no relevante, y muestra cómo podemos utilizar Lime (puedes acceder al código completo en el cuaderno Ch4/LimeDemo.ipynb):

from lime import lime_text
from lime.lime_text import LimeTextExplainer
from sklearn.pipeline import make_pipeline

y_pred_prob = classifier.predict_proba(X_test_dtm)[:, 1]
c = make_pipeline(vect, classifier)
mystring = list(X_test)[221] #Take a string from test instance
print(c.predict_proba([mystring])) #Prediction is a "No" here, i.e., not relevant
class_names = ["no", "yes"] #not relevant, relevant
explainer = LimeTextExplainer(class_names=class_names)
exp = explainer.explain_instance(mystring, c.predict_proba, num_features=6)
exp.as_list()

Este código muestra seis características que desempeñaron un papel importante a la hora de hacer esta predicción. Son los siguientes

[('YORK', 0.23416984139912805),
 ('NEW', -0.22724581340890154),
 ('showing', -0.12532906927967377),
 ('AP', -0.08486610147834726),
 ('dropped', 0.07958281943957331),
 ('trend', 0.06567603359316518)]

Así, el resultado del código anterior puede verse como una suma lineal de estas seis características. Esto significaría que, si eliminamos las características "NUEVO" y "mostrando", la predicción debería moverse hacia la clase opuesta, es decir, "relevante/Sí", en 0,35 (la suma de los pesos de estas dos características). Lime también dispone de funciones para visualizar estas predicciones. La Figura 4-8 muestra una visualización de la explicación anterior.

Como se muestra en la figura, la presencia de tres palabras -York, trend y dropped- inclina la predicción hacia el Sí, mientras que las otras tres palabras inclinan la predicción hacia el No. Aparte de algunos usos que hemos mencionado antes, estas visualizaciones de clasificadores también pueden ayudarnos si queremos hacer alguna selección informada de características.

Esperamos que esta breve introducción te haya dado una idea de lo que debes hacer si tienes que explicar las predicciones de un clasificador. También tenemos un cuaderno(Ch4/Lime_RNN.ipynb) que explica las predicciones de un modelo LSTM utilizando Lime, y dejamos esta exploración detallada de Lime como ejercicio para el lector.

Visualization of Lime’s explanation of a classifier’s prediction
Figura 4-8. Visualización de la explicación de Lime sobre la predicción de un clasificador

Aprender sin datos o con menos datos y adaptarse a nuevos dominios

En todos los ejemplos que hemos visto hasta ahora, disponíamos de un conjunto de datos de entrenamiento relativamente grande para la tarea. Sin embargo, en la mayoría de los escenarios del mundo real, esos conjuntos de datos no están fácilmente disponibles. En otros casos, podemos disponer de un conjunto de datos anotados, pero puede que no sea lo suficientemente grande como para entrenar un buen clasificador. También puede darse el caso de que dispongamos de un gran conjunto de datos de, por ejemplo, reclamaciones y solicitudes de clientes para un conjunto de productos, pero se nos pida que adaptemos nuestro clasificador a otro conjunto de productos para el que disponemos de una cantidad muy pequeña de datos (es decir, estamos adaptando un modelo existente a un nuevo dominio). En esta sección, vamos a discutir cómo construir buenos sistemas de clasificación para estos escenarios en los que no tenemos datos o tenemos que adaptarnos a los datos de entrenamiento de un nuevo dominio.

Sin datos de entrenamiento

Supongamos que nos piden que diseñemos un clasificador para segregar las reclamaciones de los clientes de nuestra empresa de comercio electrónico. Se espera que el clasificador enrute automáticamente los correos electrónicos de quejas de los clientes en un conjunto de categorías: facturación, entrega y otras. Si tenemos suerte, puede que descubramos una fuente de grandes cantidades de datos anotados para esta tarea dentro de la organización, en forma de una base de datos histórica de solicitudes de clientes y sus categorías. Si tal base de datos no existe, ¿por dónde deberíamos empezar a construir nuestro clasificador?

El primer paso en un escenario así es crear un conjunto de datos anotados en el que las reclamaciones de los clientes se asignen al conjunto de categorías mencionadas anteriormente. Una forma de abordar esto es hacer que los agentes del servicio de atención al cliente etiqueten manualmente algunas de las reclamaciones y utilizarlas como datos de entrenamiento para nuestro modelo ML. Otro enfoque es el denominado "bootstrapping" o "supervisión débil". Puede haber ciertos patrones de información en las distintas categorías de solicitudes de los clientes. Quizá las solicitudes relacionadas con la facturación mencionen variantes de la palabra "factura", importes en una moneda, etc. Las solicitudes relacionadas con la entrega hablan de envíos, retrasos, etc. Podemos empezar por recopilar algunos de estos patrones y utilizar su presencia o ausencia en una solicitud de cliente para etiquetarla, creando así un pequeño conjunto de datos anotados (quizás ruidosos) para esta tarea de clasificación. A partir de aquí, podemos construir un clasificador para anotar una colección mayor de datos. Snorkel [30], una reciente herramienta de software desarrollada por la Universidad de Stanford, es útil para la implementación de supervisión débil en diversas tareas de aprendizaje, incluida la clasificación. Snorkel se utilizó para implementar modelos de clasificación de texto basados en supervisión débil a escala industrial en Google [31]. Demostraron que la supervisión débil podía crear clasificadores de calidad comparable a los entrenados con decenas de miles de ejemplos etiquetados a mano. [32] muestra un ejemplo de cómo utilizar Snorkel para generar datos de entrenamiento para la clasificación de textos utilizando una gran cantidad de datos sin etiquetar.

En algunos otros escenarios en los que la recopilación de datos a gran escala es necesaria y factible, el crowdsourcing puede considerarse una opción para etiquetar los datos. Sitios web como Amazon Mechanical Turk y Figure Eight proporcionan plataformas para hacer uso de la inteligencia humana para crear datos de entrenamiento de alta calidad para tareas de ML. Un ejemplo popular de uso de la sabiduría de las multitudes para crear un conjunto de datos de clasificación es la "prueba CAPTCHA," que Google utiliza para preguntar si un conjunto de imágenes contiene un objeto determinado (por ejemplo, "Selecciona todas las imágenes que contengan una señal de tráfico").

Menos datos de entrenamiento: Aprendizaje Activo y Adaptación al Dominio

En situaciones como la descrita anteriormente, en la que recopilamos pequeñas cantidades de datos utilizando anotaciones humanas o bootstrapping, a veces puede resultar que la cantidad de datos sea demasiado pequeña para construir un buen modelo de clasificación. También es posible que la mayoría de las solicitudes que recogimos pertenecieran a facturación y muy pocas a las otras categorías, lo que dio lugar a un conjunto de datos muy desequilibrado. Pedir a los agentes que pasen muchas horas haciendo anotaciones manuales no siempre es factible. ¿Qué debemos hacer en estos casos?

Un enfoque para abordar estos problemas es el aprendizaje activo, que consiste principalmente en identificar qué puntos de datos son más cruciales para utilizarlos como datos de entrenamiento. Ayuda a responder a la siguiente pregunta: si tuviéramos 1.000 puntos de datos pero sólo pudiéramos etiquetar 100 de ellos, ¿qué 100 elegiríamos? Lo que esto significa es que, cuando se trata de datos de entrenamiento, no todos los puntos de datos son iguales. Algunos puntos de datos son más importantes que otros a la hora de determinar la calidad del clasificador entrenado. El aprendizaje activo convierte esto en un proceso continuo.

Utilizar el aprendizaje activo para entrenar un clasificador puede describirse como un proceso paso a paso :

  1. Entrena el clasificador con la cantidad de datos disponibles.

  2. Empieza a utilizar el clasificador para hacer predicciones sobre nuevos datos.

  3. Para los puntos de datos en los que el clasificador no está muy seguro de sus predicciones, envíalos a anotadores humanos para que los clasifiquen correctamente.

  4. Incluye estos puntos de datos en los datos de entrenamiento existentes y vuelve a entrenar el modelo.

Repite los pasos 1 a 4 hasta alcanzar un rendimiento satisfactorio del modelo.

Herramientas como Prodigy [33] tienen soluciones de aprendizaje activo implementadas para la clasificación de textos y apoyan el uso eficiente del aprendizaje activo para crear datos anotados y modelos de clasificación de textos rápidamente. La idea básica del aprendizaje activo es que los puntos de datos en los que el modelo tiene menos confianza son los puntos de datos que contribuyen más significativamente a mejorar la calidad del modelo y, por tanto, sólo se etiquetan esos puntos de datos.

Ahora, imagina un escenario para nuestro clasificador de reclamaciones de clientes en el que tenemos muchos datos históricos para una serie de productos. Sin embargo, ahora se nos pide que lo afinemos para que funcione con un conjunto de productos más nuevos. ¿Cuál es el reto potencial en esta situación? Los enfoques típicos de clasificación de texto se basan en el vocabulario de los datos de entrenamiento. Por lo tanto, están inherentemente sesgados hacia el tipo de lenguaje que se ve en los datos de entrenamiento. Así que, si los nuevos productos son muy diferentes (por ejemplo, el modelo se ha entrenado en un conjunto de productos electrónicos y lo estamos utilizando para reclamaciones sobre productos cosméticos), es poco probable que los clasificadores preentrenados y entrenados en otra fuente de datos funcionen bien. Sin embargo, tampoco es realista entrenar un nuevo modelo desde cero en cada producto o conjunto de productos, ya que volveremos a encontrarnos con el problema de la insuficiencia de datos de entrenamiento. La adaptación al dominio es un método para abordar estas situaciones; también se denomina aprendizaje por transferencia. Aquí, "transferimos" lo aprendido de un dominio (fuente) con grandes cantidades de datos a otro dominio (objetivo) con menos datos etiquetados pero grandes cantidades de datos sin etiquetar. Ya vimos un ejemplo de cómo utilizar el BERT para la clasificación de textos anteriormente en este capítulo.

Este enfoque para la adaptación de dominios en la clasificación de textos puede resumirse como sigue:

  1. Empieza con un gran modelo lingüístico preentrenado y entrenado en un gran conjunto de datos del dominio de origen (por ejemplo, datos de Wikipedia).

  2. Afina este modelo utilizando los datos no etiquetados de la lengua meta.

  3. Entrena un clasificador en los datos etiquetados del dominio de destino extrayendo representaciones de características del modelo lingüístico ajustado del Paso 2.

ULMFit [34] es otro enfoque popular de adaptación de dominios para la clasificación de textos. En experimentos de investigación, se demostró que este enfoque iguala el rendimiento del entrenamiento desde cero con 10 a 20 veces más ejemplos de entrenamiento y sólo 100 ejemplos etiquetados en tareas de clasificación de texto. Cuando se utilizaron datos no etiquetados para afinar el modelo lingüístico preentrenado, se igualó el rendimiento de utilizar de 50 a 100 veces más ejemplos etiquetados cuando se entrenaba desde cero, en las mismas tareas de clasificación de textos. Los métodos de aprendizaje por transferencia son actualmente un área activa de investigación en PNL. Su uso para la clasificación de textos aún no ha mostrado mejoras espectaculares en los conjuntos de datos estándar, ni son todavía la solución por defecto para todos los escenarios de clasificación en las configuraciones industriales. Pero podemos esperar que este enfoque dé cada vez mejores resultados en un futuro próximo.

Hasta ahora, hemos visto una serie de métodos de clasificación de texto y hemos hablado de obtener datos de entrenamiento adecuados y de utilizar diferentes representaciones de características para entrenar a los clasificadores. También hemos tratado brevemente cómo interpretar las predicciones realizadas por algunos modelos de clasificación de texto. Ahora vamos a consolidar lo que hemos aprendido hasta ahora mediante un pequeño caso práctico de construcción de un clasificador de texto para un escenario del mundo real.

Caso práctico: Venta de entradas para empresas

Consideremos un escenario del mundo real y aprendamos cómo podemos aplicar algunos de los conceptos que hemos tratado en esta sección. Imagina que nos piden que construyamos un sistema de tickets para nuestra organización que rastree todos los tickets o problemas a los que se enfrenta la gente en la organización y los dirija a agentes internos o externos. La Figura 4-9 muestra una captura de pantalla representativa de un sistema de este tipo; se trata de un sistema de tickets corporativo llamado Spoke.

A corporate ticketing system
Figura 4-9. Un sistema corporativo de venta de entradas

Ahora digamos que nuestra empresa ha contratado recientemente a un asesor médico y se ha asociado con un hospital. Así que nuestro sistema también debería ser capaz de detectar cualquier problema relacionado con la medicina y dirigirlo a las personas y equipos pertinentes. Pero aunque tenemos algunos tickets anteriores, ninguno de ellos está etiquetado como relacionado con la salud. En ausencia de estas etiquetas, ¿cómo vamos a construir un sistema de clasificación de este tipo relacionado con la salud?

Exploremos un par de opciones:

Utilizar API o bibliotecas existentes

Una opción es empezar con una API o biblioteca pública y asignar sus clases a lo que sea relevante para nosotros. Por ejemplo, las API de Google mencionadas anteriormente en el capítulo pueden clasificar el contenido en más de 700 categorías. Hay 82 categorías asociadas a temas médicos o de salud. Entre ellas se incluyen categorías como /Salud/Estados de Salud/Manejo del Dolor, /Salud/Instalaciones y Servicios Médicos/Consultorios Médicos, /Finanzas/Seguros/Seguro Médico, etc.

Aunque no todas las categorías son relevantes para nuestra organización, algunas podrían serlo, y podemos mapearlas en consecuencia. Por ejemplo, digamos que nuestra empresa no considera que el abuso de sustancias y los problemas de obesidad sean relevantes para el asesoramiento médico. Podemos ignorar /Salud/Abuso de sustancias y /Salud/Condiciones de salud/Obesidad en esta API. Del mismo modo, si el seguro debe formar parte de RRHH o derivarse fuera, también puede gestionarse con estas categorías.

Utilizar conjuntos de datos públicos

También podemos adoptar conjuntos de datos públicos para nuestras necesidades. Por ejemplo, 20 Newsgroups es un popular conjunto de datos de clasificación de textos, y también forma parte de la biblioteca sklearn. Tiene una serie de temas, incluido sci.med. También podemos utilizarlo para entrenar un clasificador básico, clasificando todos los demás temas en una categoría y sci.med en otra.

Utilizar una supervisión débil

Tenemos un historial de entradas anteriores, pero no están etiquetadas. Por lo tanto, podemos considerar la posibilidad de crear un conjunto de datos a partir de ellos, utilizando los enfoques descritos anteriormente en esta sección. Por ejemplo, considera tener una regla: "Si el ticket pasado contiene palabras como fiebre, diarrea, dolor de cabeza o náuseas, ponlo en la categoría de consejo médico". Esta regla puede crear una pequeña cantidad de datos, que podemos utilizar como punto de partida para nuestro clasificador.

Aprendizaje activo

Podemos utilizar herramientas como Prodigy para realizar experimentos de recogida de datos en los que pedimos a alguien que trabaje en el mostrador de atención al cliente que mire las descripciones de los tickets y los etiquete con una lista preestablecida de categorías. La Figura 4-10 muestra un ejemplo de utilización de Prodigy con este fin.

Active learning with Prodigy
Figura 4-10. Aprendizaje activo con Prodigy
Aprender de la información implícita y explícita

A lo largo del proceso de construcción, iteración e implementación de esta solución, estamos recibiendo comentarios que podemos utilizar para mejorar nuestro sistema. Retroalimentación explícita podría ser cuando el consejo médico o el hospital dicen explícitamente que el ticket no era relevante. La retroalimentación implícita podría extraerse de otras variables dependientes como los tiempos de respuesta de los tickets y las tasas de respuesta de los tickets. Todo ello podría tenerse en cuenta para mejorar nuestro modelo mediante técnicas de aprendizaje activo.

Un pipeline de muestra que resuma estas ideas puede parecerse a lo que se muestra en la Figura 4-11. Empezamos sin datos etiquetados y utilizamos una API pública o un modelo creado con un conjunto de datos públicos o una supervisión débil como primer modelo de referencia. Una vez que pongamos este modelo en producción, obtendremos señales explícitas e implícitas sobre dónde está funcionando o fallando. Utilizamos esta información para refinar nuestro modelo y el aprendizaje activo para seleccionar el mejor conjunto de instancias que deben etiquetarse. Con el tiempo, a medida que recopilemos más datos, podremos construir modelos más sofisticados y profundos.

A pipeline for building a classifier when there’s no training data
Figura 4-11. Un proceso para construir un clasificador cuando no hay datos de entrenamiento

En esta sección, empezamos a examinar un supuesto práctico de no disponer de suficientes datos de entrenamiento para construir nuestro propio clasificador de texto para nuestro problema personalizado. Discutimos varias soluciones posibles para abordar el problema. Esperamos que esto te ayude a prever y prepararte para algunos de los escenarios relacionados con la recopilación y creación de datos en tus futuros proyectos relacionados con la clasificación de texto .

Consejos prácticos

Hasta ahora, hemos mostrado una serie de métodos diferentes para construir clasificadores de texto y los posibles problemas con los que te puedes encontrar. Nos gustaría terminar este capítulo con algunos consejos prácticos que resumen nuestras observaciones y experiencia en la construcción de sistemas de clasificación de textos en la industria. La mayoría de ellos son lo suficientemente genéricos como para aplicarlos también a otros temas del libro.

Establecer líneas de base sólidas

Una falacia común es empezar con un algoritmo de última generación. Esto es especialmente cierto en la era actual del aprendizaje profundo, en la que cada día aparecen nuevos enfoques/algoritmos. Sin embargo, siempre es bueno empezar con enfoques más sencillos e intentar establecer primero líneas de base sólidas. Esto es útil por tres razones principales:

  1. Nos ayuda a comprender mejor el planteamiento del problema y los retos clave.

  2. Construir un MVP rápido nos ayuda a obtener los primeros comentarios de los usuarios finales y las partes interesadas.

  3. Un modelo de investigación de vanguardia puede darnos sólo una pequeña mejora en comparación con la línea de base, pero puede venir con una enorme cantidad de deuda técnica.

Datos de entrenamiento de equilibrio

Al trabajar con clasificación, es muy importante tener un conjunto de datos equilibrado en el que todas las categorías tengan la misma representación. Un conjunto de datos desequilibrado puede afectar negativamente al aprendizaje del algoritmo y dar lugar a un clasificador sesgado. Aunque no siempre podemos controlar este aspecto de los datos de entrenamiento, existen varias técnicas para corregir el desequilibrio de clases en los datos de entrenamiento. Algunas de ellas son la recogida de más datos, el remuestreo (submuestreo de clases mayoritarias o sobremuestreo de clases minoritarias) y el equilibrio de pesos.

Combina modelos y humanos en el bucle

En escenarios prácticos, tiene sentido combinar los resultados de múltiples modelos de clasificación con reglas elaboradas a mano por expertos en el dominio para conseguir el mejor rendimiento para la empresa. En otros casos, es práctico aplazar la decisión a un evaluador humano si la máquina no está segura de su decisión de clasificación. Por último, también puede haber situaciones en las que el modelo aprendido tenga que cambiar con el tiempo y con nuevos datos. Discutiremos algunas soluciones para tales escenarios en el Capítulo 11, que se centra en los sistemas de extremo a extremo.

Haz que funcione, haz que mejore

Construir un sistema de clasificación no es sólo construir un modelo. En la mayoría de los entornos industriales, la construcción de un modelo suele representar sólo entre el 5% y el 10% del proyecto total. El resto consiste en recopilar datos, crear canalizaciones de datos, implementación, pruebas, monitoreo, etc. Siempre es bueno construir un modelo rápidamente, utilizarlo para construir un sistema y luego empezar las iteraciones de mejora. Esto nos ayuda a identificar rápidamente los principales obstáculos y las partes que necesitan más trabajo, y a menudo no es la parte del modelado.

Utiliza la sabiduría de muchos

Cada algoritmo de clasificación de textos tiene sus propios puntos fuertes y débiles. No existe un único algoritmo que funcione siempre bien. Una forma de evitarlo es mediante el ensamblaje: el entrenamiento de varios clasificadores. Los datos pasan por cada clasificador, y las predicciones generadas se combinan (por ejemplo, votación por mayoría) para llegar a una predicción de clase final. El lector interesado puede consultar el trabajo de Dong et al. [35, 36] para profundizar en los métodos de ensamblaje para la clasificación de textos.

Conclusión

En este capítulo, hemos visto cómo abordar el problema de la clasificación de textos desde múltiples puntos de vista. Hemos visto cómo identificar un problema de clasificación, abordar las distintas etapas de un proceso de clasificación de textos, recopilar datos para crear conjuntos de datos relevantes, utilizar distintas representaciones de características y entrenar varios algoritmos de clasificación. Con esto, esperamos que ahora estés bien equipado y preparado para resolver problemas de clasificación de textos para tu caso de uso y escenario, y que entiendas cómo utilizar las soluciones existentes, construir nuestros propios clasificadores utilizando varios métodos, y abordar los obstáculos que puedas encontrarte en el proceso. Nos centramos en un solo aspecto de la construcción de sistemas de clasificación de textos en aplicaciones industriales: la construcción del modelo. Las cuestiones relacionadas con la implementación integral de los sistemas de PLN se tratarán en el Capítulo 11. En el próximo capítulo, utilizaremos algunas de las ideas que hemos aprendido aquí para abordar un problema de PNL relacionado pero diferente: la extracción de información.

Notas a pie de página

i Existen otras incrustaciones preentrenadas de este tipo. Nuestra elección en este caso es arbitraria.

Referencias

[1] Servicio Postal de los Estados Unidos. El Servicio Postal de los Estados Unidos: Una Historia Americana, 57-60. ISBN: 978-0-96309-524-4. Último acceso: 15 de junio de 2020.

[2] Gupta, Anuj, Saurabh Arora, Satyam Saxena y Navaneethan Santhanam. "Reducción de ruido y billetaje inteligente para sistemas de comunicación basados en medios sociales". Solicitud de patente estadounidense 20190026653, presentada el 24 de enero de 2019.

[3] Spasojevic, Nemanja y Adithya Rao. "Identificación de mensajes procesables en las redes sociales". 2015 Conferencia Internacional del IEEE sobre Grandes Datos: 2273-2281.

[4] CLPSYCH: Taller de Lingüística Computacional y Psicología Clínica. Tareas Compartidas 2019.

[5] Google Cloud. " Lenguaje Natural". Último acceso: 15 de junio de 2020.

[6] Amazon Comprehend. Último acceso: 15 de junio de 2020.

[7] Servicios Cognitivos Azure. Último acceso: 15 de junio de 2020.

[8] Iderhoff, Nicolas. nlp-datasets: Lista alfabética de conjuntos de datos de dominio libre/público con datos de texto para su uso en el Procesamiento del Lenguaje Natural (PLN), (repositorio de GitHub). Último acceso: 15 de junio de 2020.

[9] Kaggle. "Análisis de Sentimiento: Emoción en el texto". Último acceso: 15 de junio de 2020.

[10] Repositorio de Aprendizaje Automático de UC Irvine. Una colección de repositorios para el aprendizaje automático. Último acceso: 15 de junio de 2020.

[11] Google. "Búsqueda de conjuntos de datos". Último acceso: 15 de junio de 2020.

[12] Jurafsky, Dan y James H. Martin. Procesamiento del Habla y del Lenguaje, Tercera Edición (Borrador), 2018.

[13] Lemaître, Guillaume, Fernando Nogueira y Christos K. Aridas. "Imbalanced-learn: A Python Toolbox to Tackle the Curse of Imbalanced Datasets in Machine Learning". Revista de Investigación en Aprendizaje Automático 18.1 (2017): 559-563.

[14] Para una descripción matemática detallada de la regresión logística, consulta el capítulo 5 de [12].

[15] Google. Modelo word2vec preentrenado. Último acceso: 15 de junio de 2020.

[16] Bojanowski, Piotr, Edouard Grave, Armand Joulin y Tomas Mikolov. "Enriquecimiento de vectores de palabras con información de subpalabras". Transacciones de la Asociación de Lingüística Computacional 5 (2017): 135-146.

[17] Joulin, Armand, Edouard Grave, Piotr Bojanowski y Tomas Mikolov. "Bolsa de trucos para la clasificación eficiente de textos".(2016).

[18] Ramesh, Sree Harsha. torchDatasets, (repositorio de GitHub). Último acceso: 15 de junio de 2020.

[19] Joulin, Armand, Edouard Grave, Piotr Bojanowski, Matthijs Douze, Hérve Jégou y Tomas Mikolov. "Fasttext.zip: Comprimiendo modelos de clasificación de textos".(2016).

[20] Para las versiones más antiguas de Doc2vec, existen algunos modelos preentrenados; por ejemplo, https://oreil.ly/kt0U0 (último acceso: 15 de junio de 2020).

[21] Conjunto de Herramientas del Lenguaje Natural. "Documentación de NLTK 3.5". Último acceso: 15 de junio de 2020.

[22] Lau, Jey Han y Timothy Baldwin. "Una evaluación empírica de doc2vec con ideas prácticas sobre la generación de incrustación de documentos".(2016).

[23] Laboratorio de Inteligencia Artificial de Stanford. "Gran conjunto de datos de críticas de películas". Último acceso: 15 de junio de 2020.

[24] Goodfellow, Ian, Yoshua Bengio y Aaron Courville. Aprendizaje profundo. Cambridge: MIT Press, 2016. ISBN: 978-0-26203-561-3

[25] Goldberg, Yoav. "Métodos de redes neuronales para el procesamiento del lenguaje natural". Conferencias de Síntesis sobre Tecnologías del Lenguaje Humano 10.1 (2017): 1-309.

[26] Ribeiro, Marco Tulio, Sameer Singh y Carlos Guestrin. "'¿Por qué debo confiar en ti? Explicando las predicciones de cualquier clasificador". Actas de la 22ª Conferencia Internacional ACM SIGKDD sobre Descubrimiento de Conocimientos y Minería de Datos (2016): 1135-1144.

[27] Lundberg, Scott M. y Su-In Lee. "Un enfoque unificado para interpretar predicciones de modelos". Avances en Sistemas de Procesamiento de Información Neuronal 30 (NIPS 2017): 4765-4774.

[28] Marco Tulio Correia Ribeiro. Cal: Explicando las predicciones de cualquier clasificador de aprendizaje automático, (repositorio de GitHub). Último acceso: 15 de junio de 2020.

[29] Lundberg, Scott. shap: A game theoretic approach to explain the output of any machine learning model, (GitHub repo).

[30] Snorkel. "Construir y gestionar programáticamente datos de formación". Último acceso: 15 de junio de 2020.

[31] Bach, Stephen H., Daniel Rodríguez, Yintao Liu, Chong Luo, Haidong Shao, Cassandra Xia, Souvik Sen et al. "Snorkel DryBell: Un Estudio de Caso en la Implementación de la Supervisión Débil a Escala Industrial".(2018).

[32] Snorkel. "Tutorial de introducción a Snorkel: Etiquetado de datos". Último acceso: 15 de junio de 2020.

[33] Prodigio. Último acceso: 15 de junio de 2020.

[34] Fast.ai. "Presentamos la clasificación de textos más avanzada con modelos lingüísticos universales". Último acceso: 15 de junio de 2020.

[35] Dong, Yan-Shi y Ke-Song Han. "Comparación de varios métodos de conjunto para la categorización de textos". Conferencia Internacional del IEEE sobre Informática de Servicios (2004): 419-422.

[36] Caruana, Rich, Alexandru Niculescu-Mizil, Geoff Crew y Alex Ksikes. "Selección de conjuntos a partir de bibliotecas de modelos". Actas de la Vigesimoprimera Conferencia Internacional sobre Aprendizaje Automático (2004): 18.

Get Procesamiento práctico del lenguaje natural now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.