Zum Hauptinhalt springen

Absolute und gewichtete Worthäufigkeit in Texten

In diesem Tutorial lernst du, was absolute und gewichtete Worthäufigkeit im Text Mining ist und wie du sie mit defaultdict und pandas DataFrames berechnest.
· 15 Min. lesen

Entdecke KI

Ein zentrales Set an Kennzahlen im Text Mining bezieht sich auf die Häufigkeit von Wörtern (oder beliebigen Tokens) in einem bestimmten Korpus von Textdokumenten. In manchen Fällen hat allerdings jedes Dokument zusätzlich einen numerischen Wert, der ein Attribut des Dokuments beschreibt – dann lässt sich eine weitere Klasse von Metriken nutzen.

Einige Beispiele:

  • Tweets und ihre jeweilige Anzahl an Interaktionen.
  • URLs sowie deren Seitenaufrufe und Absprünge.
  • Filmtitel und ihr Einspielergebnis.
  • Keywords sowie Impressionen, Klicks und Conversions.

In diesem Tutorial

  • gehst du zunächst den Prozess durch, eine einfache Funktion zu erstellen, die die absolute und die gewichtete Häufigkeit von Wörtern in einem Dokumentenkorpus berechnet und vergleicht. So lassen sich verborgene Trends und Summen aufdecken, die beim Blick auf die Top Ten nicht auffallen – und die sich oft deutlich von der absoluten Worthäufigkeit unterscheiden.
  • Danach siehst du dir einen Datensatz aus der Praxis an (Filmtitel und Einspielergebnis), um versteckte Muster zu entdecken. Kleiner Teaser: Liebe spielt eine Rolle!
  • Du verwendest Python als Programmiersprache, setzt für die Hauptarbeit auf die Datenstruktur defaultdict aus dem collections-Modul und nutzt pandas-DataFrames für die Aufbereitung der Ergebnisse.

Absolute und gewichtete Worthäufigkeit: Einführung

Nehmen wir an, du hast zwei Tweets; ihr Inhalt und ihre Impressionen (Views) sind wie folgt:

Tweet-TextViews
spain800
france200

Die Basisauswertung ist einfach: Deine Wörter verteilen sich 50:50 auf „france“ und „spain“. In vielen Fällen sind das alle Daten, die du hast – du misst die absolute Worthäufigkeit und leitest Beziehungen daraus ab. Hier liegen dir allerdings zusätzliche Informationen zu den Dokumenten vor.

Die gewichtete Häufigkeit unterscheidet sich klar: Die Verteilung ist 80:20. Obwohl „spain“ und „france“ jeweils einmal in deinen Tweets vorkommen, erschien aus Sicht der Leser Ersteres 800-mal und Letzteres 200-mal. Das ist ein deutlicher Unterschied!

Einfache Worthäufigkeit mit defaultdict

Betrachte nun ein etwas umfangreicheres Beispiel mit einem ähnlichen Dokumentenset:

DokumentViews
france200
spain180
spain beaches170
france beaches160
spain best beaches160

Du iterierst jetzt über die Dokumente, zerlegst sie in Wörter und zählst die Vorkommen jedes einzelnen Wortes:

 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

In der obigen Schleife gehst du in der ersten Zeile die text_list nacheinander durch. Die zweite Zeile (innerhalb jedes Dokuments) iteriert über die Wörter jedes Elements, getrennt am Leerzeichen (das auch ein anderes Trennzeichen sein könnte, z. B. '-', ',', '_', etc.).

Beim Zuweisen eines Werts zu word_freq[word] gibt es zwei Fälle:

  1. Der Schlüssel word existiert: Dann wird der Wert um eins erhöht.
  2. Der Schlüssel word existiert nicht: defaultdict ruft die beim Anlegen hinterlegte Default-Funktion auf – hier int.

int gibt in diesem Fall 0 zurück. Jetzt existiert der Schlüssel, der Wert ist 0 und kann um 1 erhöht werden.

Obwohl im ersten Beispiel 'france' oben stand, siehst du nach dem Zählen über alle Wörter pro Dokument, dass 'spain' und 'beaches' gleichauf an erster Stelle liegen. Solche Analysen sind wichtig, um verborgene Trends zu erkennen – insbesondere, wenn deine Dokumentliste in die Zehn- oder Hunderttausende geht.

Gewichtete Worthäufigkeit

Nachdem du die Vorkommen jedes Wortes im Korpus gezählt hast, willst du die gewichtete Häufigkeit betrachten. Das heißt: Wie oft sind die Wörter aus Sicht deiner Leser erschienen – verglichen mit der Anzahl deiner Verwendungen?

