Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

komplizierte Wordcloud

Die "einfache" Wordcloud, die wir letzten Kapitel erstellt haben, geht auch noch viel besser und genaurer, denn zB. die "einfache" Wordcloud macht keinen Unterschied, wie Wörter geschrieben worden sind. Groß- und Kleinschreibung ist zwar kein Problem. Die Wordcloud kann automatisch erkennen, dass "japan" und "Japan" das selbe Wort ist, aber Wörter, die von der Bedeutung ähnlich sind, aber komplett anders geschrieben sind, wie zB. "good" und "better", werden als zwei komplett verschiedene Wörter betrachtet, was nicht unbedingt schlimm ist, aber wir können mit dem Package "nltk" alle Wörter zu deren Stammversion zurücksetzen, damit "good" und "better" ein und das selbe Wort ist.

Lass uns dafür ein neues Projekt "complicated_wordcloud" erstellen. Als nächstes installieren wir alle Packages, die wir dafür brauchen werden.

poetry add wordcloud matplotlib nltk

Wie in der "einfachen" Wordcloud müssen wir erstmal das Buch lesen.

from wordcloud import WordCloud
import matplotlib.pyplot as plt
import nltk

def main():
    f = open("books/lafcadio.txt", "r")
    book = f.read()
    f.close()

Jetzt können wir mit nltk anfangen den Inhalt des Buches, welches wir in die "book" Variable abgespeichert haben, zu reinigen, sprich unnötige Wörter entfernen und dann alle Wörter zu "stemmen" (in die Stammform bringen).

from wordcloud import WordCloud
import matplotlib.pyplot as plt
import nltk

def main():
    f = open("books/lafcadio.txt", "r")
    book = f.read()
    f.close()

    nltk.download("all")
    
    tokens = nltk.tokenize.word_tokenize(book)

Hier downloadedn wir alles was nltk braucht, um zu funktionieren. Alles zu downloaden ist ein bisschen overkill, aber so ist es einfacher als dir erklären, was genau du downloaden musst.

Und dann "tokenisieren" wir "book", also wir machen aus den Fließtext von "book" eine Liste von Tokens. Ein Token bedeutet hier ein Wort. Man nennt dies "Token", da ein Token nicht immer nur ein Wort sein muss. nlkt erlaubt es uns auch mit nltk.tokenize.sent_tokenize aus jeden Satz einen Token zu machen, aber das macht für eine Wordcloud gar kein Sinn, deswegen benutzen wir die word_tokenize Funktion.

['JAPAN', 'AN', 'ATTEMPT', 'AT', 'INTERPRETATION', 'BY', 'LAFCADIO', 'HEARN', '1904', 'Contents', 'CHAPTER', 'PAGE', 'I', '.', 'DIFFICULTIES', '.........................', '1', 'II', '.', 'STRANGENESS', 'AND', 'CHARM', '................', '5', 'III', '.', 'THE', 'ANCIENT', 'CULT', '....................', '21', 'IV', '.', 'THE', 'RELIGION', 'OF', 'THE', 'HOME', '............', '33', ...]

Als nächstes entfernen wir alle "stopwords". Stopwords sind Wörter, die keinen signifikanten Inhalt bieten. Zum Beispiel Wörter wie "und", "als", "dennoch", usw. Diese Wörter sind zwar grammatikalisch wichtig, aber nicht für eine Wordcloud...

Mit nltk bekommen wir zB. so alle stopwords aus der englischen Sprache:

