...

Aplicando algoritmos de modelagem de tópicos nos discursos dos políticos - Parte 1

kim kataguiri

Sobre esse projeto

Esse foi o primeiro projeto em mineração de dados que trabalhei, o foco era entender como essas técnicas funcionam. A técnica escolhida para ser implementada foi a alocação latente de Dirichlet (LDA), essa técnica extrai tópicos de grande quantidade de textos, tópicos, neste caso, é definido como um conjunto de palavras-chave como justiça, segurança, polícia.

Para mostrar uma aplicação real desta técnica, minha equipe propôs usar os discursos de políticos como amostra. A amostra foi dividida em duas partes, a primeira intitulada "novos políticos" representando os novos políticos eleitos com o auxílio das redes sociais, e a segunda intitulada "antigos políticos" representando os antigos políticos que não foram reeleitos, ambos são de direita.

A ideia era verificar se os tópicos de cada amostra são iguais se os tópicos são iguais então as ideias não mudaram, o que mudou foi a forma de comunicar, se os tópicos são diferentes então abre espaço para outras hipóteses. Este projeto atualmente não está sendo trabalhado, há outro projeto em andamento, por isso decidi escrever sobre este projeto aqui e utilizá-lo para trazer conhecimento sobre o algoritmo de modelagem de tópicos. Nosso foco está no algoritmo.

As ferramentas e bibliotecas usadas

O algoritmo que implementei tem basicamente as seguintes etapas, preparação de dados e criação do modelo LDA. A preparação de dados envolve tokenização, remoção de palavras irrelevantes (stopwords), lematização e n_grams, e a criação do modelo LDA envolve criar um dicionário, um corpus e o modelo LDA propriamente dito.

Para implementar este algoritmo foi utilizado a linguagem Python e as seguintes bibliotecas, o Gensim para criar o modelo LDA e os n_grams, o Pandas para ler arquivos JSON, o simple_process do Gensim para tokenização, o NLTK para remoção de stopwords, e o Spacy para lematização.

# Importing required libraries import gensim import pandas as pd import spacy import nltk from gensim.corpora import Dictionary from gensim.utils import simple_preprocess from nltk.corpus import stopwords from pprint import pprint nlp = spacy.load('pt_core_news_sm') # Loading models for lemmatization in the Portuguese language nltk.download('stopwords') # Downloading the NLTK's stopwords dictionary stop_words = stopwords.words('portuguese') # Loading NLTK's stopwords dictionary in the Portuguese language

Para gerenciar as bibliotecas foi usado o ambiente de desenvolvimento Pycharm e o projeto de código aberto Anaconda .

Os códigos são inspirado nesse tutorial: https://www.machinelearningplus.com/nlp/topic-modeling-gensim-python/ . Eu adaptei e organizei o código para este estudo de caso, então o código está um pouco diferente do tutorial.

Sobre as amostras

Os discursos dos políticos foram coletados no site da Câmara dos Deputados , basicamente, pesquisei o nome do candidato no site e copiei e colei seus discursos em um arquivo externo usando o mouse, depois coloquei os dados em um formato JSON usando o Notepad++ .

O arquivo JSON usado nesse projeto pode ser acessado neste link .

Independentemente do formato ou dos dados que deseja usar, é necessário converter esse arquivo em uma lista de strings. Portanto, se você quiser usar esse algoritmo em outros estudos de caso, lembre-se de fazer as adaptações necessárias.

Explicando cada passo da preparação de dados

Para entendermos melhor as etapas de preparação dos dados, eu criei um diálogo fictício entre duas pessoas e salvei em uma variável de lista de strings.

[' - Meu cachorro engordou uns 3 quilos, aquela nova ração que comprei para ele é muito boa. - Qual o nome do cachorro? - Max, eu postei umas fotos dele nas redes sociais uns 3 dias atrás', '- Oi, você viu o que postei no meu perfil? - Olhei, eu estava navegando pelas redes sociais também e encontrei um notebook barato', '- Ou eu comprei aquele notebook estava na promoção, a loja vendeu com 20% de desconto.']

A primeira etapa é a tokenização, nesta etapa, a lista de strings é transformada em um array de strings, também são removidos números, pontuação e letras isoladas.

