Vai al contenuto principale

Frequenza assoluta e ponderata delle parole in un testo

In questo tutorial imparerai la frequenza assoluta e ponderata delle parole nel text mining e come calcolarla con defaultdict e DataFrame di pandas.
ยท 15 min leggi

Scopri con l'IA

Nel text mining, un gruppo importante di metriche riguarda la frequenza delle parole (o di qualsiasi token) in un certo corpus di documenti testuali. Tuttavia, puoi usare anche un insieme aggiuntivo di metriche nei casi in cui ogni documento abbia un valore numerico associato che descrive un certo attributo del documento.

Alcuni esempi:

  • Tweet e il rispettivo numero di interazioni.
  • URL con relative pageview e frequenze di rimbalzo.
  • Titoli di film e incassi lordi.
  • Keyword con impression, clic e conversioni.

In questo tutorial,

  • per prima cosa realizzerai una semplice funzione che calcola e confronta lโ€™occorrenza assoluta e ponderata delle parole in un corpus di documenti. Questo a volte puรฒ far emergere tendenze e aggregazioni nascoste che non sono necessariamente chiare osservando solo la top ten circa. Spesso possono anche differire dalla frequenza assoluta delle parole.
  • Poi vedrai un set di dati reale (titoli di film e incasso lordo), con lโ€™obiettivo di scoprire tendenze nascoste. Anticipo: in qualche modo salterร  fuori lโ€™amore!
  • Userai Python come linguaggio di programmazione e sfrutterai la struttura dati defaultdict del modulo collections per il grosso del lavoro, oltre ai DataFrame di pandas per gestire lโ€™output finale.

Frequenza assoluta e ponderata delle parole: introduzione

Supponiamo che tu abbia due tweet e che il loro contenuto e il numero di impression (visualizzazioni) siano i seguenti:

Testo del tweetVisualizzazioni
spain800
france200

รˆ semplice fare lโ€™analisi di base e scoprire che le parole sono divise 50:50 tra "france" e "spain". In molti casi questo รจ tutto ciรฒ che hai, e puoi solo misurare la frequenza assoluta delle parole e cercare di inferire certe relazioni. In questo caso, perรฒ, hai anche dei dati su ciascuno dei documenti.

La frequenza ponderata qui รจ chiaramente diversa, e la divisione รจ 80:20. In altre parole, sebbene "spain" e "france" compaiano una volta ciascuna nei tuoi tweet, dalla prospettiva dei lettori la prima รจ apparsa 800 volte, mentre la seconda 200 volte. Cโ€™รจ una grande differenza!

Frequenza semplice delle parole usando defaultdict

Ora considera questo esempio leggermente piรน articolato per un set simile di documenti:

DocumentoVisualizzazioni
france200
spain180
spain beaches170
france beaches160
spain best beaches160

Ora cicli sui documenti, li dividi in parole e conti le occorrenze di ciascuna parola:

 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
spain3
beaches3
france2
best1

Nel ciclo sopra, la prima riga itera su text_list uno alla volta. La seconda riga (allโ€™interno di ciascun documento) itera sulle parole di ogni elemento, divise per lo spazio (che avrebbe potuto essere anche un altro carattere ("-", ",", "_", ecc.)).

Quando provi ad assegnare un valore a word_freq[word] ci sono due possibili scenari:

  1. La chiave word esiste: in tal caso lโ€™assegnazione avviene (aggiungendo uno)
  2. La chiave word non รจ in word_freq: in questo caso defaultdict chiama la funzione di default a cui รจ stato assegnato quando รจ stato definito, che in questo caso รจ int.

Quando int viene chiamato restituisce zero. Ora la chiave esiste, il suo valore รจ zero, ed รจ pronta a ricevere un +1.

Anche se nella prima tabella la parola in cima era "france", dopo aver contato tutte le parole allโ€™interno di ciascun documento vediamo che "spain" e "beaches" sono a pari merito al primo posto. Questo รจ importante per far emergere tendenze nascoste, soprattutto quando lโ€™elenco di documenti con cui stai lavorando รจ dellโ€™ordine delle decine o centinaia di migliaia.

Frequenza ponderata delle parole

Ora che hai contato le occorrenze di ciascuna parola nel corpus di documenti, vuoi vedere la frequenza ponderata. Cioรจ, vuoi vedere quante volte le parole sono apparse ai tuoi lettori, rispetto a quante volte le hai usate.

Nella prima tabella, la frequenza assoluta delle parole era divisa equamente tra "spain" e "france", ma "spain" aveva chiaramente molto piรน peso, perchรฉ il suo valore era 800, contro i 200 di "france".

