Artículos

Cómo usar aprendizaje automático para analizar sentimientos con representaciones vectoriales de palabras

Los investigadores han probado distintas formas de usar aprendizaje automático para predecir automáticamente el sentimiento de una oración. Predecir el sentimiento es un problema típico del procesamiento del lenguaje natural (NLP), y existen muchas técnicas que lo abordan con distintos métodos de aprendizaje automático.

La mayoría de estos trabajos y técnicas extraen características y las aplican a un algoritmo de aprendizaje automático «tradicional». En los últimos años, la aparición de las representaciones vectoriales de palabras (word embeddings) hizo más común el uso de redes neuronales que de algoritmos tradicionales, gracias a sus resultados superiores.

En este artículo uso redes neuronales convolucionales y representaciones vectoriales de palabras para predecir el sentimiento de reseñas de Amazon.

El análisis de sentimientos permite predecir automáticamente opiniones y emociones.
El análisis de sentimientos permite predecir automáticamente opiniones y emociones.

Corpus de reseñas de Amazon

Dentro de la clasificación de algoritmos de aprendizaje automático, las redes neuronales pertenecen al aprendizaje supervisado. En este, los algoritmos aprenden una función que relaciona una entrada específica con una salida específica mediante ejemplos preclasificados llamados conjunto de entrenamiento. Cuando termina la fase de aprendizaje, podemos aplicar la función aprendida para clasificar ejemplos nuevos.

En las redes neuronales tenemos un conjunto de «neuronas» que calcula una función específica llamada función de activación. Las neuronas se agrupan en capas y se conectan mediante pesos específicos. Cada neurona recibe una entrada de la capa anterior y aplica la función de activación hacia la siguiente.

La cantidad de capas, las neuronas por capa y el tipo de función de activación conforman la arquitectura de la red neuronal.

Dado un conjunto de neuronas con una arquitectura específica, el algoritmo de aprendizaje ajusta los pesos usando el conjunto de entrenamiento.

Un conjunto de entrenamiento permite que un algoritmo de aprendizaje supervisado aprenda una función.
Un conjunto de entrenamiento permite que un algoritmo de aprendizaje supervisado aprenda una función.

En el análisis de sentimientos queremos encontrar una función que tome una oración y determine su sentimiento, positivo o negativo. Para aprenderla con redes neuronales, debemos entrenar la máquina con un corpus de oraciones y sus sentimientos correspondientes.

En este artículo usaremos el conjunto de datos de reseñas de Amazon publicado por Kaggle.

Es un archivo CSV con 4,000,000 reseñas de Amazon y la siguiente información:

  • Título
  • Texto de la reseña
  • Etiqueta

La etiqueta puede ser etiqueta 1 si la reseña tiene 1 o 2 estrellas, o etiqueta 2 si tiene 4 o 5 estrellas. Las reseñas de 3 estrellas, neutrales, no se incluyen. Este conjunto es especialmente interesante porque contiene reseñas de muchos temas.

Por ejemplo, una reseña positiva, con etiqueta 2:

Título: Una mirada fascinante a la vida de los adolescentes japoneses modernos

Texto: Disfruté muchísimo Rising Sons and Daughters. No conozco otro libro que observe la sociedad japonesa desde el punto de vista de sus jóvenes, situados entre la antigua cultura japonesa de sus padres, de moderación y obediencia a la voluntad de la comunidad, y la admiración de sus pares por la cultura occidental. Como era de esperar, los «nuevos jóvenes» de Japón parecen estar creando una mezcla «internacional», como demuestra la familia Ando en este libro bellamente escrito de escenas de la vida privada de sus integrantes. Steven Wardell es claramente un joven autor talentoso, acogido por esta familia de cuatro adolescentes durante parte de su educación, lo que le permitió observar la vida familiar japonesa desde dentro. ¡Una gran lectura!

Y una reseña negativa, con etiqueta 1:

Título: UNIDAD DE CD PORTÁTIL ADDONICS: estoy decepcionado con su rendimiento

