Einführung in Stemming und Lemmatisierung deutscher Texte mit Python

Um beim Text Mining zusammengehörende Wörter zu gruppieren, bedient man sich im Natural Language Processing (NLP) zweier Methoden: Lemmatisierung (lemmatising) und Stemming. Das ist notwendig, um z.B. einen Text besser kategorisieren bzw. mit Stichworten versehen zu können. Eines der wichtigsten Anwendungsgebiete ist sicherlich die Indexierung von Dokumenten durch eine Suchmaschine. Ein ganz einfaches Beispiel: Enthält ein Dokument sehr oft das Wort Häuser und der Nutzer sucht nach dem Begriff Haus, wird das relevante Dokument wohl nicht in den Suchergebnissen auftauchen.

Um das zu umgehen, müssen flektierte und abgeleitete Wörter zu Ihrer Grundform zurückgeführt werden. Beim Stemming werden dazu einfache heuritische Methoden angewendet, bei dem das Suffix der Wörter entfernt wird. Aus dem Wort Katzen wird so dessen Grundform Katze. Bei der Plural-Form Häuser ist das etwas schwieriger. Mit dem Abschneiden des Suffixes kommt man hier nicht weit, weshalb man sich bei der Lemmatisierung an Listen bzw. Datenbanken orientiert, die die reflektierte Formen enthalten und so eine sichere Verknüpfung von Häuser zur Singular-Form Haus erlauben.

Soviel zur Theorie. In der Praxis gibt es Python und eine Vielzahl von Modulen, die einem eine Menge Arbeit abnehmen. Im Folgenden vergleiche ich ein halbes Dutzend Module, die die Lemmatisierung und das Stemming beherrschen und auch für Deutsche Texte anwendbar sind.

Hinweis: Zur Vorbereitung beim Text Mining gehören natürlich auch das Säubern des Textes, Entfernen von Stop-Wörtern und das Tokenizing, also Aufbrechen eines Satzes in seine einzelnen Bestandteile. Diesen Schritt überspringe ich hier.

Stemming mit Porter, Lancaster und Snowball

Für das Stemming habe ich mir drei Module angeschaut:

  • Porter Stemmer
  • Lancaster Stemmer
  • Snowball Stemmer

Der Porter Stemmer wurde bereits 1979 von Martin F. Porter entwickelt und gilt zumindest in der englischen Sprache als sehr effektiv. Der Lancaster Stammer geht auf den Ende der 1980er Jahre an der Lancaster University von Chris Paice und Gareth Husk entwickelten Paice-Husk Stemming Algorithmus zurück. Im Gegensatz zum festen Regelsatz von Porter wird beim Lancaster mit externen Regeln gearbeitet, womit der Algorithmus flexibler ist.

Der Snowball Stemmer ist eigentlich kein eigener Algorithmus, sondern eine Sprache, um einen eigenen Stemmer zu schreiben.

Installation und Anwendung

Alle drei Module sind Bestandteil des Natural Language Toolkit und können dementsprechend sehr unkompliziert mit pip install nltk installiert werden. Danach sieht ein Anwendungsbeispiel folgendermaßen aus:

 from nltk.stem import PorterStemmer
 from nltk.stem import LancasterStemmer
 from nltk.stem.snowball import SnowballStemmer
 
 porter = PorterStemmer()
 lancaster = LancasterStemmer()
 snowball = SnowballStemmer("german")
 
 word = 'Katzen'
 
 print ('Porter: ' + porter.stem(word))
 print ('Lancaster: ' + lancaster.stem(word))
 print ('Snowball: ' + snowball.stem(word))

Da Snowball mehrere Sprachen unterstützt, muss hier vorher festgelegt werden, mit welcher Sprache wir arbeiten. Der Rest ist eigentlich ziemlich straight forward. Das Ergebnis zeigt aber die Schwächen des Stemmings:

Porter: katzen 
Lancaster: katz 
Snowball: katz 

Keiner der Stemmer kommt auf Katze. Klar: Hier werden einfach nur ein paar Buchstaben abgeschnitten. Da Porter nicht für die deutsche Sprache ausgelegt ist, wird hier sogar die reflektierte Form zurückgegeben. Das Stemming kann also dabei helfen, reflektierte Wörter auf einen gemeinsamen Stamm zu reduzieren. Die Bedeutung geht dabei aber oft verloren.

Genau deshalb gibt es die Lemmatisierung

Lemmatisieren mit HannoverTagger, WordNet, Spacy und IWNLP