Ma qual รจ la frequenza ponderata delle parole per la seconda tabella, leggermente piรน complessa?

Scopriamolo!

Puoi riutilizzare parte del codice di sopra, con alcune aggiunte:

 # 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_freqwtd_freqrel_value
spain3510170
beaches3490163
france2360180
best1160160

Alcune osservazioni:

  • Sebbene "france" fosse la frase piรน alta in assoluto, "spain" e "beaches" sembrano piรน prominenti quando consideri la frequenza ponderata.
  • rel_value รจ una semplice divisione per ottenere il valore per occorrenza di ciascuna parola.
  • Guardando rel_value, vedi anche che, pur essendo "france" piuttosto bassa nella metrica wtd_freq, sembra avere potenziale, perchรฉ il valore per occorrenza รจ alto. Questo potrebbe suggerire, per esempio, di aumentare la copertura di contenuti su "france".

Potresti anche voler aggiungere altre metriche che mostrino le percentuali e le percentuali cumulative di ciascun tipo di frequenza, cosรฌ da avere una prospettiva migliore su quante parole costituiscono la maggior parte del totale, se ce ne sono:

 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_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
spain30.3333330.3333335100.3355260.335526170
beaches30.3333330.6666674900.3223680.657895163
france20.2222220.8888893600.2368420.894737180
best1160160

Altro si puรฒ analizzare, e con piรน dati in genere arrivano piรน sorprese.

Come potrebbe apparire tutto questo in un contesto reale con dati reali?

Esaminerai i titoli dei film, vedrai quali parole sono piรน usate nei titoli โ€” cioรจ la frequenza assoluta โ€” e quali parole sono associate al maggior incasso, ovvero la frequenza ponderata.

Boxoffice Mojo ha un elenco di oltre 15.000 film, insieme al relativo incasso lordo e posizioni in classifica. Inizia facendo scraping dei dati usando requests e BeautifulSoup โ€” Puoi giร  esplorare Boxoffice Mojo qui se ti va:

ย 
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)
ย 01234
01Star Wars: The Force AwakensBV$936,662,2252015
12AvatarFox$760,507,6252009^
23Black PantherBV$681,084,1092018
34TitanicPar.$659,363,9441997^
45Jurassic WorldUni.$652,270,6252015
56Marvel's The AvengersBV$623,357,9102012
67Star Wars: The Last JediBV$620,181,3822017
78The Dark KnightWB$534,858,4442008^
89Rogue One: A Star Wars StoryBV$532,177,3242016
910Beauty and the Beast (2017)BV$504,014,1652017
boxoffice_df.tail(15)
ย 01234
1548515486The Dark HoursN/A$4232005
15486154872:22Magn.$4222017
1548715488State ParkAtl$4211988
1548815489The Magician (2010)Reg.$4062010
1548915490SkinlessPPF$4002014
1549015491CinemanovelsMont.$3982014
1549115492Hannah: Buddhism's Untold JourneyKL$3962016
1549215493Apartment 143Magn.$3832012
1549315494The MarshAll.$3362007
1549415495The ChambermaidFM$3152015
1549515496News From Planet MarsKL$3102016
1549615497Trojan WarWB$3091997
1549715498Lou! Journal infimeDistrib.$2872015
1549815499InterventionAll.$2792007
1549915500PlaybackMagn.$2642012

Vedrai che alcuni valori numerici hanno caratteri speciali ($, , e ^), e alcuni valori sono in realtร  N/A. Quindi devi sistemarli:

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

Ora trasformi lโ€™elenco in un DataFrame di pandas assegnando alle colonne i nomi appropriati e convertendo ai tipi di dato desiderati.

 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_grossrankstudiotitleyear
09366622251BVStar Wars: The Force Awakens2015
17605076252FoxAvatar2009
26810841093BVBlack Panther2018
36593639444Par.Titanic1997
46522706255Uni.Jurassic World2015
56233579106BVMarvel's The Avengers2012
66201813827BVStar Wars: The Last Jedi2017
75348584448WBThe Dark Knight2008
85321773249BVRogue One: A Star Wars Story2016
950401416510BVBeauty and the Beast (2017)2017
1048629556111BVFinding Dory2016
1147454467712FoxStar Wars: Episode I - The Phantom Menace1999
1246099800713FoxStar Wars1977
1345900586814BVAvengers: Age of Ultron2015
1444813909915WBThe Dark Knight Rises2012

La parola "star" รจ tra le prime, poichรฉ compare in cinque dei primi quindici film, e sai anche che la saga di Star Wars ha ancora piรน film, diversi dei quali in alto in classifica.