Texto: Estoy decepcionado con su rendimiento. Parece tener poca potencia e intenta leer los CD constantemente, la mitad de las veces sin éxito. Voy a intentar devolverla a Amazon.

Este conjunto se divide en dos grupos:

  • el «conjunto de entrenamiento», con 360,000 reseñas

  • el «conjunto de prueba», con 400,000 reseñas

La idea es usar el conjunto de entrenamiento para enseñar a la red neuronal a evaluar el sentimiento y luego usar el conjunto de prueba para evaluar qué tan bien aprendió.

Referencia de base

Para comparar resultados, definiré una referencia de base usando el léxico de opiniones de Liu y Hu. Este contiene una lista de palabras clasificadas como positivas o negativas.

El algoritmo de base es muy simple e intuitivo: cuenta las palabras positivas y negativas de una oración. Si hay más positivas que negativas, podemos suponer que su sentimiento es positivo. Si hay más negativas, suponemos que es negativo. Sin embargo, hay muchos casos que no cubre, como las negaciones.

El algoritmo es el siguiente:

from nltk.corpus import opinion_lexicon
from nltk.tokenize import treebank

def demo_liu_hu_lexicon(sentence):
    tokenizer = treebank.TreebankWordTokenizer()
    pos_words = 0
    neg_words = 0
    tokenized_sent = [word.lower() for word in tokenizer.tokenize(sentence)]

    for word in tokenized_sent:
        if word in opinion_lexicon.positive():
            pos_words += 1
        elif word in opinion_lexicon.negative():
            neg_words += 1
    if pos_words > neg_words:
        return 'Positive'
    elif pos_words < neg_words:
        return 'Negative'
    else:
        return 'Neutral'

Al aplicarlo al conjunto de Amazon, obtenemos una exactitud del 50%.

Algoritmos de redes neuronales

Los algoritmos de redes neuronales requieren que la entrada se exprese como vectores de números enteros de alta dimensión, mayor que 100. Para usar una red neuronal en tareas de NLP, necesitamos convertir las oraciones en vectores. Esta tarea se llama preprocesamiento y hay varias formas de realizarla.

En este artículo usaré un modelo de representaciones vectoriales de palabras para obtener los vectores asociados a las oraciones. Estas representaciones relacionan palabras y vectores mediante un algoritmo automático. Son muy útiles en NLP porque los vectores mantienen la relación semántica entre palabras.

Por ejemplo, la función que transforma Hombre en Mujer devolverá Reina si la aplicamos a Rey.

Una ilustración de Word2vec
Una ilustración de Word2vec

Estas representaciones también mantienen la similitud semántica: las palabras con significados similares generarán vectores similares.

En este artículo usaré un modelo proporcionado por Google, generado con el algoritmo Word2vec* a partir de un corpus de noticias.

Para obtener un vector que represente las oraciones, debemos preprocesarlas. El primer paso es tokenizar cada oración, lo que la convierte en una lista de tokens.

Por ejemplo:

This sound track was beautiful! It paints the senery [sic] ** in your mind so well I would recomend [sic] it even to people who hate vid. game music! I have played the game Chrono Cross but out of all of the games I have ever played it has the best music! It backs away from crude keyboarding and takes a fresher step with grate guitars and soulful orchestras. It would impress anyone who cares to listen! ^_^

se tokeniza así:

[*'this', 'sound', 'track', 'was', 'beautiful', '!', 'it', 'paints', 'the', 'senery', 'in', 'your', 'mind', 'so', 'well', 'i', 'would', 'recomend', 'it', 'even', 'to', 'people', 'who', 'hate', 'vid', '.', 'game', 'music', '!', 'i', 'have', 'played', 'the', 'game', 'chrono', 'cross', 'but', 'out', 'of', 'all', 'of', 'the', 'games', 'i', 'have', 'ever', 'played', 'it', 'has', 'the', 'best', 'music', '!', 'it', 'backs', 'away', 'from', 'crude', 'keyboarding', 'and', 'takes', 'a', 'fresher', 'step', 'with', 'grate', 'guitars', 'and', 'soulful', 'orchestras', '.', 'it', 'would', 'impress', 'anyone', 'who', 'cares', 'to', 'listen', '!', '^_^'*]

