Artigos

Como usar aprendizado de máquina para analisar sentimentos com representações vetoriais de palavras

Pesquisadores testaram diferentes formas de usar aprendizado de máquina para prever automaticamente o sentimento de uma frase. Prever sentimentos é um problema típico do processamento de linguagem natural (NLP), e há muitas técnicas que o abordam com diferentes métodos de aprendizado de máquina.

A maioria desses trabalhos e técnicas extrai características e as aplica a um algoritmo de aprendizado de máquina “tradicional”. Nos últimos anos, o surgimento das representações vetoriais de palavras (word embeddings) tornou o uso de redes neurais mais comum do que o de algoritmos tradicionais, graças aos resultados superiores.

Neste artigo, uso redes neurais convolucionais e representações vetoriais de palavras para prever o sentimento de avaliações da Amazon.

A análise de sentimentos permite prever automaticamente opiniões e emoções.
A análise de sentimentos permite prever automaticamente opiniões e emoções.

Corpus de avaliações da Amazon

Na classificação dos algoritmos de aprendizado de máquina, as redes neurais pertencem ao aprendizado supervisionado. Nele, os algoritmos aprendem uma função que relaciona uma entrada específica a uma saída específica usando exemplos pré-classificados chamados conjunto de treinamento. Ao terminar a fase de aprendizado, podemos aplicar a função aprendida para classificar novos exemplos.

Nas redes neurais, temos um conjunto de “neurônios” que calcula uma função específica chamada função de ativação. Os neurônios são agrupados em camadas e conectados por pesos específicos. Cada um recebe uma entrada da camada anterior e aplica a função de ativação para a próxima.

A quantidade de camadas, os neurônios por camada e o tipo de função de ativação compõem a arquitetura da rede neural.

Dado um conjunto de neurônios com uma arquitetura específica, o algoritmo de aprendizado ajusta os pesos usando o conjunto de treinamento.

Um conjunto de treinamento permite que um algoritmo de aprendizado supervisionado aprenda uma função.
Um conjunto de treinamento permite que um algoritmo de aprendizado supervisionado aprenda uma função.

Na análise de sentimentos, queremos encontrar uma função que receba uma frase e determine seu sentimento, positivo ou negativo. Para aprendê-la com redes neurais, precisamos treinar a máquina com um corpus de frases e seus sentimentos correspondentes.

Neste artigo, usaremos o conjunto de dados de avaliações da Amazon publicado pelo Kaggle.

É um arquivo CSV com 4,000,000 avaliações da Amazon e estas informações:

  • Título
  • Texto da avaliação
  • Rótulo

O rótulo pode ser rótulo 1 se a avaliação tiver 1 ou 2 estrelas, ou rótulo 2 se tiver 4 ou 5 estrelas. Avaliações de 3 estrelas, neutras, não são incluídas. Esse conjunto é especialmente interessante porque contém avaliações sobre muitos assuntos.

Por exemplo, uma avaliação positiva, com rótulo 2:

Título: Uma visão fascinante da vida dos adolescentes japoneses modernos

Texto: Gostei muito de Rising Sons and Daughters. Não conheço outro livro que observe a sociedade japonesa pela perspectiva de seus jovens, entre a antiga cultura japonesa dos pais, de contenção e obediência à vontade da comunidade, e a admiração dos colegas pela cultura ocidental. Como esperado, os “novos jovens” do Japão parecem criar uma mistura “internacional”, como a família Ando demonstra neste livro lindamente escrito de cenas da vida privada de seus integrantes. Steven Wardell é claramente um jovem autor talentoso, acolhido por essa família de quatro adolescentes durante parte de sua educação, podendo assim observar a vida familiar japonesa de dentro para fora. Uma ótima leitura!

E uma avaliação negativa, com rótulo 1:

Título: UNIDADE DE CD PORTÁTIL ADDONICS: estou decepcionado com o desempenho

Texto: Estou decepcionado com o desempenho. Parece ter pouca potência e tenta ler CDs constantemente, metade das vezes sem sucesso. Vou tentar devolvê-la à Amazon.

Esse conjunto é dividido em dois grupos:

  • o “conjunto de treinamento”, com 360,000 avaliações

  • o “conjunto de teste”, com 400,000 avaliações

A ideia é usar o conjunto de treinamento para ensinar a rede neural a avaliar sentimentos e depois usar o conjunto de teste para avaliar o quanto ela aprendeu.

Referência de base

Para comparar os resultados, definirei uma referência de base usando o léxico de opiniões de Liu e Hu. Ele contém uma lista de palavras classificadas como positivas ou negativas.

O algoritmo de base é muito simples e intuitivo: conta as palavras positivas e negativas de uma frase. Se houver mais positivas do que negativas, podemos assumir que o sentimento é positivo. Se houver mais negativas, assumimos que é negativo. No entanto, há muitos casos que ele não cobre, como negações.

O algoritmo é o seguinte:

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'

Ao aplicá-lo ao conjunto da Amazon, alcançamos 50% de acurácia.

Algoritmos de redes neurais

Os algoritmos de redes neurais exigem que a entrada seja expressa como vetores de números inteiros de alta dimensão, maior que 100. Para usar uma rede neural em tarefas de NLP, precisamos converter frases em vetores. Essa tarefa se chama pré-processamento, e há várias maneiras de realizá-la.

Neste artigo, usarei um modelo de representações vetoriais de palavras para obter os vetores associados às frases. Essas representações relacionam palavras e vetores por meio de um algoritmo automático. São muito úteis em NLP porque os vetores mantêm a relação semântica entre as palavras.

Por exemplo, a função que transforma Homem em Mulher retornará Rainha se aplicada a Rei.

Uma ilustração de Word2vec
Uma ilustração de Word2vec

Essas representações também mantêm a similaridade semântica: palavras com significados semelhantes geram vetores semelhantes.

Neste artigo, usarei um modelo fornecido pelo Google, gerado com o algoritmo Word2vec* a partir de um corpus de notícias.

Para obter um vetor que represente as frases, precisamos pré-processá-las. A primeira etapa é tokenizar cada frase, convertendo-a em uma lista de tokens.

Por exemplo:

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! ^_^

é tokenizado assim:

[*'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', '!', '^_^'*]

A próxima etapa consiste em substituir todas as “palavras de parada” e preservar apenas os N tokens mais comuns. Mantendo apenas esses “N” tokens, podemos ignorar palavras que aparecem em poucas avaliações e não contribuem para o algoritmo de aprendizado.

Depois de realizar testes experimentais com o conjunto de treinamento variando N, determinei que N=7000 é o valor ideal.

Uma avaliação fica assim depois de substituir as palavras de parada e manter apenas os tokens mais comuns:

[*'<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>*']

Por fim, devemos definir uma matriz de representações vetoriais e substituir as palavras pelo índice correspondente. Esse método é descrito em mais detalhes aqui.

Depois dessa etapa, teremos:

[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 neural básico

Minha primeira abordagem para prever o sentimento de uma avaliação foi usar uma rede neural básica com duas camadas densas.

As redes foram definidas e treinadas usando keras com TensorFlow como base.

A arquitetura foi definida assim:

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'])

Onde embedding_layer é definido como:

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

A primeira camada é de representações vetoriais. Ela recebe um vetor com um índice e retorna uma matriz com as representações correspondentes.

A segunda é de achatamento. Ela concatena todos os vetores em um só. Se ajustarmos os vetores a 500 palavras e o modelo tiver dimensão 300, o resultado será um vetor com dimensões 500x300.

Por fim, a terceira e a quarta camadas são densas e reduzem as dimensões desses vetores para 250 e 1, respectivamente.

O algoritmo ajusta apenas os pesos da 3.ª e da 4.ª camadas. Os pesos da primeira não são treinados porque representam o modelo de representações vetoriais de palavras.

Essa rede básica funciona com 80% de acurácia, uma melhoria de 30% em relação à referência de base. No entanto, os melhores resultados atuais em análise de sentimentos superam 95%, então o algoritmo ainda precisa de algumas melhorias.

Modelo neural CNN

Minha próxima etapa foi substituir a rede básica por uma rede neural convolucional (CNN). As CNNs foram projetadas para processar imagens rapidamente. O problema das redes regulares é que todas as camadas são totalmente conectadas: se criarmos muitas camadas ocultas, o custo de ajustar os pesos será alto.

A definição de CNNs e suas diferenças em relação às redes regulares estão aqui.

Em resumo, com CNNs não consideramos o vetor de entrada inteiro, mas apenas o elemento mais próximo de cada componente. Essa mudança reduz muito o ajuste das redes porque a quantidade de conexões entre neurônios é consideravelmente menor.

CNNs podem ser usadas em problemas nos quais a vizinhança importa. As imagens atendem a essa condição —mudanças em um pixel afetam a imagem em relação à vizinhança—, assim como as frases.

Rede neural regular
Rede neural regular
Rede neural convolucional
Rede neural convolucional

Podemos usar uma CNN no nosso problema com esta arquitetura:

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'])

A arquitetura é semelhante à solução anterior. A principal diferença é que adicionamos algumas camadas com convoluções.

Ao aplicar essa rede ao corpus de avaliações da Amazon, os resultados alcançam cerca de 90% de acurácia. São bons resultados, e eu os considero aceitáveis.

Conclusões e formas de melhorar

Neste artigo, mostrei que usar representações vetoriais de palavras para resolver problemas de NLP é uma boa abordagem. Elas têm propriedades que podemos aproveitar. Manter as relações semânticas entre palavras é muito importante.

Além disso, permitem omitir a etapa de extração de características. Isso é importante porque, em alguns problemas de NLP, as características necessárias não são triviais e extraí-las exige muita pesquisa e testes.

Outra vantagem é permitir o uso de redes neurais em tarefas de NLP. Sem essas representações, não seria possível usar redes neurais para NLP porque precisaríamos extrair mais de 100 características.

Também mostrei como as CNNs podem ser usadas fora do processamento de imagens. Elas são úteis na análise de sentimentos e melhoram a acurácia em 10% em relação às redes neurais tradicionais.

Em um problema futuro, poderíamos usar diferentes modelos de representações vetoriais para obter resultados melhores. Por exemplo, criar um modelo vetorial de um corpus de avaliações em vez de notícias, pois uma representação vetorial voltada ao sentimento deve ser mais acurada do que uma genérica.

“Como usar aprendizado de máquina para analisar sentimentos com representações vetoriais de palavras” por Pablo Grill está sob a licença CC BY SA. Os exemplos de código-fonte estão sob a licença MIT.

Foto de sophilabs.

Classificado em Pesquisa e aprendizado.

Leituras relacionadas