Für die Lemmatisierung habe ich vier Module herausgesucht. Vor allem für die englische Sprache ist die Auswahl aber weitaus größer, für deutsche Texte ist es hingegen schwierig, aktuelle und gepflegte Module zu finden.

  • WordNet
  • SpaCy
  • HannoverTagger
  • IWNLP

Das WordNet Modul gehört ebenfalls zum NLTK und ist einer der am weitesten verbreiteten Lemmatiser. Das Modul wurde 2001 entwickelt; WordNet selber ist eine riesige lexikalische Datenbank, die seit 1985 an der Princeton University entwickelt wird und mittlerweile über 200 Sprachen unterstützt.

SpaCy ist vergleichsweise jung (2015) aber mittlerweile auch sehr weit verbreitet. Im Gegensatz zum NLTK, dass eine Vielzahl von Lösungen und Algorithmen mitbringt, konzentriert sich SpaCy auf genau einen Algorithmus, um ein Problem zu lösen und ist damit ein wenig fokussierter als das NLTK. Während das NLTK eher im Forschungsbereich anzutreffen ist, wird SpaCy vornehmlich im produktiven Bereich verwendet.

Der HannoverTagger, kurz HanTa - nicht zu verwechseln mit dem gleichnamigen Virus, wurde 2019 an der Hochschule Hannover entwickelt. HanTa wurde mit dem Ziel entwickelt, auch für deutsche Texte eine vernünftige Lemmatisierungs-Lösung zu besitzen.

Daneben gibt es noch IWNLP von Matthias Liebeck. IWNLP ist der Name der entsprechenden SpaCy-Erweiterung für IWNLP-py, was wiederum die Python-Implementierung von IWNLP ist: Inverse Wiktionary for Natural Language Processing. IWNLP nutzt zur Lemmatisierung einfach den Deutschen Bereich des Wiktionaries.

Was ist mit GermaLemma und German Lemmatizer?

GermaLemma ist ein weiteres, recht junges Modul von Markus Konrad, das aber leider die POS der Wörter erfordert. POS steht für Part-Of-Speech, also die Wortart, wie z.B. Substantiv, Verb, Adjektiv und so weiter. Da alle anderen Lemmatizer ohne die POS arbeiten und ich die einfachste Lösung gesucht habe, bleibt dieses Modul außen vor.

Eine weitere Lösung wäre Docker-Image mit dem Namen German Lemmatizer gewesen, dass die Funktionen von INWLP und GermaLemma kombiniert. Das ganze lässt sich aber leider nur mit etwas Mehraufwand auch außerhalb von Docker nutzen, weshalb ich auch den German Lemmatizer hier nicht berücksichtigt habe.

WordNet kann Wörter übrigens ohne POS lemmatisieren, die Ergebnisse sind mit POS aber weitaus genauer. Die Klassifizierung des POS ist freilich keine Raketenwissenschaft und z.B. hier recht gut beschrieben.

Installation und Anwendung

Da wir oben schon das NLTK installiert haben, können wir direkt auf WordNet zugreifen. SpaCy installieren wir mit pip install spacy, dort wird dann auch gleich IWNLP mitgeliefert. Der HanTa lässt sich ebenfalls unkompliziert installieren: pip install HanTa.

Um IWNLP zum Laufen zu bringen, benötigen wir noch den letzten Dump von hier (letzter Stand 2018/10/01). Das Archiv enthälte eine JSON-Datei - das Lexikon mit etwa drölfizigtausend Lemmas. Um SpaCy für die deutsche Sprache anwendbar zumachen, müssen wir hier ein komplettes Modell herunterladen. Das übernimmt SpaCy für uns mit folgendem Befehl:

python -m spacy download de_core_news_md

(Es gibt drei verschieden große Modelle, ich habe mich für die goldene Mitte entschieden).

Die Implementierung ist dann etwas aufwendiger, da bei der Lemmatisierung Trainingsmodelle eingesetzt werden, und nicht nur “einfache” Algorithmen:

 from HanTa import HanoverTagger as ht
 from nltk.stem import WordNetLemmatizer
 from spacy_iwnlp import spaCyIWNLP
 import spacy
 
 hannover = ht.HanoverTagger('morphmodel_ger.pgz')
 wordnet = WordNetLemmatizer()
 
 spc =  spacy.load(r'/usr/local/lib/python3.9/site-packages/de_core_news_md/de_core_news_md-2.3.0', disable=['parser', 'ner'])
 
 iwnlp = spc
 iwnlp_pipe = spaCyIWNLP(lemmatizer_path='/Users/user1/Downloads/IWNLP.Lemmatizer_20181001.json')
 iwnlp.add_pipe(iwnlp_pipe)
 
 print ('HanTa:' + str(hannover.analyze(word)[0]))
 print ('Wordnet:' + wordnet.lemmatize(word, 'NN'))
 print ('SpaCy:' + str([token.lemma_ for token in spc(word)][0]))
 print ('IWNLP:' + str([token.lemma_ for token in iwnlp(word)][0]))