El siguiente paso consiste en reemplazar todas las «palabras vacías» y conservar solo los N tokens más comunes. Al mantener únicamente esos «N» tokens, podemos ignorar las palabras que aparecen en pocas reseñas y no contribuyen al algoritmo de aprendizaje.

Después de realizar pruebas experimentales con el conjunto de entrenamiento variando N, pude determinar que N=7000 es el valor óptimo.

Así se ve una reseña después de reemplazar las palabras vacías y conservar solo los tokens más comunes:

[*'<UNK>', '<UNK>', 'finished', 'reading', '<UNK>', '<UNK>', '<UNK>', 'wicked', '<UNK>', '<UNK>', '<UNK>', 'fell', '<UNK>', 'love', '<UNK>', '<UNK>', '<UNK>', '<UNK>', '<UNK>', 'expected', '<UNK>', 'average', 'romance', 'read', '<UNK>', '<UNK>', 'instead', '<UNK>', 'found', 'one', '<UNK>', '<UNK>', 'favorite', 'books', '<UNK>', '<UNK>', 'time', '<UNK>', '<UNK>', '<UNK>', '<UNK>', 'thought', '<UNK>', 'could', 'predict', '<UNK>', 'outcome', '<UNK>', '<UNK>', 'shocked', '<UNK>', '<UNK>', 'writting', '<UNK>', '<UNK>', 'descriptive', '<UNK>', '<UNK>', 'heart', 'broke', '<UNK>', 'julia', "'s", '<UNK>', '<UNK>', '<UNK>', 'felt', '<UNK>', '<UNK>', '<UNK>', '<UNK>', '<UNK>', '<UNK>', '<UNK>', 'instead', '<UNK>', '<UNK>', '<UNK>', 'distant', 'reader', '<UNK>', '<UNK>', '<UNK>', '<UNK>', '<UNK>', 'lover', '<UNK>', 'romance', 'novels', '<UNK>', '<UNK>', '<UNK>', '<UNK>', 'must', 'read', '<UNK>', '<UNK>', "n't", 'let', '<UNK>', 'cover', 'fool', '<UNK>', '<UNK>', 'book', '<UNK>', 'spectacular', '<UNK>*']

Finalmente, debemos definir una matriz de representaciones vectoriales y reemplazar las palabras por su índice correspondiente. Este método se describe con más detalle aquí.

Después de este paso, obtendremos:

[7000, 97, 362, 7000, 283, 7000, 7000, 5936, 7000, 7000, 7000, 7000, 313, 7000, 16, 7000, 6, 1359, 7000, 14, 7000, 40, 7000, 552, 7000, 7000, 126, 44, 7000, 7000, 7000, 390, 7000, 126, 7000, 1681, 7000, 7000, 7000, 7000, 7000, 7000, 655, 7000, 7000, 48, 390, 7000, 7000, 7000, 23, 44, 7000, 7000, 6737, 157, 7000, 3762, 7000, 7000, 302, 7000, 7000, 1131, 7000, 7000, 2921, 7000, 3830, 7000, 7000, 7000, 6, 4382, 83, 7000, 1971, 7000, 216, 7000, 7000]

Modelo neuronal básico

Mi primer enfoque para predecir el sentimiento de una reseña fue usar una red neuronal básica con dos capas densas.

Las redes se definieron y entrenaron usando keras con TensorFlow como base.

La arquitectura se definió así:

