O que se passa na cabeça de um gênio? Contando as palavras da obra Dom Casmurro, de Machado de Assis.

Christian Zambra
productmanagerslife
8 min readMar 9, 2024
Capitu e Machado de Assis, ilustração feita por Christian Zambra usando leonardo.ai.

Quais as palavras mais citadas na obra Dom Casmurro?

Neste post, descrevo abaixo um código em Python para classificar e contar palavras. E o texto em uma das obras mais emblemáticas de um gênio da literatura Brasileira e Mundial, Machado de Assis.

Ao falar em Dom Casmurro, é do Bentinho que você lembra?

Machado de Assis nasceu em uma família pobre, no Morro do Livramento, Rio de Janeiro. Descendente de negros alforriados e portugueses, é tido por críticos como Harold Bloom como o maior escritor negro de todos os tempos.

Seu livro, publicado no ano de 1899, é narrado no segundo império. Vale lembrar que em 1888 foi proclamada a abolição da escravatura no Brasil, e em 1889 a proclamação da república.

Em um cenário de profundas mudanças, Machado de Assis traz as memórias de Dom Casmurro, ou Bentinho. Nestas memórias se destacam o ciúme a desconfiança dele em relação à sua esposa, que foi sua namorada desde a infância. A ideia de que tenha sido traído por ela com seu melhor amigo, bem como de que seu filho na verdade seja fruto dessa traição. E a desconfiança entre classes, dado que apesar de vizinhos desde a infância, Bentinho era de uma família rica, e sua namorada e futura esposa de uma família pobre.

Capitu.

Vamos aos resultados: O nome Bentinho (o Dom Casmurro) aparece 56 vezes na obra. O nome Ezequiel 50 vezes(a maioria se referindo ao filho de Bentinho e poucas ao primeiro nome de Escobar). Escobar aparece 109 vezes. E, como a maior presença de maneira incontestável, o nome que mais aparece é Capitu, 338 vezes. Vale lembrar que o livro tem 139 páginas.

O personagem mais marcante do livro é Capitu.

Não a toa, é o primeiro personagem de quem lembramos. A personagem descrita pelos olhos de um marido ciumento, num romance que trás dúvidas e interpretações distintas através dos séculos. A personagem vista com desconfiança como a vizinha pobre. A “morena, olhos claros e grandes, nariz reto e comprido, tinha a boca fina e o queixo largo”, “olhos de ressaca”, “olhos de cigana oblíqua e dissimulada”. Os olhos de cigana são clara referência a outra mulher literária, Carmen, a da ópera de Bizet e do livro que deu origem à ópera, do autor Prosper Merimée. Uma referência a outra mulher de uma classe marginalizada, e também protagonista de uma tragédia.

Conclusão (calma, o código vem em seguida)

Apesar de ser uma pessoa de produtos apaixonada por AI, e não um crítico literário, me arriscarei aqui a compartilhar algumas conclusões.

O que se passou na cabeça desse gênio foi Capitu.

Mais que o narrador, mais que sua família, mais que seu filho e mais que o potencial amigo que o traiu, o que se passou na cabeça de Machado de Assis foi Capitu. A descrição dessa mulher, morena, pobre, inteligente, líder (salvou o Bentinho do seminário) que assusta a classe dominante é a grande criação genial do autor negro pobre que ascendeu para as mais altas e intelectuais classes do império e da república. Desde o princípio, e propositalmente, estava na mente do autor a construção de descrição desta personagem que representa um momento histórico tão marcante.

Ousaria comparar Capitu a uma pintura, uma obra de arte capaz de representar seu tempo e ser reinterpretada nas gerações seguintes. Machado de Assis colocou nela as características, tensões e conflitos da sociedade de seu tempo e que perduram até hoje.

Olhando para essa contagem de palavras, eu tenho claro em minha mente que quando Machado de Assis escreveu o livro Dom Casmurro, o que ele tinha como objetivo, o que estava claro em sua mente e ele citou mais de 300 vezes, foi Capitu.

Contar Palavras em Python

Eu rodei o código no Google Colab, e o disponibilizei no GitHub, link ao final do post. O código foi escrito com a ajuda do ChatGPT, tendo sido ajustado para versões atuais das bibliotecas e objetivos específicos (como ignorar palavras específicas na contagem).

Inicialmente, instalamos o PyPDF2, para poder ler o arquivo do livro Dom Casmurro.

!pip install PyPDF2 unidecode

Em seguida instalei o SpaCy, um dos melhores classificadores de palavras do mercado, junto com uma bilioteca para lingua portuguesa.

!python -m spacy download pt_core_news_sm

Aqui importamos as principais bibliotecas

import PyPDF2
from collections import Counter
import re
from unidecode import unidecode
import spacy

E aqui eu conecto no Google Drive, onde está o arquivo do livro a ser analisado. Importante notar que ao rodar esse trecho, o arquivo pedirá autorização para acessar o seu Google Drive.

from google.colab import drive
drive.mount('/content/drive')

