Pular para o conteúdo principal

Frequência absoluta e ponderada de palavras em texto

Neste tutorial, você vai aprender sobre frequência absoluta e ponderada de palavras em mineração de texto e como calculá-las com defaultdict e DataFrames do pandas.
Atualizado 17 de set. de 2026  · 15 min lido

Explorar com IA

ChatGPTClaudePerplexity

Um conjunto importante de métricas em mineração de texto está relacionado à frequência de palavras (ou qualquer token) em um determinado corpus de documentos. Mas você também pode usar um conjunto adicional de métricas quando cada documento tiver um valor numérico associado que descreve algum atributo do documento.

Alguns exemplos:

  • Tweets e seus respectivos números de engajamentos.
  • URLs e seus pageviews e rejeições.
  • Títulos de filmes e sua bilheteria total.
  • Palavras-chave e suas impressões, cliques e conversões.

Neste tutorial,

  • você primeiro vai passar pelo processo de criar uma função simples que calcula e compara a ocorrência absoluta e ponderada de palavras em um corpus de documentos. Isso às vezes revela tendências e agregados ocultos que não ficam claros ao olhar apenas para os dez primeiros valores. Eles também podem ser bem diferentes da frequência absoluta de palavras.
  • Depois, você vai ver um conjunto de dados do mundo real (títulos de filmes e a bilheteria total) e tentar descobrir tendências escondidas. Um spoiler: o amor vai aparecer de algum jeito!
  • Você vai usar Python como linguagem de programação e aproveitar a estrutura de dados defaultdict do módulo collections para o grosso do trabalho, além de DataFrames do pandas para organizar o resultado final.

Frequência absoluta e ponderada de palavras: introdução

Vamos supor que você tenha dois tweets, com o conteúdo e número de impressões (visualizações) a seguir:

Texto do tweet Visualizações
spain 800
france 200

É simples fazer a análise básica e concluir que suas palavras estão divididas em 50:50 entre "france" e "spain". Em muitos casos, é só isso que você tem, e só dá para medir a frequência absoluta de palavras e tentar inferir certas relações. Aqui, porém, você tem dados sobre cada um dos documentos.

A frequência ponderada, por sua vez, é claramente diferente: a divisão é 80:20. Em outras palavras, embora "spain" e "france" apareçam uma vez cada nos seus tweets, na perspectiva dos leitores, a primeira apareceu 800 vezes, enquanto a segunda apareceu 200 vezes. É uma diferença enorme!

Frequência simples de palavras usando defaultdict

Agora considere um exemplo um pouco mais elaborado para um conjunto semelhante de documentos:

Documento Visualizações
france 200
spain 180
spain beaches 170
france beaches 160
spain best beaches 160

Agora você percorre os documentos, divide em palavras e conta as ocorrências de cada palavra:

 from collections import defaultdict

import pandas as pd

text_list = ['france', 'spain', 'spain beaches', 'france beaches', 'spain best beaches']

word_freq = defaultdict(int)

for text in text_list:
    for word in text.split():
        word_freq[word] += 1

pd.DataFrame.from_dict(word_freq, orient='index') \
.sort_values(0, ascending=False) \
.rename(columns={0: 'abs_freq'})
  abs_freq
spain 3
beaches 3
france 2
best 1

No loop acima, a primeira linha percorre text_list item a item. A segunda linha (dentro de cada documento) percorre as palavras de cada item, dividindo pelo caractere de espaço (que poderia ser qualquer outro caractere: "-", ",", "_", etc.).

Ao tentar atribuir um valor a word_freq[word], há dois cenários possíveis:

  1. A chave word existe: nesse caso a atribuição é feita (somando um)
  2. A chave word não está em word_freq; então o defaultdict chama a função padrão que foi atribuída a ele quando foi definido, que aqui é int.

Quando int é chamada, retorna zero. Agora a chave existe, seu valor é zero e está pronta para receber +1.

Embora a palavra no topo fosse "france" na primeira tabela, depois de contar todas as palavras dentro de cada documento, vemos que "spain" e "beaches" empatam na primeira posição. Isso é importante para revelar tendências ocultas, especialmente quando a lista de documentos com que você lida está na casa das dezenas ou centenas de milhares.