model = Sequential()
model.add(embedding_layer)
model.add(Flatten())
model.add(Dense(250, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

Donde embedding_layer se define como:

Embedding( len(text_vector_dict_keys), 300, weights=[embedding_matrix] input_length=MAX_WORDS, trainable=False)

La primera capa es una capa de representaciones vectoriales. Recibe un vector con un índice y devuelve una matriz con las representaciones correspondientes.

La segunda es una capa de aplanamiento. Concatena todos los vectores en uno solo. Si ajustamos los vectores a 500 palabras y el modelo tiene dimensión 300, el resultado es un vector de dimensiones 500x300.

Finalmente, la tercera y cuarta capas son densas y reducen las dimensiones de estos vectores a 250 y 1, respectivamente.

El algoritmo solo ajusta los pesos de las capas 3.ª y 4.ª. Los pesos de la primera capa no se entrenan porque representan el modelo de representaciones vectoriales de palabras.

Esta red básica funciona con una exactitud del 80%, una mejora del 30% respecto de la referencia de base. Sin embargo, los mejores resultados actuales en análisis de sentimientos superan el 95%, por lo que el algoritmo aún necesita algunas mejoras.

Modelo neuronal CNN

Mi siguiente paso fue reemplazar la red básica por una red neuronal convolucional (CNN). Las CNN fueron diseñadas para procesar imágenes rápidamente. El problema de las redes regulares es que todas sus capas están completamente conectadas: si creamos muchas capas ocultas, el costo de ajustar los pesos es alto.

La definición de las CNN y sus diferencias con las redes regulares se encuentran aquí.

En resumen, con las CNN no consideramos todo el vector de entrada, sino solo el elemento más cercano a cada componente. Este cambio reduce mucho el ajuste de las redes porque la cantidad de conexiones entre neuronas es considerablemente menor.

Las CNN pueden usarse en problemas donde la vecindad es importante. Las imágenes cumplen esta condición —los cambios en un píxel afectan la imagen en relación con su vecindad—, al igual que las oraciones.

Red neuronal regular
Red neuronal regular
Red neuronal convolucional
Red neuronal convolucional

Podemos usar una CNN en nuestro problema con esta arquitectura:

model = Sequential()
model.add(embedding_layer)
model.add(Conv1D(filters=32, kernel_size=3, padding='same', activation='relu'))
model.add(Conv1D(filters=64, kernel_size=3, padding='same', activation='relu'))
model.add(MaxPooling1D(pool_size=2))
model.add(Dropout(0.2))
model.add(Conv1D(filters=128, kernel_size=3, padding='same', activation='relu'))
model.add(MaxPooling1D(pool_size=2))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(250, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

La arquitectura es similar a la solución anterior. La diferencia principal es que introdujimos algunas capas adicionales con convoluciones.

Al aplicar esta red al corpus de reseñas de Amazon, los resultados alcanzan aproximadamente un 90% de exactitud. Son buenos resultados y los considero aceptables.

Conclusiones y formas de mejorar

En este artículo mostré que usar representaciones vectoriales de palabras para resolver problemas de NLP es un buen enfoque. Tienen propiedades que podemos aprovechar. Mantener las relaciones semánticas entre palabras es muy importante.

Además, permiten omitir la fase de extracción de características. Esto es importante porque, en algunos problemas de NLP, las características necesarias no son triviales y extraerlas requiere mucha investigación y pruebas.

Otra ventaja es que permiten usar redes neuronales en tareas de NLP. Sin estas representaciones, no sería posible usar redes neuronales para NLP porque tendríamos que extraer más de 100 características.

También mostré cómo las CNN pueden usarse fuera del procesamiento de imágenes. Son útiles en análisis de sentimientos y mejoran la exactitud en un 10% respecto de las redes neuronales tradicionales.

En un problema futuro, podríamos usar distintos modelos de representaciones vectoriales para obtener mejores resultados. Por ejemplo, crear un modelo vectorial a partir de un corpus de reseñas en lugar de noticias, porque una representación vectorial orientada al sentimiento debería ser más exacta que una genérica.

“Cómo usar aprendizaje automático para analizar sentimientos con representaciones vectoriales de palabras” de Pablo Grill está bajo la licencia CC BY SA. Los ejemplos de código fuente están bajo la licencia MIT.

Foto de sophilabs.

Clasificado en Investigación y aprendizaje.

Lecturas relacionadas