nltk.corpus.stopwords.words("english")
['a', 'about', 'above', 'after', 'again', 'against', 'ain', 'all', 'am', 'an', 'and', 'any', 'are', 'aren', "aren't", 'as', 'at', 'be', 'because', 'been', 'before', 'being', 'below', 'between', 'both', 'but', 'by', 'can', 'couldn', "couldn't", 'd', 'did', 'didn', "didn't", 'do', 'does', 'doesn', "doesn't", 'doing', 'don', "don't", 'down', 'during', 'each', 'few', 'for', 'from', 'further', 'had', 'hadn', "hadn't", 'has', 'hasn', "hasn't", 'have', 'haven', "haven't", 'having', 'he', "he'd", "he'll", 'her', 'here', 'hers', 'herself', "he's", 'him', 'himself', 'his', 'how', 'i', "i'd", 'if', "i'll", "i'm", 'in', 'into', 'is', 'isn', "isn't", 'it', "it'd", "it'll", "it's", 'its', 'itself', "i've", 'just', 'll', 'm', 'ma', 'me', 'mightn', "mightn't", 'more', 'most', 'mustn', "mustn't", 'my', 'myself', 'needn', "needn't", 'no', 'nor', 'not', 'now', 'o', 'of', 'off', 'on', 'once', 'only', 'or', 'other', 'our', 'ours', 'ourselves', 'out', 'over', 'own', 're', 's', 'same', 'shan', "shan't", 'she', "she'd", "she'll", "she's", 'should', 'shouldn', "shouldn't", "should've", 'so', 'some', 'such', 't', 'than', 'that', "that'll", 'the', 'their', 'theirs', 'them', 'themselves', 'then', 'there', 'these', 'they', "they'd", "they'll", "they're", "they've", 'this', 'those', 'through', 'to', 'too', 'under', 'until', 'up', 've', 'very', 'was', 'wasn', "wasn't", 'we', "we'd", "we'll", "we're", 'were', 'weren', "weren't", "we've", 'what', 'when', 'where', 'which', 'while', 'who', 'whom', 'why', 'will', 'with', 'won', "won't", 'wouldn', "wouldn't", 'y', 'you', "you'd", "you'll", 'your', "you're", 'yours', 'yourself', 'yourselves', "you've"]

Oder hier einmal alle stopwords von der deutschen Sprache:

nltk.corpus.stopwords.words("german")
['aber', 'alle', 'allem', 'allen', 'aller', 'alles', 'als', 'also', 'am', 'an', 'ander', 'andere', 'anderem', 'anderen', 'anderer', 'anderes', 'anderm', 'andern', 'anderr', 'anders', 'auch', 'auf', 'aus', 'bei', 'bin', 'bis', 'bist', 'da', 'damit', 'dann', 'der', 'den', 'des', 'dem', 'die', 'das', 'dass', 'daß', 'derselbe', 'derselben', 'denselben', 'desselben', 'demselben', 'dieselbe', 'dieselben', 'dasselbe', 'dazu', 'dein', 'deine', 'deinem', 'deinen', 'deiner', 'deines', 'denn', 'derer', 'dessen', 'dich', 'dir', 'du', 'dies', 'diese', 'diesem', 'diesen', 'dieser', 'dieses', 'doch', 'dort', 'durch', 'ein', 'eine', 'einem', 'einen', 'einer', 'eines', 'einig', 'einige', 'einigem', 'einigen', 'einiger', 'einiges', 'einmal', 'er', 'ihn', 'ihm', 'es', 'etwas', 'euer', 'eure', 'eurem', 'euren', 'eurer', 'eures', 'für', 'gegen', 'gewesen', 'hab', 'habe', 'haben', 'hat', 'hatte', 'hatten', 'hier', 'hin', 'hinter', 'ich', 'mich', 'mir', 'ihr', 'ihre', 'ihrem', 'ihren', 'ihrer', 'ihres', 'euch', 'im', 'in', 'indem', 'ins', 'ist', 'jede', 'jedem', 'jeden', 'jeder', 'jedes', 'jene', 'jenem', 'jenen', 'jener', 'jenes', 'jetzt', 'kann', 'kein', 'keine', 'keinem', 'keinen', 'keiner', 'keines', 'können', 'könnte', 'machen', 'man', 'manche', 'manchem', 'manchen', 'mancher', 'manches', 'mein', 'meine', 'meinem', 'meinen', 'meiner', 'meines', 'mit', 'muss', 'musste', 'nach', 'nicht', 'nichts', 'noch', 'nun', 'nur', 'ob', 'oder', 'ohne', 'sehr', 'sein', 'seine', 'seinem', 'seinen', 'seiner', 'seines', 'selbst', 'sich', 'sie', 'ihnen', 'sind', 'so', 'solche', 'solchem', 'solchen', 'solcher', 'solches', 'soll', 'sollte', 'sondern', 'sonst', 'über', 'um', 'und', 'uns', 'unsere', 'unserem', 'unseren', 'unser', 'unseres', 'unter', 'viel', 'vom', 'von', 'vor', 'während', 'war', 'waren', 'warst', 'was', 'weg', 'weil', 'weiter', 'welche', 'welchem', 'welchen', 'welcher', 'welches', 'wenn', 'werde', 'werden', 'wie', 'wieder', 'will', 'wir', 'wird', 'wirst', 'wo', 'wollen', 'wollte', 'würde', 'würden', 'zu', 'zum', 'zur', 'zwar', 'zwischen']