Frequência ponderada de palavras

Agora que você contou as ocorrências de cada palavra no corpus, quer ver a frequência ponderada. Ou seja, quer ver quantas vezes as palavras apareceram para seus leitores, em comparação com quantas vezes você as usou.

Na primeira tabela, a frequência absoluta das palavras foi dividida igualmente entre "spain" e "france", mas "spain" teve muito mais peso, porque seu valor foi 800, contra 200 de "france".

Mas qual seria a frequência ponderada de palavras para a segunda tabela, um pouco mais complexa?

Vamos descobrir!

Você pode reaproveitar parte do código acima, com alguns acréscimos:

 # default value is now a list with two ints
word_freq = defaultdict(lambda: [0, 0]) 

# the `views` column you had in the first DataFrame
num_list = [200, 180, 170, 160, 160]

# looping is now over both the text and the numbers
for text, num in zip(text_list, num_list): 
    for word in text.split(): 
        # same as before
        word_freq[word][0] += 1 
        # new line, incrementing the numeric value for each word
        word_freq[word][1] += num 

columns = {0: 'abs_freq', 1: 'wtd_freq'}

abs_wtd_df = pd.DataFrame.from_dict(word_freq, orient='index') \
             .rename(columns=columns) \
             .sort_values('wtd_freq', ascending=False) \
             .assign(rel_value=lambda df: df['wtd_freq'] / df['abs_freq']) \
            .round()

abs_wtd_df.style.background_gradient(low=0, high=.7, subset=['rel_value'])
  abs_freq wtd_freq rel_value
spain 3 510 170
beaches 3 490 163
france 2 360 180
best 1 160 160

Algumas observações:

  • Embora "france" fosse a expressão mais alta no geral, "spain" e "beaches" parecem mais proeminentes quando você considera a frequência ponderada.
  • rel_value é uma divisão simples para obter o valor por ocorrência de cada palavra.
  • Olhando para rel_value, você também vê que, apesar de "france" estar relativamente baixa em wtd_freq, há potencial ali, porque o valor por ocorrência é alto. Isso pode indicar, por exemplo, ampliar sua cobertura de conteúdo sobre "france".

Você também pode adicionar outras métricas que mostrem as porcentagens e porcentagens acumuladas de cada tipo de frequência, para ter uma perspectiva melhor de quantas palavras formam a maior parte do total, se houver:

 abs_wtd_df.insert(1, 'abs_perc', value=abs_wtd_df['abs_freq'] / abs_wtd_df['abs_freq'].sum())
abs_wtd_df.insert(2, 'abs_perc_cum', abs_wtd_df['abs_perc'].cumsum())
abs_wtd_df.insert(4, 'wtd_freq_perc', abs_wtd_df['wtd_freq'] / abs_wtd_df['wtd_freq'].sum())
abs_wtd_df.insert(5, 'wtd_freq_perc_cum', abs_wtd_df['wtd_freq_perc'].cumsum())
abs_wtd_df.style.background_gradient(low=0, high=0.8)
  abs_freq abs_perc abs_perc_cum wtd_freq wtd_freq_perc wtd_freq_perc_cum rel_value
spain 3 0.333333 0.333333 510 0.335526 0.335526 170
beaches 3 0.333333 0.666667 490 0.322368 0.657895 163
france 2 0.222222 0.888889 360 0.236842 0.894737 180
best 1 0.111111 1 160 0.105263 1 160

Com mais dados, dá para analisar muito mais — e geralmente aparecem boas surpresas.

Como isso ficaria num cenário real, com dados reais?

Vamos olhar títulos de filmes, ver quais palavras são mais usadas nos títulos — que é a frequência absoluta —, e quais palavras estão associadas à maior bilheteria — a frequência ponderada.

O Boxoffice Mojo tem uma lista com mais de 15 mil filmes, junto com sua bilheteria total e posições no ranking. Comece coletando os dados com requests e BeautifulSoup — você também pode explorar o Boxoffice Mojo aqui, se quiser:

 
import requests
from bs4 import BeautifulSoup
 final_list = []