Aqui, crio a primeira função de contar palavras. Ela simplesmente conta quantas vezes as palavras se repentem, e tem como argumentos de entrada o endereço de onde o .pdf está (file_path), e as palavras que não devem ser contempladas na contagem (exclude_words). Isso se dá pois existem diversas palavras que aparecem diversas vezes em qualquer texto e não são relevantes para a análise, como “o”, “e”, “da”, “do”, etc.

def read_pdf_count_words(file_path, exclude_words=[]):
# Open the PDF file in binary mode
with open(file_path, 'rb') as file:
# Create a PDF reader object
pdf_reader = PyPDF2.PdfReader(file)

# Initialize an empty string to store the extracted text
text = ''

# Iterate through each page and extract text
for page_num in range(len(pdf_reader.pages)):
page = pdf_reader.pages[page_num]
text += page.extract_text()

# Normalize the text to remove accents and convert to lowercase
normalized_text = unidecode(text.lower())

# Use regular expression to extract words (ignoring non-alphanumeric characters)
words = re.findall(r'\b\w+\b', normalized_text)

# Exclude specified words
filtered_words = [word for word in words if word not in exclude_words]

# Count the occurrences of each word
word_counts = Counter(filtered_words)

# Get the top n words
top_words = word_counts.most_common(100)

# Display the results
print(f"Total words: {len(words)}")
print("Top 5 words:")
for word, count in top_words:
print(f"{word}: {count}")

Na função abaixo (de certa forma redundante à primeira), utilizamos o SpaCy para classificar as palavras em nomes, verbos, etc, e trazer as mais relevantes. Eu utilizei as duas funções em paralelo.

def classify_and_list_top_n(file_path, exclude_words=[], top_n=5):
# Open the PDF file in binary mode
with open(file_path, 'rb') as file:
# Create a PDF reader object
pdf_reader = PyPDF2.PdfReader(file)

# Initialize an empty string to store the extracted text
text = ''

# Iterate through each page and extract text
for page_num in range(len(pdf_reader.pages)):
page = pdf_reader.pages[page_num]
text += page.extract_text()

# Normalize the text to remove accents and convert to lowercase
normalized_text = unidecode(text.lower())

# Use regular expression to extract words (ignoring non-alphanumeric characters)
words = re.findall(r'\b\w+\b', normalized_text)

# Exclude specified words
filtered_words = [word for word in words if word not in exclude_words]

# Join the filtered words into a string
text_for_spacy = ' '.join(filtered_words)

# Load spaCy with the Portuguese model
nlp = spacy.load('pt_core_news_sm')

# Process the text with spaCy
doc = nlp(text_for_spacy)

# Initialize counters for nouns and verbs
noun_counts = Counter()
verb_counts = Counter()

propn_counts = Counter()
num_counts = Counter()
adp_counts = Counter()
aux_counts = Counter()
det_counts = Counter()

# Classify words into nouns and verbs
for token in doc:
if token.pos_ == 'NOUN':
noun_counts[token.text] += 1
elif token.pos_ == 'VERB':
verb_counts[token.text] += 1

elif token.pos_ == 'PROPN':
propn_counts[token.text] += 1
elif token.pos_ == 'NUM':
num_counts[token.text] += 1
elif token.pos_ == 'ADP':
adp_counts[token.text] += 1
elif token.pos_ == 'AUX':
aux_counts[token.text] += 1
elif token.pos_ == 'DET':
det_counts[token.text] += 1




# Get the top N most used nouns and verbs
top_n_nouns = [word for word, count in noun_counts.most_common(top_n)]
top_n_verbs = [word for word, count in verb_counts.most_common(top_n)]

top_n_propn = [word for word, count in propn_counts.most_common(top_n)]
top_n_num = [word for word, count in num_counts.most_common(top_n)]
top_n_adp = [word for word, count in adp_counts.most_common(top_n)]
top_n_aux = [word for word, count in aux_counts.most_common(top_n)]
top_n_det = [word for word, count in det_counts.most_common(top_n)]

# Display the results
print(f"In the text, the {top_n} most used nouns are: {', '.join(top_n_nouns)}")
print(f"The {top_n} most used verbs are: {', '.join(top_n_verbs)}")

print(f"The {top_n} most used proper name are: {', '.join(top_n_propn)}")
print(f"The {top_n} most used numbers are: {', '.join(top_n_num)}")
print(f"The {top_n} most used adp are: {', '.join(top_n_adp)}")
print(f"The {top_n} most used aux are: {', '.join(top_n_aux)}")
print(f"The {top_n} most used det are: {', '.join(top_n_det)}")

Aqui, eu executei a primeira função. Customizei o arquivo exclude_words com uma lista de stop_words genérica, da qual exclui alguns termos, e acrecentei diversos outros específicos desse livro. A cada vez que rodava, via termos não relevantes aparecendo e os excluía através dessa lista de exclude_words.