Im ersten Beispiel war die absolute Häufigkeit 50:50 zwischen 'spain' und 'france', aber 'spain' hatte deutlich mehr Gewicht, weil sein Wert 800 betrug, gegenüber 200 für 'france'.

Wie sieht nun die gewichtete Worthäufigkeit für die zweite, etwas komplexere Tabelle aus?

Finden wir es heraus!

Du kannst Teile des obigen Codes wiederverwenden – mit ein paar Ergänzungen:

 # 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

Einige Beobachtungen:

  • Obwohl 'france' insgesamt die häufigste Phrase war, sind 'spain' und 'beaches' bei Betrachtung der gewichteten Häufigkeit prominenter.
  • rel_value ist schlicht der Wert pro Vorkommen, also wtd_freq geteilt durch abs_freq.
  • Beim Blick auf rel_value siehst du auch: Obwohl 'france' bei wtd_freq relativ weit unten liegt, steckt Potenzial drin – der Wert pro Vorkommen ist hoch. Das könnte ein Hinweis sein, deine Inhalte zu 'france' auszubauen.

Praktisch ist auch, Prozentwerte und kumulierte Prozente für beide Häufigkeiten zu ergänzen. So bekommst du ein Gefühl, wie viele Wörter den Großteil der Summe ausmachen:

 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
best10.11111111600.1052631160

Mit mehr Daten lassen sich weitere Muster erkennen – und oft gibt es Überraschungen.

Wie sieht das nun in der Praxis mit echten Daten aus?

Du schaust dir Filmtitel an: Welche Wörter kommen in den Titeln am häufigsten vor (absolute Häufigkeit)? Und welche Wörter sind mit dem meisten Umsatz verknüpft (gewichtete Häufigkeit)?

Boxoffice Mojo führt eine Liste mit über 15.000 Filmen inklusive Einspielergebnis und Rang. Starte mit dem Scrapen der Daten via requests und BeautifulSoup – hier kannst du Boxoffice Mojo bereits erkunden:

 
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
67BV$620,181,3822017
78WB$534,858,4442008^
89BV$532,177,3242016
910BV$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

Du siehst: Manche numerischen Werte enthalten Sonderzeichen ($, , und ^), und einige Werte sind N/A. Das musst du bereinigen:

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

Jetzt wandelst du die Liste in ein pandas-DataFrame um, vergibst passende Spaltennamen und konvertierst in die gewünschten Datentypen.

 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

Das Wort „star“ ist eines der häufigsten: Es taucht in fünf der Top-15-Filme auf – und die Star-Wars-Reihe umfasst noch mehr Titel, mehrere davon ebenfalls unter den Top-Plätzen.

Lass uns jetzt den entwickelten Code auf diesen Datensatz anwenden. Neu ist unten nichts – wir packen alles in eine Funktion:

 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

Wenig überraschend führen sogenannte „Stopwörter“ die Liste an – und einige tauchen doppelt auf, groß- und kleingeschrieben. Also gibt es zwei To-dos:

  1. Stopwörter entfernen: Ergänze einen neuen Parameter in der Funktion und übergib eine eigene Stopwortliste.
  2. Wörter in Kleinschreibung verarbeiten, um Duplikate zu vermeiden.