for i in range(1, 156):
    if not i%10:
        print(i)
    page = 'http://www.boxofficemojo.com/alltime/domestic.htm?page=' + str(i) + '&p=.htm'
    resp = requests.get(page)
    soup = BeautifulSoup(resp.text, 'lxml')
    # trial and error to get the exact positions
    table_data = [x.text for x in soup.select('tr td')[11:511]]  
    # put every 5 values in a row
    temp_list = [table_data[i:i+5] for i in range(0, len(table_data[:-4]), 5)] 
    for temp in temp_list:
        final_list.append(temp)
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
boxoffice_df = pd.DataFrame.from_records(final_list)

boxoffice_df.head(10)
  0 1 2 3 4
0 1 Star Wars: The Force Awakens BV $936,662,225 2015
1 2 Avatar Fox $760,507,625 2009^
2 3 Black Panther BV $681,084,109 2018
3 4 Titanic Par. $659,363,944 1997^
4 5 Jurassic World Uni. $652,270,625 2015
5 6 Marvel's The Avengers BV $623,357,910 2012
6 7 BV Star Wars: The Last Jedi 2017
7 8 WB The Dark Knight 2008
8 9 BV Rogue One: A Star Wars Story 2016
9 10 BV Beauty and the Beast (2017) 2017
boxoffice_df.tail(15)
  0 1 2 3 4
15485 15486 The Dark Hours N/A $423 2005
15486 15487 2:22 Magn. $422 2017
15487 15488 State Park Atl $421 1988
15488 15489 The Magician (2010) Reg. $406 2010
15489 15490 Skinless PPF $400 2014
15490 15491 Cinemanovels Mont. $398 2014
15491 15492 Hannah: Buddhism's Untold Journey KL $396 2016
15492 15493 Apartment 143 Magn. $383 2012
15493 15494 The Marsh All. $336 2007
15494 15495 The Chambermaid FM $315 2015
15495 15496 News From Planet Mars KL $310 2016
15496 15497 Trojan War WB $309 1997
15497 15498 Lou! Journal infime Distrib. $287 2015
15498 15499 Intervention All. $279 2007
15499 15500 Playback Magn. $264 2012

Perceba que alguns valores numéricos têm caracteres especiais ($, , e ^) e alguns valores são N/A. Então você precisa tratá-los:

na_year_idx =  [i for i, x in enumerate(final_list) if x[4] == 'n/a'] # get the indexes of the 'n/a' values
new_years = [1998, 1999, 1960, 1973]  # got them by checking online

print(*[(i, x) for i, x in enumerate(final_list) if i in na_year_idx], sep='\n')
print('new year values:', new_years)
(8003, ['8004', 'Warner Bros. 75th Anniversary Film Festival', 'WB', '$741,855', 'n/a'])
(8148, ['8149', 'Hum Aapke Dil Mein Rahte Hain', 'Eros', '$668,678', 'n/a'])
(8197, ['8198', 'Purple Moon (Re-issue)', 'Mira.', '$640,945', 'n/a'])
(10469, ['10470', 'Amarcord', 'Jan.', '$125,493', 'n/a'])
new year values: [1998, 1999, 1960, 1973]
for na_year, new_year in zip(na_year_idx, new_years):
    final_list[na_year][4] = new_year
    print(final_list[na_year], new_year)
['8004', 'Warner Bros. 75th Anniversary Film Festival', 'WB', '$741,855', 1998] 1998
['8149', 'Hum Aapke Dil Mein Rahte Hain', 'Eros', '$668,678', 1999] 1999
['8198', 'Purple Moon (Re-issue)', 'Mira.', '$640,945', 1960] 1960
['10470', 'Amarcord', 'Jan.', '$125,493', 1973] 1973

Agora transforme a lista em um DataFrame do pandas, nomeando as colunas de forma apropriada e convertendo para os tipos de dados desejados.

 import re
regex = '|'.join(['\$', ',', '\^'])

columns = ['rank', 'title', 'studio', 'lifetime_gross', 'year']

