Nuvem de Palavras com Python para Amantes de Literatura
Recentemente, descobri um novo passatempo: pegar os meus livros favoritos em PDF e transformá-los em nuvens de palavras - claro, com Python! Afinal, para quem gosta de programação de verdade, o ato de criar coisas legais com as suas próprias habilidades não se restringe a trabalho, não é mesmo?
Por isso, decidi escrever este artigo para ajudar outros amantes de literatura como eu a criar as suas próprias nuvens, como esta:
A nuvem acima foi criada a partir do livro "O Pequeno Príncipe", de Antoine de Saint-Exupéry. Percebam que há algumas palavras que não fazem sentido, mas isso não é um problema da nuvem - é apenas uma questão de tratamento de dados, pois essa etapa faz parte de um projeto maior ainda em desenvolvimento, e o tratamento não foi finalizado.
Mas chega de introdução e vamos aprender!
1. Setup
As etapas que vou trazer aqui foram todas feitas pelo Google Colab, então talvez você vá precisar fazer algumas alterações caso use uma plataforma diferente para criar o seu notebook.
1.1 - Instalação de Bibliotecas
Em primeiro lugar, é necessário garantir que todas as bibliotecas necessárias estão instaladas no Colab. Pela minha experiência, vai ser necessário instalar apenas a PyPDF2 e wordcloud. No Colab, você pode fazer isso com:
!pip install <nome-da-biblioteca>
1.2 - Importação das Bibliotecas
Para importar as bibliotecas PyPDF2, Pandas e o matplotlib.pyplot, simplesmente use:
import <nome-da-biblioteca> as <apelido>
Porém, para as bibliotecas do Colab e do wordcloud, vamos precisar de partes específicas, então é só usar:
from google.colab import files
from wordcloud import WordCloud
Observação: eu só importo a biblioteca do Colab para carregar o PDF no código. Porém, quem é rato da plataforma, sabe que é possível fazer isso também usando a seção de Arquivos.
2. Importação do arquivo
Esse passo só vai ser necessário caso você decida fazer o upload pela função files.upload() do Colab. Caso não, pule para o próximo!
Para importar, use:
variavel_com_pdf = files.upload()
Daí, a plataforma vai pedir que você selecione o arquivo para carregar - pode ser tanto do PC, quanto do Drive.
3. Extração das palavras
Para criar a nuvem, vamos precisar extrair todas as palavras do PDF. (Por isso, use um arquivo que não seja um mero escaneamento!)
3.1 - Criação de uma função
Na minha experiência com programação, especialmente Python, eu fui aprendendo aos poucos a importância da criação de funções para facilitar o workflow. Neste projeto, a função a seguir vai ser usada apenas uma vez, mas vale a pena adicioná-la ao seu repositório pessoal de funções depois!
O código é o seguinte:
def extrair_palavras(caminho):
palavras = []
leitor_pdf = pdf.PdfReader(caminho)
for pagina in range(len(leitor_pdf.pages)):
conteudo = leitor_pdf.pages[pagina]
texto = conteudo.extract_text()
palavras += texto.split()
return palavras
Em poucas palavras, o que essa função vai fazer é percorrer o PDF página a página, extrair todo o texto encontrado nelas, separá-lo em palavras e carregar todas elas em uma lista. Por último, ela retorna a lista para que a gente possa aproveitar em outra função.
3.2 - Extração real e criação do DataFrame
Depois disso, basta usar o caminho do arquivo PDF (no formato string) como parâmetro da função criada e depois salvar tudo em um dataframe do Pandas.
Entretanto, se você optar por importar o arquivo pelo files.upload() como eu, há um passo adicional antes: é necessário extrair o caminho do PDF para usá-lo na função. Para isso acontecer, basta usar:
caminho = list(variavel_com_pdf.keys())[0]
Aí, sim, você pode fazer a extração:
variavel_palavras = extrair_palavras(caminho)
df = pd.DataFrame({'Nome_Coluna': variavel_palavras})
4. Higienização das palavras
Sim, eu sei que o termo higienização está, de certa forma, obsoleto, mas eu amo usá-lo porque o acho muito engraçado, então vamos deixar assim.
O que nos importa é: este passo é sobre fazer alguns tratamento nas palavras a fim de deixá-las o mais apresentável possível para a "foto" (a nuvem, no caso).
4.1 - Criação de função
Lembra quando citei acima sobre a importância de criar funções para um repositório pessoal para melhorar o nosso workflow? Então, aqui vai mais uma:
def remover_pontua(dataframe):
pontua = ['.', ',', '-', ':', ';', '...', '—', '(', ')', '"', '', ' ', '!', '?']
for p in pontua:
dataframe['Palavra'] = dataframe['Palavra'].apply(lambda x: x.strip(p))
A função acima vai nos ajudar a remover pontuações das palavras, já que a outra função criada anteriormente não faz isso de forma automática. (Claro que, se você quiser, pode empacotar tudo isso em uma função só!) Além disso, há dois aspectos importantes a serem percebidos aqui:
- Na variável 'pontua', eu criei uma lista com as principais pontuações que, provavelmente, estariam no texto. Caso você perceba que há outras no arquivo que utilizar, pode incrementar a lista, ou até mesmo importar um arquivo .txt com todas as pontuações (há alguns na internet).
- Eu defini a coluna do dataframe parâmetro como 'Palavra' porque, no meu projeto, costumo usar esse mesmo nome para todos os PDFs que eu passei pelo código. Caso você deseje usar nomes diferentes a cada novo PDF que carregar, pode usar o index da coluna (1) para isso, mas acho pouco provável que será necessário.
4.2 - Aplicação da função e últimos ajustes
Agora é só chamar a função usando o dataframe como parâmetro:
remover_pontua(df)
Algo importante que percebi é que a função .strip() substitui os os itens da lista por espaços, então vale removê-los. Para isso, use:
df = df.drop(df[df['Palavra'] == ''].index)
df = df.drop(df[df['Palavra'] == ' '].index)
df = df.drop(df[df['Palavra'] == ' '].index)
(Acredite: as três linhas serão necessárias!)
Outro ponto aqui é que a função .strip() só remove os itens da lista quando estes são encontrados no início ou no final da string. Isso faz com que, se você estiver utilizando um texto em Português, os casos de ênclise ("faz-me", "disse-lhe" etc) e mesóclise ("dar-te-ão", "abençoa-lo-á" etc) não percam o hífen. Por isso, vamos precisar separar esas palavras em duas (ou três) usando o código:
df['Palavra'] = df['Palavra'].str.split('-')
df = df.explode('Palavra').reset_index(drop=True)
Isso vai separar as palavras usando o hífen como delimitador, depois registrá-las em linhas diferentes do dataframe e, por último, resetar a indexação dele.
Para finalizar esta etapa, faz sentido deixar tudo em letras minúsculas. Então, faça o seguinte:
df['Palavra'] = df['Palavra'].str.lower()
Observação: quando eu fiz essa higienização com o PDF do Pequeno Príncipe, percebi que algumas palavras, por algum motivo, continuaram com pontuação. Por isso, rodei a função remover_pontua() uma última vez para garantir.
5. Criação da nuvem
Chegamos à última etapa! \o/
Esta é bem curtinha e envolve três passos: juntar as palavras em uma única string; criar a nuvem; e plotar tudo em uma imagem.
Se você quiser, antes, pode remover as palavras duplicadas para facilitar o processo (eu recomendo, inclusive). Só usar:
dfNovo = df.drop_duplicates()
Para juntar tudo em uma string, use o:
visual = ' '.join(dfNovo['Palavra'])
Para criar a nuvem, use:
nuvem = WordCloud(width=800, height=600, background_color='white').generate(visual)
(Se quiser criar uma imagem com proporção diferente, só alterar os valores de width [largura] e height [altura]. Você pode também escolher outras cores de fundo usando 'blue' [azul], 'green' [verde], 'red' [vermelho] etc no lugar de 'white' [branco].)
Por último, basta plotar tudo:
plt.figure(figsize=(10, 6))
plt.imshow(nuvem, interpolation='bilinear')
plt.axis('off')
plt.show()
(Percebam que 'plt' é o apelido que eu dei para o pyplot do matplotlib. Se você usar outro apelido, ajuste o código.)
6. Observações e considerações finais
Tcharam! Está feita a sua nuvem, agora é só compartilhar!
É possível que você perceba que os artigos (o, a, os, as etc) e várias stopwords vão estar na nuvem. Se você não quiser que elas apareçam, basta carregar um arquivo .txt com as palavras, salvar em uma lista e usar, logo antes da criação da nuvem, o seguinte código:
for termo in stopwords:
for palavra in df['Palavra']:
if termo == palavra:
df = df.drop(df[df['Palavra'] == termo].index)
E é isso! Botem o projeto em prática, façam as suas próprias nuvens e compartilhem no Instagram, Facebook e onde mais for. Inclusive, se quiserem compartilhar aqui, basta comentar com o link da sua publicação! Vou adorar ir ver e curtir.
Se quiserem ver o meu notebook no Colab com o projeto completo, só clicar aqui. Porém, não se esqueçam: ele faz parte de um projeto maior, então vocês vão encontrar muitas outras coisas lá!