Um jetzt die stopwords aus unseren tokens herauszufiltern, müssen wir erstmal alle tokens kleinbuchstabig machen.

tokens = [token.casefold() for token in tokens]

Anstelle .casefold() hätten wir auch .lower() verwenden können, aber .casefold() funktioniert mit allen Sprachen und deren Sonderzeichen, ... hust Deutsch hust.

['japan', 'an', 'attempt', 'at', 'interpretation', 'by', 'lafcadio', 'hearn', '1904', 'contents', 'chapter', 'page', 'i', '.', 'difficulties', '.........................', '1', 'ii', '.', 'strangeness', 'and', 'charm', '................', '5', 'iii', '.', 'the', 'ancient', 'cult', '....................', '21', 'iv', '.', 'the', 'religion', 'of', 'the', 'home', '............', '33', ...]

Jetzt können wir alle stopwords aus tokens rausfiltern.

stopwords = nltk.corpus.stopwords.words("english")
tokens = [token for token in tokens if not token in stopwords]

Ok jetzt fehlt nur noch das "stemmen". Der "PorterStemmer" ist bei englischen Texten der beliebteste, also lass uns den verwenden. nltk bietet den uns auch gleich schon an!

stemmer = nltk.stem.PorterStemmer()
tokens = [stemmer.stem(token) for token in tokens]
['japan', 'attempt', 'at', 'interpret', 'by', 'lafcadio', 'hearn', '1904', 'content', 'chapter', 'page', 'i', '.', 'difficulti', '.........................', '1', 'ii', '.', 'strang', 'and', 'charm', '................', '5', 'iii', '.', 'the', 'ancient', 'cult', '....................', '21', 'iv', '.', 'the', 'religion', 'of', 'the', 'home', '............', '33', 'v.', ...]

Et voila! Wir sind fertig! Jetzt können wir aus diesen Tokens eine Wordcloud erstellen. Aber halt stopp! Die WordCloud.generate() Funktion erlaubt nur Text in Form eines Strings und nicht in Form einer Liste von Tokens. Lass uns erstmal alle tokens wieder zu einem einzigen Fließtext kombinieren.

text = " ".join(tokens)

" ".join(tokens) kombiniert alle tokens zu einem String mit einem Leerzeichen zwischen jeden einzelnen Token. Und so können wir es jetzt, genau so wie in der "einfachen" Wordcloud gemacht haben, der generate Funktion weiter geben.

WordCloud(
    background_color = "white",
    height = 1000,
    width = 1000,
).generate(text)

Am Ende sieht unser kompletter Code so hier aus:

from wordcloud import WordCloud
import matplotlib.pyplot as plt
import nltk

def main():
    f = open("books/lafcadio.txt", "r")
    book = f.read()
    f.close()

    nltk.download("all")

    tokens = nltk.tokenize.word_tokenize(book)

    stopwords = nltk.corpus.stopwords.words("english")

    tokens = [token.casefold() for token in tokens]
    tokens = [token for token in tokens if token not in stopwords]

    stemmer = nltk.stem.PorterStemmer()
    tokens = [stemmer.stem(token) for token in tokens]

    text = " ".join(tokens)

    wordcloud = WordCloud(
        background_color = "white",
        height = 1000,
        width = 1000,
    ).generate(text)

    wordcloud.to_file("output/cloud_comlicated.png")

    plt.imshow(wordcloud)
    plt.show()

Und unsere generierte Wordcloud so: