Analise de Sentimentos — Naive Bayes
Na próxima série de tópicos, vamos mergulhar em diferentes abordagens para resolver o problema do Olá Mundo da NLP, a análise de sentimentos.
O código esta disponível aqui.
O classificador Naive Bayes
O classificador Naive Bayes usa o Teorema de Bayes, que para o nosso problema diz que a probabilidade do rótulo (positivo ou negativo) para o texto dado é igual à probabilidade de encontrarmos esse texto dado o rótulo , vezes a probabilidade de um rótulo ocorrer, tudo dividido pela probabilidade de encontrarmos esse texto:
\[P(label|text) = \frac{P(text|label) * P(label)}{P(text)}\]Como o texto é composto de palavras, podemos dizer:
\[P(label|word_1, word_2, ..., word_n) = \frac{P(word_1, word_2, ..., word_n|label) * P(label)}{P(word_1, word_2, ..., word_n)}\]Queremos comparar as probabilidades dos rótulos e escolher aquele com maior probabilidade. Como o termo P(word_1, word_2, …, word_n) é igual para tudo, podemos removê-lo. Supondo que não haja dependência entre palavras no texto (o que pode causar alguns erros, pois algumas palavras só “funcionam” juntas com outras), temos:
\[P(label|word_1, word_2, ..., word_n) = P(word_1|label) * P(word_2|label) * ... * P(word_n|label) * P(label)\]Então terminamos! Com um conjunto de treinamento, podemos encontrar cada termo da equação, por exemplo:
- \(P(rotulo=positivo)\) é a fração do conjunto de treinamento que é umtexto positivo
- \(P(word_1 \vert label=negativo)\) é o número de vezes que a palavra 1 aparece em um texto negativo dividido pelo número de vezes que a palavra 1 aparece em cada texto.
O código
Para esta tarefa usaremos uma famosa biblioteca de aprendizado de máquina de código aberto, a scikit-learn .
Nosso conjunto de dados é composto por resenhas de filmes e rótulos que informam se a crítica é negativa ou positiva. Vamos carregar o conjunto de dados:
O arquivo de reviews é um pouco grande, então está em formato zip. Vamos Extraí-lo:
import zipfile
with zipfile.ZipFile("reviews.zip", 'r') as zip_ref:
zip_ref.extractall(".")
Agora que temos os arquivos reviews.txt e labels.txt, vamos carregá-los na memória:
with open("reviews.txt") as f:
reviews = f.read().split("\n")
with open("labels.txt") as f:
labels = f.read().split("\n")
reviews_tokens = [review.split() for review in reviews]
Em seguida, carregamos o módulo para transformar nossas entradas de revisão em vetores binários com a ajuda da classe MultiLabelBinarizer:
from sklearn.preprocessing import MultiLabelBinarizer
onehot_enc = MultiLabelBinarizer()
onehot_enc.fit(reviews_tokens)
Depois disso, dividimos os dados em conjunto de treinamento e teste com a train_test_split função:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(reviews_tokens, labels, test_size=0.25, random_state=None)
Em seguida, criamos um classificador Naive Bayes e treinamos nossos dados. Usaremos um classificador Bernoulli Naive Bayes que é apropriado para vetores de características compostos de dados binários. Fazemos isso com a classe BernoulliNB:
from sklearn.naive_bayes import BernoulliNB
bnbc = BernoulliNB(binarize=None)
bnbc.fit(onehot_enc.transform(X_train), y_train)
Treinar o modelo levou apenas 1 segundo!
Após o treinamento, utilizamos a scorefunção para verificar o desempenho do classificador:
score = bnbc.score(onehot_enc.transform(X_test), y_test)
O cálculo da pontuação levou apenas 0,4 segundos!
Rodando o classificador algumas vezes, obtemos cerca de 85% de precisão. Nada mal para um classificador tão simples.