if __name__ == "__main__":
# Specify the correct filename in the path
pdf_file_path = '/content/drive/MyDrive/teste_conta_palavras/DomCasmurro.pdf'

exclude_words = [
#lista generica de stop words
'de', 'a', 'o', 'que', 'e', 'do', 'da', 'em', 'um', 'para', 'é', 'com', 'não', 'uma', 'os', 'no', 'se', 'na', 'por', 'mais', 'as', 'dos', 'como', 'mas', 'ao', 'ele', 'das', 'à', 'seu', 'sua', 'ou', 'ser', 'quando', 'muito', 'há', 'nos', 'já', 'eu', 'também', 'só', 'pelo', 'pela', 'até', 'isso', 'ela', 'entre', 'depois', 'sem', 'mesmo', 'aos', 'seus', 'quem', 'nas', 'me', 'esse', 'eles', 'estão', 'você', 'essa', 'num', 'nem', 'suas', 'meu', 'às', 'minha', 'têm', 'numa', 'pelos', 'elas', 'havia', 'seja', 'qual', 'será', 'nós', 'tenho', 'lhe', 'deles', 'essas', 'esses', 'pelas', 'este', 'fosse', 'dele', 'tu', 'te', 'vocês', 'vos', 'lhes', 'meus', 'minhas', 'teu', 'tua', 'teus', 'tuas', 'nosso', 'nossa', 'nossos', 'nossas', 'dela', 'delas', 'esta', 'estes', 'estas', 'aquele', 'aquela', 'aqueles', 'aquelas', 'isto', 'aquilo',
#palavras/verbos da lista generica que inclui na busca (tirei do stop words)
# 'foi', 'tem', 'ter','tinha', 'foram', 'está', 'era', 'estou', 'está', 'estamos', 'estão', 'estive', 'esteve', 'estivemos', 'estiveram', 'estava', 'estávamos', 'estavam', 'estivera', 'estivéramos', 'esteja', 'estejamos', 'estejam', 'estivesse', 'estivéssemos', 'estivessem', 'estiver', 'estivermos', 'estiverem', 'hei', 'há', 'havemos', 'hão', 'houve', 'houvemos', 'houveram', 'houvera', 'houvéramos', 'haja', 'hajamos', 'hajam', 'houvesse', 'houvéssemos', 'houvessem', 'houver', 'houvermos', 'houverem', 'houverei', 'houverá', 'houveremos', 'houverão', 'houveria', 'houveríamos', 'houveriam', 'sou', 'somos', 'são', 'era', 'éramos', 'eram', 'fui', 'foi', 'fomos', 'foram', 'fora', 'fôramos', 'seja', 'sejamos', 'sejam', 'fosse', 'fôssemos', 'fossem', 'for', 'formos', 'forem', 'serei', 'será', 'seremos', 'serão', 'seria', 'seríamos', 'seriam', 'tenho', 'tem', 'temos', 'tém', 'tinha', 'tínhamos', 'tinham', 'tive', 'teve', 'tivemos', 'tiveram', 'tivera', 'tivéramos', 'tenha', 'tenhamos', 'tenham', 'tivesse', 'tivéssemos', 'tivessem', 'tiver', 'tivermos', 'tiverem', 'terei', 'terá', 'teremos', 'terão', 'teria', 'teríamos', 'teriam',
#lista especifica de stop words, para Dom Casmurro
'nao','tambem','tudo','ja','assim','ha','vez','agora','la','so','mim','outra','ainda','nada','tempo','dia','voce','lo','tao','outro','ate','entao','dizer','cousa','ia','bem','fez',
#'disse',
#lista de palavras de marcação, ligadas à publicacao do livro: Editora, etc.
'www','capitulo','nead','unama','br']

read_pdf_count_words(pdf_file_path, exclude_words)

E aqui eu executo a função do SpaCy. Note que, como a biblioteca identifica e classifica os termos, reduzi significantemente a lista de exclude_words. Infelizmente o SpaCy não está perfeitamente calibrado para Português do Brasil, e trás varias palavras que não são nomes como nomes por exemplo. Mas ampliando a lista de resultados, é possível trazer uma lista e corrigir manualmente.

if __name__ == "__main__":
# Specify the correct filename in the path
pdf_file_path = '/content/drive/MyDrive/teste_conta_palavras/DomCasmurro.pdf'

# Specify the list of words to exclude from the count
#exclude_words = ["a", "e", "o", "lhe"] # Add more words as needed
exclude_words = ['www','capitulo','nead','unama','br']
# Specify the number of most used words to display
top_n = 10

classify_and_list_top_n(pdf_file_path, exclude_words, top_n)

É importante notar que, em ambos os métodos, temos como nome mais citado o de Capitu. :)

Links:

Código no GitHub: https://github.com/christianzambra/productmanagerslife/blob/main/contar_e_classificar_palavras.ipynb

--

--

Christian Zambra
productmanagerslife

Passionate to learn; believes that new products are made to change people’s life for better; Fuzzy AND Techie :) B. Engineering & Advertising. Alma Matter: USP