[['meu', 'cachorro', 'engordou', 'uns', 'quilos', 'aquela', 'nova', 'ração', 'que', 'comprei', 'para', 'ele', 'muito', 'boa', 'qual', 'nome', 'do', 'cachorro', 'max', 'eu', 'postei', 'umas', 'fotos', 'dele', 'nas', 'redes', 'sociais', 'uns', 'dias', 'atrás'], ['oi', 'você', 'viu', 'que', 'postei', 'no', 'meu', 'perfil', 'olhei', 'eu', 'estava', 'navegando', 'pelas', 'redes', 'sociais', 'também', 'encontrei', 'um', 'notebook', 'barato'], ['ou', 'eu', 'comprei', 'aquele', 'notebook', 'estava', 'na', 'promoção', 'loja', 'vendeu', 'com', 'de', 'desconto']]

Em modelagem de tópico é comum ouvir os termos, palavras, documentos, e corpus, onde documentos é um conjunto de palavras e corpus um conjunto de documentos. Para o algoritmo, cada elemento da matriz é uma palavra, cada linha da matriz é um documento e a matriz é o corpus.

O segundo passo é a remoção das stopwords, stopwords são palavras comuns da linguagem e não têm significado relevante para a formação dos tópicos. Se você não remover as palavras irrelevantes, o algoritmo considerará essas palavras para formar os tópicos, então em vez de lei, polícia, justiça o algoritmo pode retornar as, para, justiça. Após a remoção das stopwords, o resultado foi:

[['cachorro', 'engordou', 'uns', 'quilos', 'nova', 'ração', 'comprei', 'boa', 'nome', 'cachorro', 'max', 'postei', 'umas', 'fotos', 'redes', 'sociais', 'uns', 'dias', 'atrás'], ['oi', 'viu', 'postei', 'perfil', 'olhei', 'navegando', 'redes', 'sociais', 'encontrei', 'notebook', 'barato'], ['comprei', 'notebook', 'promoção', 'loja', 'vendeu', 'desconto']]

As seguintes palavras foram removidas: ‘meu’, ‘aquela’, ‘que’, ‘para’, ‘ele’, ‘muito’, ‘qual’, ‘do’, ‘eu’, ‘dele’, ‘nas’, ‘você’, ‘no’, ‘meu’, ‘estava’, ‘pelas’, ‘também’, ‘um’, ‘ou’, ‘aquele’, ‘com’, ‘de’. O próximo passo é a lematização, observe o resultado abaixo:

[['cachorro', 'engordar', 'um', 'quilo', 'novo', 'ração', 'comprar', 'bom', 'nome', 'cachorro', 'max', 'postar', 'umar', 'foto', 'rede', 'social', 'um', 'dia', 'atrás'], ['oi', 'ver', 'postar', 'perfil', 'olhar', 'navegar', 'rede', 'social', 'encontrar', 'notebook', 'baratar'], ['comprar', 'notebook', 'promoção', 'loja', 'vender', 'descontar']]

A lematização transforma a palavra em sua "versão raiz", então palavras como 'engordou' se tornam 'engordar' e 'quilos' se tornam 'quilo'. O Spacy usa modelos estatísticos para descobrir se uma palavra é um verbo ou um substantivo, então em alguns casos, eles falham, neste caso, o Spacy pensa que a palavra 'barato' é um verbo, por isso 'barato' torne-se 'baratar'. Esta etapa é importante porque o algoritmo analisa apenas a sintaxe, não a semântica, então por exemplo, as palavras cachorro e cachorros têm o mesmo significado, porém, a sintaxe é diferente, então o algoritmo entende isso como duas palavras com um significado diferente.

A próximo passo é o n_gram, nesta etapa, palavras que muitas vezes aparecem juntas são conectadas com um underline, por exemplo, mídia social torna-se mídia_social, então o algoritmo entende mídia social como uma palavra com o mesmo significado em vez de duas palavras com significado diferente. Este passo é importante pelo mesmo motivo que a lematização.

[['cachorro', 'engordar', 'um', 'quilo', 'novo', 'ração', 'comprar', 'bom', 'nome', 'cachorro', 'max', 'postar', 'umar', 'foto', 'rede_social', 'um', 'dia', 'atrás', 'rede_social'], ['oi', 'ver', 'postar', 'perfil', 'olhar', 'navegar', 'rede_social', 'encontrar', 'notebook', 'baratar'], ['comprar', 'notebook', 'promoção', 'loja', 'vender', 'descontar']]