boxoffice_df = pd.DataFrame({
    'rank': [int(x[0]) for x in final_list],  # convert ranks to integers
    'title': [x[1] for x in final_list],  # get titles as is
    'studio': [x[2] for x in final_list],  # get studio names as is
    'lifetime_gross': [int(re.sub(regex, '', x[3])) for x in final_list],  # remove special characters and convert to integer
    'year': [int(re.sub(regex, '', str(x[4]))) for x in final_list],  # remove special characters and convert to integer
})
print('rows:', boxoffice_df.shape[0])
print('columns:', boxoffice_df.shape[1])
print('\ndata types:')
print(boxoffice_df.dtypes)
boxoffice_df.head(15)
rows: 15500
columns: 5

data types:
lifetime_gross     int64
rank               int64
studio            object
title             object
year               int64
dtype: object
  lifetime_gross rank studio title year
0 936662225 1 BV Star Wars: The Force Awakens 2015
1 760507625 2 Fox Avatar 2009
2 681084109 3 BV Black Panther 2018
3 659363944 4 Par. Titanic 1997
4 652270625 5 Uni. Jurassic World 2015
5 623357910 6 BV Marvel's The Avengers 2012
6 620181382 7 BV Star Wars: The Last Jedi 2017
7 534858444 8 WB The Dark Knight 2008
8 532177324 9 BV Rogue One: A Star Wars Story 2016
9 504014165 10 BV Beauty and the Beast (2017) 2017
10 486295561 11 BV Finding Dory 2016
11 474544677 12 Fox Star Wars: Episode I - The Phantom Menace 1999
12 460998007 13 Fox Star Wars 1977
13 459005868 14 BV Avengers: Age of Ultron 2015
14 448139099 15 WB The Dark Knight Rises 2012

A palavra "star" está entre as principais, aparecendo em cinco dos quinze filmes do topo — e a série Star Wars tem ainda mais títulos, vários deles no topo também.

Agora vamos usar o código que você desenvolveu e ver como ele funciona nesse conjunto de dados. Não há nada novo no código abaixo — só juntamos tudo em uma única função:

 def word_frequency(text_list, num_list, sep=None):
    word_freq = defaultdict(lambda: [0, 0])

    for text, num in zip(text_list, num_list):
        for word in text.split(sep=sep): 
            word_freq[word][0] += 1 
            word_freq[word][1] += num

    columns = {0: 'abs_freq', 1: 'wtd_freq'}

    abs_wtd_df = (pd.DataFrame.from_dict(word_freq, orient='index')
                 .rename(columns=columns )
                 .sort_values('wtd_freq', ascending=False)
                 .assign(rel_value=lambda df: df['wtd_freq'] / df['abs_freq']).round())

    abs_wtd_df.insert(1, 'abs_perc', value=abs_wtd_df['abs_freq'] / abs_wtd_df['abs_freq'].sum())
    abs_wtd_df.insert(2, 'abs_perc_cum', abs_wtd_df['abs_perc'].cumsum())
    abs_wtd_df.insert(4, 'wtd_freq_perc', abs_wtd_df['wtd_freq'] / abs_wtd_df['wtd_freq'].sum())
    abs_wtd_df.insert(5, 'wtd_freq_perc_cum', abs_wtd_df['wtd_freq_perc'].cumsum())

    return abs_wtd_df
word_frequency(boxoffice_df['title'], boxoffice_df['lifetime_gross']).head()
  abs_freq abs_perc abs_perc_cum wtd_freq wtd_freq_perc wtd_freq_perc_cum rel_value
The 3055 0.068747 0.068747 67518342498 0.081167 0.081167 22100930.0
the 1310 0.029479 0.098227 32973100860 0.039639 0.120806 25170306.0
of 1399 0.031482 0.129709 30180592467 0.036282 0.157087 21572975.0
and 545 0.012264 0.141973 12188113847 0.014652 0.171739 22363512.0
2 158 0.003556 0.145529 9032673058 0.010859 0.182598 57168817.0

Sem surpresa, as "stop words" dominam o topo — isso acontece em quase todas as coleções de documentos. Você também as vê duplicadas, algumas capitalizadas e outras não. Há duas ações claras a tomar:

  1. Remover todas as stop words: dá para fazer isso adicionando um novo parâmetro à função e passando sua própria lista de stop words.
  2. Colocar todas as palavras em minúsculas para evitar duplicatas

Aqui vai uma atualização simples da função (novo parâmetro rm_words, além das linhas 6, 7 e 8):