Ora utilizziamo il codice sviluppato e vediamo come funziona su questo set di dati. Non cโ€™รจ nulla di nuovo nel codice seguente, semplicemente lo racchiudi tutto in una funzione:

 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_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
The30550.0687470.068747675183424980.0811670.08116722100930.0
the13100.0294790.098227329731008600.0396390.12080625170306.0
of13990.0314820.129709301805924670.0362820.15708721572975.0
and5450.0122640.141973121881138470.0146520.17173922363512.0
21580.0035560.14552990326730580.0108590.18259857168817.0

Non sorprende che le "stop word" siano in cima, cosa piuttosto comune per la maggior parte delle raccolte di documenti. Inoltre sono duplicate, dove alcune sono in maiuscolo e altre no. Quindi hai due cose chiare da gestire:

  1. Rimuovere tutte le stop word: puoi farlo aggiungendo un nuovo parametro alla funzione e fornendo la tua lista di stop word.
  2. Gestire tutte le parole in minuscolo per rimuovere i duplicati

Ecco un semplice aggiornamento della funzione (nuovo parametro rm_words, e anche le righe 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

ย wordabs_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
021580.004439450.0044394590326730580.01376340.01376345.71688e+07
1star450.00126440.0057038553746588190.008189530.02195291.19437e+08
2man1950.005479070.011182939670378540.00604470.02799762.03438e+07
3part410.001152010.012334932625797770.004971290.03296897.95751e+07
4movie1170.003287440.015622432160505570.004900390.03786932.74876e+07

Diamo unโ€™occhiata allo stesso DataFrame ordinato in base a abs_freq:

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

ย wordabs_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
26love2110.005928630.06954216042068850.002444380.1113997.60288e+06

Ora visualizziamo per confrontare entrambe e vedere le tendenze nascoste:

 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

Sembra che, almeno nella mente di produttori e sceneggiatori, lโ€™amore conquisti tutto! รˆ la parola piรน usata in tutti i titoli dei film. Non รจ perรฒ cosรฌ in alto quando si passa alla frequenza ponderata (incasso al botteghino).

In altre parole, se guardi tutti i titoli dei film, la parola "love" sarebbe quella che incontreresti piรน spesso. Ma stimando quale parola sia apparsa di piรน agli occhi degli spettatori (usando lโ€™incasso lordo come metrica), allora "2", "star" e "man" sarebbero le piรน viste, o comunque associate al maggior incasso.

Per essere chiari: questi sono calcoli molto semplici. Quando dici che la frequenza ponderata della parola "love" รจ 1.604.106.767, significa semplicemente che la somma degli incassi lordi a vita di tutti i film il cui titolo includeva la parola "love" รจ stata quella cifra.

รˆ anche interessante che "2" sia la parola in cima. Ovviamente non รจ una parola, ma indica che i secondi capitoli delle serie cinematografiche ammontano a una somma molto grande. Lo stesso vale per "3", che รจ in quinta posizione. Nota che anche "part" e "ii" sono nella top ten, a conferma dello stesso fatto.

"American" e "movie" hanno un alto valore relativo.

Una nota rapida sulle stop word usate in questa funzione

Di solito forniresti un elenco piรน completo di stop word rispetto a quello qui usato, soprattutto se stai lavorando con articoli o post sui social. Ad esempio il pacchetto nltk fornisce elenchi di stop word in diverse lingue, che puoi scaricare e utilizzare.

Le parole qui sono state scelte dopo alcune verifiche sui film principali. Molte di queste sono solitamente considerate stop word, ma nel caso dei titoli di film, aveva senso mantenerne alcune perchรฉ potrebbero dare qualche indizio. Per esempio, le parole "I", "me", "you" potrebbero suggerire certe dinamiche sociali. Un altro motivo รจ che i titoli di film sono frasi molto brevi, e stiamo cercando di ricavarne il maggior significato possibile.

Puoi sicuramente provare con il tuo set di parole e ottenere risultati leggermente diversi.

Guardando alla lista originale dei titoli dei film, vediamo che alcune delle parole principali non compaiono nemmeno nella top ten, ed รจ proprio questo il tipo di insight che cerchiamo di far emergere con questo approccio.

boxoffice_df.head(10)
ย lifetime_grossrankstudiotitleyear
09366622251BVStar Wars: The Force Awakens2015
17605076252FoxAvatar2009
26810841093BVBlack Panther2018
36593639444Par.Titanic1997
46522706255Uni.Jurassic World2015
56233579106BVMarvel's The Avengers2012
66201813827BVStar Wars: The Last Jedi2017
75348584448WBThe Dark Knight2008
85321773249BVRogue One: A Star Wars Story2016
950401416510BVBeauty and the Beast (2017)2017

Successivamente, ha senso esplorare meglio le parole principali piรน interessanti. Filtriamo i film che contengono "2" e vediamo:

(boxoffice_df[boxoffice_df['title']                  
              .str
              .contains('2 | 2', case=False)] # spaces used to exclude words like '2010'
              .head(10))
ย lifetime_grossrankstudiotitleyear
1544122624716DWShrek 22004
3038981310131BVGuardians of the Galaxy Vol. 22017
3138101121932WBHarry Potter and the Deathly Hallows Part 22011
3537358582536SonySpider-Man 22004
3836806126539Uni.Despicable Me 22013
6431243333165Par.Iron Man 22010
7929232473780LG/SThe Twilight Saga: Breaking Dawn Part 22012
8728172390288LGFThe Hunger Games: Mockingjay - Part 22015
117245852179118BVToy Story 21999
146226164286147NLRush Hour 22001

Diamo anche unโ€™occhiata ai principali film con "star":

boxoffice_df[boxoffice_df['title'].str.contains('star | star', case=False)].head(10)
ย lifetime_grossrankstudiotitleyear
09366622251BVStar Wars: The Force Awakens2015
66201813827BVStar Wars: The Last Jedi2017
85321773249BVRogue One: A Star Wars Story2016
1147454467712FoxStar Wars: Episode I - The Phantom Menace1999
1246099800713FoxStar Wars1977
3338027057734FoxStar Wars: Episode III - Revenge of the Sith2005
6531067674066FoxStar Wars: Episode II - Attack of the Clones2002
105257730019106Par.Star Trek2009
140228778661141Par.Star Trek Into Darkness2013
301158848340302Par.Star Trek Beyond2016

E, infine, i principali film con "man":

boxoffice_df[boxoffice_df['title'].str.contains('man | man', case=False)].head(10)
ย lifetime_grossrankstudiotitleyear
1842331581219BVPirates of the Caribbean: Dead Man's Chest2006
2240901399423BVIron Man 32013
3537358582536SonySpider-Man 22004
4833653030349SonySpider-Man 32007
5333036019454WBBatman v Superman: Dawn of Justice2016
5931841210160Par.Iron Man2008
6431243333165Par.Iron Man 22010
8229104551883WBMan of Steel2013
176206852432177WBBatman Begins2005
182202853933183SonyThe Amazing Spider-Man 22014

Prossimi passi e miglioramenti

Come primo passo, potresti cercare di ottenere piรน parole: i titoli dei film sono estremamente brevi e spesso non veicolano il significato letterale delle parole. Per esempio, un padrino dovrebbe essere una persona che assiste al battesimo di un bambino e promette di prendersene cura (o magari un mafioso che uccide per piacere?!).

Un ulteriore esercizio potrebbe essere quello di ottenere descrizioni piรน dettagliate, oltre al titolo del film. Per esempio:

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

ci dice molto di piรน del film rispetto a "The Matrix".

In alternativa, potresti anche prendere una delle seguenti strade per arricchire la tua analisi:

  • Analisi statistica migliore: gestione di valori estremi/outlier, uso di altre metriche.
  • Text mining: raggruppare parole e argomenti simili ("happy", "happiness", "happily", ecc.).
  • Analisi granulare: eseguire la stessa funzione per anni/decenni diversi o per determinati studi di produzione.

Potresti essere interessato a esplorare direttamente questi dati e altri ancora:

Ok, ora hai esplorato il conteggio delle parole nei titoli dei film e visto la differenza tra frequenze assolute e ponderate, e come trascurarne una possa far perdere una parte importante del quadro. Hai anche visto i limiti di questo approccio e alcune proposte per migliorare la tua analisi.

Hai creato una funzione dedicata che puoi eseguire facilmente per analizzare qualsiasi set di dati testuali simili con numeri, e sai come questo puรฒ migliorare la comprensione di questo tipo di dati.

Provala analizzando le prestazioni dei tuoi tweet, gli URL del tuo sito, i tuoi post su Facebook o qualsiasi altro set di dati simile che potresti incontrare.

Potrebbe essere piรน semplice clonare il repository con il codice e provare tu stesso.

La funzione word_frequency fa parte del pacchetto advertools, che puoi scaricare e provare nel tuo lavoro/ricerca.

Dai unโ€™occhiata e fammi sapere! @eliasdabbas

Dai unโ€™occhiata al Tutorial sui dizionari in Python di DataCamp per imparare a creare la frequenza delle parole, e al tutorial Web Scraping & NLP in Python per imparare a tracciare le distribuzioni di frequenza delle parole.

Argomenti

Correlato