O n_gram possui dois métodos para conectar as palavras que aparecem frequentemente juntas, o primeiro e o que estamos usando é o original_score , o segundo é npmi_score , esses métodos calculam a pontuação entre duas palavras, com base nessa pontuação o algoritmo conecta as palavras. Cada método recebe parâmetros, alterando os valores desses parâmetros pode gerar resultados diferentes, neste caso, usei min_count = 2 e threshold = 10.

Criando um dicionário e um corpus

Agora com os dados prontos, vamos criar um dicionário, ou seja, vamos atribuir um identificador (número) para a palavra, logo em seguida vamos criar um corpus, esse corpus contém a palavra e a quantidade de vezes que ela aparece no documento, veja o exemplo abaixo.

[[('atrás', 1), ('bom', 1), ('cachorro', 2), ('comprar', 1), ('dia', 1), ('engordar', 1), ('foto', 1), ('max', 1), ('nome', 1), ('novo', 1), ('postar', 1), ('quilo', 1), ('ração', 1), ('rede_social', 2), ('um', 2), ('umar', 1)], [('postar', 1), ('rede_social', 1), ('baratar', 1), ('encontrar', 1), ('navegar', 1), ('notebook', 1), ('oi', 1), ('olhar', 1), ('perfil', 1), ('ver', 1)], [('comprar', 1), ('notebook', 1), ('descontar', 1), ('loja', 1), ('promoção', 1), ('vender', 1)]]

Lembre-se de que cada linha da matriz é um documento.

# Adding more words in the stopwords dictionary stop_words.extend(['ir', 'aqui', 'ter', 'todo', 'fazer', 'dizer', 'falar', 'estar', 'hoje', 'algum', 'outro', 'ser', 'querer', 'qualquer', 'nado', 'porque', 'vir', 'partir', 'governar', 'deputar', 'parlamentar', 'sr', 'presidente', 'vice', 'discursar', 'parecer', 'vez', 'dar', 'ex', 'sim', 'levar', 'quase', 'chance', 'ano', 'além', 'sob', 'termo', 'sempre', 'nenhum', 'coisa', 'frase', 'diverso', 'olhar', 'exas', 'aliás', 'ficar', 'tanto', 'saber', 'colocar', 'tão', 'dia', 'senhor', 'então', 'tipo', 'lado', 'palavra', 'gente', 'apresentar', 'continuar', 'lá', 'nº', 'nome', 'exª', 'ali', 'câmara', 'comissão']) def tokenization(texts_list): for text in texts_list: yield (gensim.utils.simple_preprocess(str(text), deacc=False)) def remove_stopwords(matrix): return [[word for word in simple_preprocess(str(line)) if word not in stop_words] for line in matrix] def lemmatization(matrix): matrix_out = [] for line in matrix: doc = nlp(" ".join(line)) matrix_out.append([word.lemma_ for word in doc]) return matrix_out def n_grams(matrix): n_grams_model = gensim.models.Phrases(matrix, min_count=2, threshold=10) matrix_out = gensim.models.phrases.Phraser(n_grams_model) return [matrix_out[line] for line in matrix] def create_dictionary(matrix): return Dictionary(matrix) def create_corpus(id2word, matrix): return [id2word.doc2bow(line) for line in matrix] df = pd.read_json('Arquivos json/KimKataguiri 2019.json', encoding="utf8") database = df.discursos.values.tolist() # Convert from text to list data_processing = list(tokenization(database)) # Convert in array, remove numbers, punctuation e isolated letters data_processing = remove_stopwords(data_processing) data_processing = lemmatization(data_processing) # Transforms the word in its "root version" data_processing = remove_stopwords(data_processing) data_processing = n_grams(data_processing) # Connect two words that appear often together data_processing = n_grams(data_processing) data_processing = remove_stopwords(data_processing) dictionary = create_dictionary(data_processing) # Assign a ID for each word print(len(dictionary)) dictionary.filter_extremes(no_below=2) # remove the words that appear in less than 2 documents print(len(dictionary)) corpus = create_corpus(dictionary, data_processing) lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=5, passes=5, random_state=100, chunksize=5) pprint(lda_model.show_topics(num_words=10, formatted=False)) lda_model.save('LDA model/my_lda.model')

1

Ir para a página

2

Minhas mídias sociais 😊

Meu portfolio

lattes curriculum

Contate-me 🤗

mail

tsukasa.renato@gmail.com

14 997468186