Hier ist ein einfaches Update (neuer Parameter rm_words sowie Zeilen 6, 7 und 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.027997639670378540.00604470.02799762.03438e+07
3part410.001152010.032968932625797770.004971290.03296897.95751e+07
4movie1170.003287440.037869332160505570.004900390.03786932.74876e+07

Schauen wir auf dasselbe DataFrame, sortiert nach 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.11139916042068850.002444380.1113997.60288e+06
2man1950.005479070.027997639670378540.00604470.02799762.03438e+07

Visualisieren wir das Ganze, um beide Perspektiven zu vergleichen und verborgene Trends zu sehen:

 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

Zumindest in den Köpfen von Produzenten und Autorinnen scheint Liebe zu siegen: „love“ ist das meistgenutzte Wort in allen Filmtiteln. Beim Kriterium gewichtete Häufigkeit (Box-Office-Einnahmen) liegt es allerdings nicht ganz vorne.

Heißt: In allen Filmtiteln würdest du „love“ am häufigsten finden. Betrachtet man hingegen, welches Wort aus Sicht der Zuschauer am meisten „erschien“ (Einspielergebnis als Proxy), führen „2“, „star“ und „man“ – sie sind mit den höchsten Einnahmen verknüpft.

Zur Klarstellung: Das sind sehr einfache Berechnungen. Wenn die gewichtete Häufigkeit von „love“ 1.604.106.767 beträgt, heißt das lediglich, dass die Summe der gesamten Einspielergebnisse aller Filme, deren Titel das Wort „love“ enthält, genau diesen Betrag ausmacht.

Spannend ist auch, dass „2“ an der Spitze steht. Natürlich ist das kein Wort, sondern ein Hinweis darauf, dass zweite Teile von Filmreihen enorm viel Umsatz generieren. Ähnlich „3“ auf Position fünf. Auch „part“ und „ii“ finden sich in den Top Ten und stützen diese Beobachtung.

„American“ und „movie“ haben einen hohen relativen Wert.

Kurz zu den verwendeten Stopwörtern

Normalerweise würdest du eine umfassendere Stopwortliste verwenden – besonders bei Artikeln oder Social Posts. Das Paket nltk stellt z. B. Stopwortlisten für mehrere Sprachen bereit.

Die hier genutzten Wörter wurden nach einigen Stichproben unter den Top-Filmen gewählt. Viele davon sind zwar klassisch Stopwörter, bei Filmtiteln kann es aber sinnvoll sein, einige zu behalten – sie liefern Kontext. Beispielsweise können „I“, „me“, „you“ etwas über soziale Dynamiken andeuten. Außerdem sind Filmtitel sehr kurze Phrasen, aus denen wir möglichst viel Bedeutung ziehen wollen.

Probier es gern mit deiner eigenen Wortliste – du wirst leicht abweichende Ergebnisse sehen.

Im Vergleich zur ursprünglichen Titelliste fällt auf: Einige der Top-Wörter tauchen nicht einmal in den Top Ten der Titel auf. Genau diese Art von Insight wollen wir mit diesem Ansatz sichtbar machen.

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

Als Nächstes lohnt sich ein Blick auf spannende Top-Wörter. Filtern wir nach Filmen mit „2“:

(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

Werfen wir auch einen Blick auf die Top-„star“-Filme:

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

Und zuletzt die Top-„man“-Filme:

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

Nächste Schritte und Verbesserungen

Als ersten Schritt könntest du mehr Wörter einbeziehen: Filmtitel sind extrem kurz und transportieren oft nicht die wörtliche Bedeutung. Beispiel: Ein „Godfather“ ist eigentlich ein Taufpate, der die Fürsorge für ein Kind zusichert (oder ein Mafioso, der zum Vergnügen tötet?!).

Als weitere Übung könntest du zu den Titeln detailliertere Beschreibungen ergänzen. Zum Beispiel:

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

Dieser Satz verrät deutlich mehr über den Film als „The Matrix“.

Alternativ kannst du deine Analyse entlang folgender Pfade vertiefen:

  • Fundiertere Statistik: Ausreißer behandeln, weitere Kennzahlen nutzen.
  • Text Mining: Ähnliche Wörter und Themen bündeln („happy“, „happiness“, „happily“, etc.).
  • Granulare Analysen: Die Funktion nach Jahren/Jahrzehnten oder je Produktionsstudio laufen lassen.

Vielleicht möchtest du die Daten selbst weiter erkunden – sowie weitere Datensätze:

Du hast nun die Worthäufigkeit in Filmtiteln untersucht und den Unterschied zwischen absoluter und gewichteter Häufigkeit gesehen – und warum das Weglassen einer Sichtweise ein unvollständiges Bild ergibt. Außerdem kennst du die Grenzen des Ansatzes und Ansatzpunkte zur Verbesserung.

Du hast eine Funktion erstellt, die du schnell auf beliebige ähnliche Text-Datensätze mit Zahlen anwenden kannst – und weißt, wie sie dein Verständnis solcher Daten verbessert.

Probiere es aus: Analysiere deine Tweets, die URLs deiner Website, deine Facebook-Posts oder jeden anderen vergleichbaren Datensatz.

Am einfachsten ist es vielleicht, das Repository zu klonen und selbst loszulegen.

Die Funktion word_frequency ist Teil des Pakets advertools, das du herunterladen und in deiner Arbeit/Forschung einsetzen kannst.

Schau es dir an und gib Bescheid! @eliasdabbas

Sieh dir auch DataCamps Python Dictionaries Tutorial an, um Worthäufigkeiten zu erstellen, und das Tutorial Web Scraping & NLP in Python, um Worthäufigkeitsverteilungen zu visualisieren.

Themen

Ähnlich

Tutorial

Wie sortiert man ein Wörterbuch in Python nach Werten?

Tutorial

Python Datenstrukturen Tutorial