Dem HannoverTagger wird bei der Initialisierung das entsprechende Modell mitgegeben. WordNet benötigt keine weiteren Parameter. Der SpaCy-Lemmatiser (hier spc) wird mit dem deutschen News Paket über spacy.load() initialisiert. Alternativ funktioniert die Initialisierung auch über den Shortcut de:

 spc = spacy.load('de', disable=['parser', 'ner'])

Um den Vorgang etwas zu beschleunigen, deaktivieren wir die Funktionen parser und ner. Der Parser macht bei der Verarbeitung von Sätzen Sinn, ner steht für Name Entity Recognition, sprich die Erkennung von Eigennamen. Das ist bei der Lemmatisierung durchaus wichtig, möchte ich hier aber erstmal nicht berücksichtigen.

Da IWNLP ebenfalls über SpaCy aktiviert wird, klonen wir das Objekt einfach und fügen dann unsere eigene Pipeline hinzu add_pipe(). Diese muss auf das Lexikon als JSON-Datei verweisen, den wir vorher heruntergeladen haben. Das wars auch schon, danach sehen wir, wie sich die Module untereinander und im Vergleich zum Stemming schlagen:

HanTa:Katze 
Wordnet:Katzen
SpaCy:Katze
IWNLP:Katze 

Das Ergebnis überrascht nur ein kleines bisschen: Obwohl die eigentliche WordNet-Datenbank 200 Sprachen unterstützt, schafft es das Modul nicht, das richtige Lemma zuzuordnen. Ich finde leider auch keine Informationen dazu, wie WordNet auf Deutsch getrimmt werden kann. Die Ergebnisse von HanTa, SpaCy und IWNLP passen allerdings. IWNLP (und demnach auch SpaCy) liefern bei Bedarf übrigens mehr als nur ein Lemma zurück:

 print (str([token._.iwnlp_lemmas for token in iwnlp(word)][0]))
 print (str([token.pos_ for token in iwnlp(word)][0]))

Mit pos_ und _.iwnlp_lemmas bekommt man einerseits den Part-Of-Speech und in IWNLP sogar eine Liste aller denkbaren Lemmas - sofern zutreffend.

Wer den Vergleich etwas hübscher aufbereitet für mehrer Wörter nutzen will, kann dazu folgendes Jupyter-Notebook nutzen. Ich hab das ganze mal für eine beliebige Schlagzeile von Spiegel Online durchgespielt und folgendes Ergebnis erhalten. Der Original-Satz lautet:

Der weltweite CO₂-Ausstoß steigt weiter – trotz Corona-Knick, heißt es im neuen Bericht des Uno-Umweltprogramms. Ohne grüne Konjunkturpakete sei das Pariser Zwei-Grad-Limit nicht mehr zu retten.

Und das ist das Ergebnis nach dem Steming und Lemmatisieren:

7 Methoden zum Stemming und Lemmatisieren im Vergleich

Das Stemming liefert, naturgemäß, ein relativ grobes Ergebnis ab. Um die Wörter in einem Text schnell zu kategorisieren reicht das sicherlich aus. Bei der Lemmatisierung fällt auf, das SpaCy trotz deutscher Sprachpakete nicht ganz zufriedenstellend arbeitet. So wird aus “das” z.B. “der”. Dafür wird “trotz” korrekt “trotzen” zugeordenet - was dem HanTa nicht gelingt. HanTa wiederum kennt als einziger den Singular von Konjunkturpakete.

Fazit

Die Verarbeitung englischer Texte ist, aufgrund der großen Verbreitung der Sprache, gar kein Problem. Bei deutschen Texten wird es schon etwas schwieriger, allerdings liefern HanTa, IWNLP und auch SpaCy recht gute Ergebnisse ab. Mein subjektiver Favorit ist HanTa. Aber die Stichprobe ist viel zu gering, um hier einen klaren Favoriten identifizieren zu können.

Der Vergleich dient eher nicht als repräsentivate Untersuchung aller denkbaren Varianten, soll aber einen kleinen Einblick in NLP und die automatisierte Text-Verarbeitung im Text-Mining geben und ein paar Code-Beispiele liefern, um den Einsteig in Python zu erleichtern. Ich hoffe das ist gelungen!