# words will be expanded
def word_frequency(text_list, num_list, sep=None, rm_words=('the', 'and', 'a')):  
    word_freq = defaultdict(lambda: [0, 0])

    for text, num in zip(text_list, num_list):
        for word in text.split(sep=sep): 
            # This should take care of ignoring the word if it's in the stop words
            if word.lower() in rm_words:  
                continue                  
            # .lower() makes sure we are not duplicating words
            word_freq[word.lower()][0] += 1  
            word_freq[word.lower()][1] += num

    columns = {0: 'abs_freq', 1: 'wtd_freq'}

    abs_wtd_df = (pd.DataFrame.from_dict(word_freq, orient='index')
                 .rename(columns=columns )
                 .sort_values('wtd_freq', ascending=False)
                 .assign(rel_value=lambda df: df['wtd_freq'] / df['abs_freq']).round())

    abs_wtd_df.insert(1, 'abs_perc', value=abs_wtd_df['abs_freq'] / abs_wtd_df['abs_freq'].sum())
    abs_wtd_df.insert(2, 'abs_perc_cum', abs_wtd_df['abs_perc'].cumsum())
    abs_wtd_df.insert(4, 'wtd_freq_perc', abs_wtd_df['wtd_freq'] / abs_wtd_df['wtd_freq'].sum())
    abs_wtd_df.insert(5, 'wtd_freq_perc_cum', abs_wtd_df['wtd_freq_perc'].cumsum())

    abs_wtd_df = abs_wtd_df.reset_index().rename(columns={'index': 'word'})

    return abs_wtd_df
from collections import defaultdict
word_freq_df =  word_frequency(boxoffice_df['title'], 
                               boxoffice_df['lifetime_gross'],
                               rm_words=['of','in', 'to', 'and', 'a', 'the', 
                                         'for', 'on', '&', 'is', 'at', 'it',
                                         'from', 'with'])



word_freq_df.head(15).style.bar(['abs_freq', 'wtd_freq', 'rel_value'],
                                               color='#60DDFF') # E6E9EB

  word abs_freq abs_perc abs_perc_cum wtd_freq wtd_freq_perc wtd_freq_perc_cum rel_value
0 2 158 0.00443945 0.00443945 9032673058 0.0137634 0.0137634 5.71688e+07
1 star 45 0.0012644 0.00570385 5374658819 0.00818953 0.0219529 1.19437e+08
2 man 195 0.00547907 0.0111829 3967037854 0.0060447 0.0279976 2.03438e+07
3 part 41 0.00115201 0.0123349 3262579777 0.00497129 0.0329689 7.95751e+07
4 movie 117 0.00328744 0.0156224 3216050557 0.00490039 0.0378693 2.74876e+07

Vamos olhar o mesmo DataFrame ordenado por abs_freq:

(word_freq_df.sort_values('abs_freq', ascending=False)
 .head(15)
    .style.bar(['abs_freq', 'wtd_freq', 'rel_value'],
               color='#60DDFF'))

  word abs_freq abs_perc abs_perc_cum wtd_freq wtd_freq_perc wtd_freq_perc_cum rel_value
26 love 211 0.00592863 0.069542 1604206885 0.00244438 0.111399 7.60288e+06
2 man 195 0.00547907 0.0111829 3967037854 0.0060447 0.0279976 2.03438e+07
24 my 191 0.00536668 0.0618994 1629540498 0.00248298 0.106478 8.53163e+06
15 i 168 0.00472043 0.0392526 2203439786 0.00335745 0.081014 1.31157e+07
0 2 158 0.00443945 0.00443945 9032673058 0.0137634 0.0137634 5.71688e+07
10 me 140 0.00393369 0.027873 2459330128 0.00374736 0.0634279 1.75666e+07
31 life 134 0.0037651 0.0764822 1534647732 0.00233839 0.123297 1.14526e+07
8 last 133 0.003737 0.0231807 2670229651 0.00406871 0.0557015 2.00769e+07
23 you 126 0.00354032 0.0565327 1713758853 0.00261131 0.103995 1.36013e+07
4 movie 117 0.00328744 0.0156224 3216050557 0.00490039 0.0378693 2.74876e+07
14 story 107 0.00300646 0.0345322 2231437526 0.00340011 0.0776565 2.08546e+07
33 night 104 0.00292217 0.0814555 1523917360 0.00232204 0.127946 1.46531e+07
19 american 93 0.00261309 0.0478505 1868854192 0.00284763 0.0932591 2.00952e+07
117 girl 90 0.0025288 0.151644 842771661 0.00128416 0.26663 9.36413e+06
16 day 87 0.00244451 0.0416971 2164198760 0.00329766 0.0843116 2.48758e+07

Agora vamos visualizar para comparar os dois e enxergar as tendências escondidas:

 import matplotlib.pyplot as plt
plt.figure(figsize=(20,8))
plt.subplot(1, 2, 1)

word_freq_df_abs = word_freq_df.sort_values('abs_freq', ascending=False).reset_index()

plt.barh(range(20),
         list(reversed(word_freq_df_abs['abs_freq'][:20])), color='#288FB7')
for i, word in enumerate(word_freq_df_abs['word'][:20]):
    plt.text(word_freq_df_abs['abs_freq'][i], 20-i-1, 
             s=str(i+1) + '. ' + word + ': '  + str(word_freq_df_abs['abs_freq'][i]),
             ha='right', va='center', fontsize=14, color='white', fontweight='bold')
plt.text(0.4, -1.1, s='Number of times the word was used in a movie title; out of 15500 movies.', fontsize=14)
plt.text(0.4, -1.8, s='Data: boxofficemojo.com Apr. 2018.   Feedback: @eliasdabbas', fontsize=14)


plt.vlines(range(0, 210, 10), -1, 20, colors='gray', alpha=0.1)
plt.hlines(range(0, 20, 2), 0, 210, colors='gray', alpha=0.1)
plt.yticks([])
plt.xticks([])
plt.title('Words Most Used in Movie Titles', fontsize=22, fontweight='bold')

# =============
plt.subplot(1, 2, 2)
# plt.axis('off')
plt.barh(range(20),
         list(reversed(word_freq_df['wtd_freq'][:20])), color='#288FB7')
for i, word in enumerate(word_freq_df['word'][:20]):
    plt.text(word_freq_df['wtd_freq'][i], 20-i-1, 
             s=str(i+1) + '. ' + word + ': ' + '$' + str(round(word_freq_df['wtd_freq'][i] / 1000_000_000, 2)) + 'b',
             ha='right', va='center', fontsize=14, color='white', fontweight='bold')
plt.text(0.4, -1.1, s='Alltime boxoffice revenue of all movies whos title contained the word. (Top word is "2") ', fontsize=14)
plt.text(0.4, -1.8, s='Data collection & methodology: http://bit.ly/word_freq', fontsize=14)

plt.vlines(range(0, 9_500_000_000, 500_000_000), -1, 20, colors='gray', alpha=0.1)
plt.hlines(range(0, 20, 2), 0, 10_000_000_000, colors='gray', alpha=0.1)
plt.xlim((-70_000_000, 9_500_000_000))
plt.yticks([])
plt.xticks([])
plt.title('Words Most Associated With Boxoffice Revenue', fontsize=22, fontweight='bold')
plt.tight_layout(pad=0.01)
plt.show()

words most box office data

Pelo menos na cabeça dos produtores e roteiristas, o amor vence tudo! É a palavra mais usada em todos os títulos de filmes. Já na frequência ponderada (receita de bilheteria), ela não fica tão alta.

Em outras palavras, se você olhar para todos os títulos de filmes, a palavra "love" é a que mais vai encontrar. Mas, estimando qual palavra apareceu mais aos olhos do público (usando a bilheteria como métrica), então "2", "star" e "man" seriam as mais vistas ou as mais associadas à receita.

Deixando claro: são cálculos bem simples. Quando dizemos que a frequência ponderada da palavra "love" é 1.604.106.767, isso simplesmente significa que a soma da bilheteria total de todos os filmes cujo título incluía a palavra "love" foi esse valor.

Também é curioso que "2" seja a líder. Obviamente, não é uma palavra, mas indica que as segundas partes de franquias somam um valor enorme. O mesmo vale para "3", que está na quinta posição. Note que "part" e "ii" também estão entre as dez primeiras, reforçando o ponto.

"American" e "movie" têm valor relativo alto.

Uma nota rápida sobre as stop words usadas nesta função

Normalmente você forneceria uma lista mais ampla de stop words do que a usada aqui, principalmente se estiver lidando com artigos ou posts de redes sociais. Por exemplo, o pacote nltk oferece listas de stop words em vários idiomas, que você pode baixar e usar.

As palavras aqui foram escolhidas depois de algumas verificações nos filmes do topo. Muitas costumam ser consideradas stop words, mas no caso de títulos de filmes, fez sentido manter algumas delas porque podem gerar insights. Por exemplo, as palavras "I", "me", "you" podem indicar certas dinâmicas sociais. Outro motivo é que títulos são frases muito curtas, e queremos extrair o máximo de sentido possível.

Você pode (e deve) testar com sua própria lista de palavras e obter resultados um pouco diferentes.

Voltando à lista original de títulos, vemos que algumas das palavras do topo nem aparecem entre as dez primeiras — e é justamente esse tipo de insight que tentamos revelar com esta abordagem.

boxoffice_df.head(10)
  lifetime_gross rank studio title year
0 936662225 1 BV Star Wars: The Force Awakens 2015
1 760507625 2 Fox Avatar 2009
2 681084109 3 BV Black Panther 2018
3 659363944 4 Par. Titanic 1997
4 652270625 5 Uni. Jurassic World 2015
5 623357910 6 BV Marvel's The Avengers 2012
6 620181382 7 BV Star Wars: The Last Jedi 2017
7 534858444 8 WB The Dark Knight 2008
8 532177324 9 BV Rogue One: A Star Wars Story 2016
9 504014165 10 BV Beauty and the Beast (2017) 2017

Em seguida, faz sentido explorar melhor as palavras mais interessantes. Vamos filtrar os filmes que contêm "2" e ver:

(boxoffice_df[boxoffice_df['title']                  
              .str
              .contains('2 | 2', case=False)] # spaces used to exclude words like '2010'
              .head(10))
  lifetime_gross rank studio title year
15 441226247 16 DW Shrek 2 2004
30 389813101 31 BV Guardians of the Galaxy Vol. 2 2017
31 381011219 32 WB Harry Potter and the Deathly Hallows Part 2 2011
35 373585825 36 Sony Spider-Man 2 2004
38 368061265 39 Uni. Despicable Me 2 2013
64 312433331 65 Par. Iron Man 2 2010
79 292324737 80 LG/S The Twilight Saga: Breaking Dawn Part 2 2012
87 281723902 88 LGF The Hunger Games: Mockingjay - Part 2 2015
117 245852179 118 BV Toy Story 2 1999
146 226164286 147 NL Rush Hour 2 2001

Vamos dar uma olhada também nos principais filmes com "star":

boxoffice_df[boxoffice_df['title'].str.contains('star | star', case=False)].head(10)
  lifetime_gross rank studio title year
0 936662225 1 BV Star Wars: The Force Awakens 2015
6 620181382 7 BV Star Wars: The Last Jedi 2017
8 532177324 9 BV Rogue One: A Star Wars Story 2016
11 474544677 12 Fox Star Wars: Episode I - The Phantom Menace 1999
12 460998007 13 Fox Star Wars 1977
33 380270577 34 Fox Star Wars: Episode III - Revenge of the Sith 2005
65 310676740 66 Fox Star Wars: Episode II - Attack of the Clones 2002
105 257730019 106 Par. Star Trek 2009
140 228778661 141 Par. Star Trek Into Darkness 2013
301 158848340 302 Par. Star Trek Beyond 2016

E, por fim, os principais filmes com "man":

boxoffice_df[boxoffice_df['title'].str.contains('man | man', case=False)].head(10)
  lifetime_gross rank studio title year
18 423315812 19 BV Pirates of the Caribbean: Dead Man's Chest 2006
22 409013994 23 BV Iron Man 3 2013
35 373585825 36 Sony Spider-Man 2 2004
48 336530303 49 Sony Spider-Man 3 2007
53 330360194 54 WB Batman v Superman: Dawn of Justice 2016
59 318412101 60 Par. Iron Man 2008
64 312433331 65 Par. Iron Man 2 2010
82 291045518 83 WB Man of Steel 2013
176 206852432 177 WB Batman Begins 2005
182 202853933 183 Sony The Amazing Spider-Man 2 2014

Próximos passos e melhorias

Como primeiro passo, você pode tentar obter mais palavras: títulos de filmes são extremamente curtos e muitas vezes não transmitem o significado literal. Por exemplo, "padrinho" deveria ser a pessoa que testemunha o batismo de uma criança e promete cuidar dela (ou talvez um mafioso que mata por prazer?!).

Um exercício adicional seria obter descrições mais detalhadas, além do título. Por exemplo:

"A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers."

diz muito mais sobre o filme do que "The Matrix".

Alternativamente, você pode seguir um dos caminhos abaixo para enriquecer sua análise:

  • Análise estatística mais robusta: tratar valores extremos/outliers, usar outras métricas.
  • Mineração de texto: agrupar palavras e tópicos semelhantes ("happy", "happiness", "happily", etc.).
  • Análise granular: rodar a mesma função por ano/década ou por determinados estúdios.

Talvez você queira explorar os dados por conta própria, assim como outros conjuntos:

Pronto: você explorou as contagens de palavras em títulos de filmes, viu a diferença entre frequências absoluta e ponderada e como deixar uma de fora pode esconder parte importante da história. Também viu as limitações dessa abordagem e algumas sugestões de como melhorar sua análise.

Você criou uma função prática que pode rodar facilmente para analisar qualquer conjunto de texto similar com números e entendeu como isso pode ampliar sua compreensão desse tipo de dado.

Experimente analisar o desempenho dos seus tweets, as URLs do seu site, seus posts no Facebook ou qualquer outro conjunto de dados parecido que você encontrar.

Talvez seja mais fácil simplesmente clonar o repositório com o código e testar você mesmo.

A função word_frequency faz parte do pacote advertools, que você pode baixar e usar no seu trabalho/pesquisa.

Dá uma olhada e me conta! @eliasdabbas

Confira o tutorial de dicionários em Python da DataCamp para aprender a criar frequência de palavras, e o tutorial de web scraping e PLN em Python para aprender a plotar distribuições de frequência de palavras.

Tópicos
Python
Aprendizado de máquina

Aprenda mais sobre Python

Curso

Introdução ao Python

4 h
7M
Domine os fundamentos da análise de dados com Python em quatro horas e explore pacotes populares.
Ver detalhesRight Arrow
Iniciar Curso
Ver maisRight Arrow
Relacionado

Tutorial

Stemming e lematização em Python

Este tutorial aborda o stemming e a lematização de um ponto de vista prático usando o pacote Python Natural Language ToolKit (NLTK).
Kurtis Pykes 's photo

Kurtis Pykes

12 min

Tutorial

Tutorial de mineração de regras de associação em Python

Descobrindo padrões ocultos em Python com mineração de regras de associação
Moez Ali's photo

Moez Ali

14 min

Tutorial

Entendendo a classificação de textos em Python

Descubra o que é a classificação de texto, como ela funciona e os casos de uso bem-sucedidos. Explore exemplos de ponta a ponta de como criar um pipeline de pré-processamento de texto seguido de um modelo de classificação de texto em Python.
Moez Ali's photo

Moez Ali

12 min

Tutorial

Funções em Python: como chamar e escrever funções

Descubra como escrever funções em Python reutilizáveis e eficientes. Domine parâmetros, instruções de retorno e temas avançados como funções lambda. Organize melhor seu código com main() e outras boas práticas.
Karlijn Willems's photo

Karlijn Willems

14 min

Tutorial

Tutorial do Python pandas: O guia definitivo para iniciantes

Você está pronto para começar sua jornada com os pandas? Aqui está um guia passo a passo sobre como você pode começar.
Vidhi Chugh's photo

Vidhi Chugh

15 min

Tutorial

Tutorial de manipulação de dados categóricos de aprendizado de máquina com Python

Aprenda os truques comuns para lidar com dados categóricos e pré-processá-los para criar modelos de aprendizado de máquina!
Moez Ali's photo

Moez Ali

14 min

Ver MaisVer Mais