Natural Language Processing mit spaCy

Was ist Natural Language Processing?

Natural Language Processing (NLP) ist eine Kombination aus Linguistik, Computerwissenschaft und Künstlicher Intelligenz. Dabei geht es um die maschinelle Verarbeitung von natürlicher Sprache, um sie in eine Form zu bringen, die von einem Computer verarbeitet werden kann und zugleich auch deren Inhalt und Bedeutung beschreibt.

Für NLP gibt es eine Vielzahl verschiedener Anwendungsmöglichkeiten. Dies beinhaltet beispielsweise:

Somit spielt Natural Language Processing eine wichtige Rolle für generelle linguistische Textanalysen, Sprachassistenten, Chatbots, Übersetzer oder Suchmaschinen.

Was ist spaCy?

spaCy ist eine freie open-source Python Bibliothek von Explosion AI, die einen einfachen Einstieg in die Disziplin des Natural Language Processing ermöglicht und zugleich auch fortgeschrittene Methoden zur Analyse von Texten bietet. Dafür stehen umfangreiche Features, wie Tokenization, POS-Tagging, Lemmatization oder NER, zur Verfügung.

spaCy stellt bereits statistische Modelle für verschiedene Sprachen zur Verfügung (darunter Englisch, Deutsch, Französisch, Chinesisch, Japanisch, etc.). Diese sind notwendig um einen Text mit linguistischen Annotationen auszustatten, z.B. ob ein Wort ein Substantiv oder ein Verb ist.

spaCy einrichten

spaCy ist kompatibel mit 64-bit CPython 2.7 / 3.5+ und ist für Unix/Linux, macOS/OS X und Windows verfügbar. Es steht über pip oder conda zur Verfügung. Im Folgenden wird die Installation auf einem Windows Rechner unter der Verwendung von pip betrachtet. Grundsätzlich empfiehlt es sich eine Virtual Environment zu verwenden. Weitere Informationen zum Anlegen einer Virtual Environment und zusätzlichen Tipps zur Verwendung von pip lassen sich hier finden: Installing packages using pip and virtual environments.

Die Installation von spaCy erfolgt mit folgendem Befehl:

$ pip install -U spacy

Wie zuvor schon erwähnt bietet spaCy verschieden statistische Modelle für die unterschiedlichen Sprachen. Das Standardmodell ist en_core_web_sm (Englisch). Da der Fokus in diesem Überblick auf deutschen Texten liegt, wird ein Modell für die deutsche Sprache (de_core_news_sm) benötigt. spaCy bietet für Deutsch auch noch zwei weitere Modelle an, die sich hauptsächlich in der Größe von dem bereits genannten unterscheiden. de_core_news_sm reicht für einen ersten Einblick jedoch aus. Das Modell wird mit dem folgenden Befehl in der console heruntergeladen:

$ python -m spacy download de_core_news_sm

Wenn spaCy erfolgreich installiert und das Sprachmodell heruntergeladen wurde, kann man auch schon starten.

Erste Schritte mit spaCy

Um nun einen ersten einfachen Text zu Analysieren muss zunächst das Sprachmodell geladen werden:

import spacy
nlp = spacy.load('de_core_news_sm')

nlp repräsentiert nun das deutsche Sprachmodell, womit aus einem Text ein spaCy Doc Objekt erstellt wird.

doc = nlp('Alex spielt mit seinen Freunden Fußball.')
print([token.text for token in doc])
['Alex', 'spielt', 'mit', 'seinen', 'Freunden', 'Fußball', '.']

Wie hierbei erkennbar ist, enthält ein solches Doc Objekt eine Reihe von Tokens, in die das Sprachmodell den Text aufgeteilt hat. Ein Token ist z.B. ein Wort oder ein Satzzeichen. Die Aufteilung eines Textes in diese einzelnen Bestandteile wird auch als Tokenization bezeichnet. Ein Token enthält neben dem eigentlichen Text noch weitere Informationen. Nachfolgend werden ein paar davon ausgegeben.

import pandas as pd
pd.DataFrame({"Token": [token.text for token in doc],
              "Lemma": [token.lemma_ for token in doc],
              "POS": [token.pos_ for token in doc],
              "Tag": [token.tag_ for token in doc],
              "Dep": [token.dep_ for token in doc]})
Token Lemma POS Tag Dep
0 Alex Alex PROPN NE sb
1 spielt spielen VERB VVFIN ROOT
2 mit mit ADP APPR mo
3 seinen seinen DET PPOSAT nk
4 Freunden Freund NOUN NN nk
5 Fußball Fußball NOUN NN nk
6 . . PUNCT $. punct

Jetzt lassen sich neben der Tokenization auch noch weitere Features erkennen, die spaCy mit sich bringt. Hier wurden nur ein paar der Eigenschaften eines Tokens ausgewählt, die jeweils durch ein Feature zustande kommen:

  • Lemmatisierung: Lemmatisierung steht für die Rückführung eines Wortes in seine Grundform. Hier wird z.B. aus “spielt” wieder “spielen”
  • POS-Tagging: Part-of-speech tagging bestimmt hier POS wie auch Tag. Die Kürzel in der Spalte POS beschreiben demnach die Wortart eines Tokens (“spielt” - Verb) und Tag welchen Satzteil es einnimmt
  • Dependency Parse: Hier werden syntaktische Beziehungen zwischen Tokens festgehalten, die visualisiert werden können (siehe folgende Grafik) oder durch die navigiert werden kann.
spacy.displacy.render(doc)
Alex PROPN spielt VERB mit ADP seinen DET Freunden NOUN Fußball. NOUN sb mo nk nk nk

Alle weiteren Eigenschaften, die ein Token beinhaltet, können hier eingesehen werden.

Um längere Texte handhabbar zu machen, können diese über das Doc Object in ihre einzelnen Sätze zerlegt werden. Um dies zu zeigen, wird wiederum ein Doc Object erstellt, diesmal jedoch für einen etwas längeren Text der mehrere Sätze umfasst.

text = '''Alex arbeitet seit einem Jahr bei trinnovative. Er interessiert sich für Themen wie z.B. KI und NLP. Heute schreibt er einen Artikel.'''
doc = nlp(text)
sents = doc.sents

for sent in sents:
    print(list(sent))
[Alex, arbeitet, seit, einem, Jahr, bei, trinnovative, .]
[Er, interessiert, sich, für, Themen, wie, z.B., KI, und, NLP, .]
[Heute, schreibt, er, einen, Artikel, .]

Wie in diesem Beispiel zu sehen ist, hat spaCy die drei Sätze korrekt extrahiert. Ein Satz (hier sent) besteht wieder jeweils aus einzelnen Tokens, auf die dann wiederum wie zuvor zugegriffen werden kann.

5 Häufigste Wörter (most frequent words)

Die häufigsten Wörter eines Textes sind bei dessen Verarbeitung meist eine wichtige Kenngröße, die einen ersten Endruck vom Inhalt liefert. Deshalb wird Anhand des Wikipediaeintrags über Computerlinguistk (Definition + Geschichte) demonstriert wie diese Worthäufigkeiten mit spaCy wiedergegeben werden. Zunächst werden jedoch ein paar, für NLP typische, Vorverarbeitungsschritte durchgeführt (Preprocessing). Diese sind:

  • Filtern von Stoppwörtern
  • Filtern von Satzzeichen
  • Lemmatisierung der Tokens
  • Text in lowercase umwandeln

Hier stellt sich die Fragen, was Stoppwörtern (stop words) eigentlich sind und warum sie herausgefiltert werden sollten. Stoppwörter sind für gewöhnlich die häufigsten Wörter einer Sprache, die gleichzeitig wenig bis keine Relevanz für das Erfassen des Textinhaltes haben. Diese werden in einer sogenannten Stoppwortliste geführt, welche wie eine Blacklist behandelt wird. Wörter die also in dieser Liste aufgeführt sind, werden einfach herausgefiltert. Es gibt keine standardisierte Stoppwortliste für jede Sprache und sie kann bei verschiedenen Anwendungen variieren, das Prinzip bleibt jedoch gleich. Ein paar Beispiele für typische deutsche Stoppwörter sind: ich, du, er, der, die, und, in, sein. Würde man solche Wörter nicht herausfiltern, so wären die häufigsten Wörter eines Textes nicht sehr aufschlussreich, was dessen Inhalt betrifft.

Wie bei den Stoppwörtern gilt auch das Gleiche für die Satzzeichen. Sie sind nicht relevant für das Erfassen des Textinhaltes und würden die Liste der häufigsten Wörter nur verfälschen.

Bei der Lemmatisierung wird, wie oben schon kurz angesprochen, ein Wort wieder in seine Grundform zurückgeführt (“untersucht” -> “untersuchen”). Dieser Schritt wird vorgenommen, um die Vielzahl an Wortformen eines Wortes auf einen einzelnen Begriff zu reduzieren. Wenn, wie in diesem Fall, die häufigsten Wörter eines Textes ausgegeben werden sollen und die Tokens nicht lemmatisiert werden, dann würden z.B. “untersucht” und “untersuchen” als zwei verschiedene Wörter gelten, was ein unerwünschtes Ergebnis liefern würde. Aus demselben Grund werden auch alle Wörter in Kleinbuchstaben umgewandelt um z.B. der Großschreibung am Anfang eines Satzes entgegenzuwirken.

Je nach Anwendung können diese Preprocessing-Schritte natürlich variieren. Ein Token von spaCy beinhaltet eine Vielzahl an weiteren Eigenschaften, nach denen gefiltert werden kann. Ein paar Beispiele sind: is_digit, is_currency, like_email, like_url.

Im Folgenden wird nun das Erklärte umgesetzt:

from collections import Counter

doc = nlp(long_text)
# Alle vier Schritte des Preprocessing + filtern von tokens die nur Leerzeichen enthalt
words = [token.lemma_.lower() for token in doc if not token.is_stop and not token.is_punct and not token.is_space]
# Häufigkeit für jedes Wort berechnen
word_freq = Counter(words)
# 10 häufigste Wörter auswählen
most_freq_words = word_freq.most_common(10)

for word in most_freq_words:
    print(word)
('computerlinguistik', 6)
('begriff', 3)
('untersuchen', 2)
('sprache', 2)
('informatik', 2)
('chomsky', 2)
('cl', 1)
('linguistischen', 1)
('datenverarbeitung', 1)
('ldv', 1)

Das Ergebnis liefert jetzt einen einfachen ersten Überblick über den Inhalt des Textes. “Computerlinguistik” tritt sechs mal auf und ist somit das häufigste Wort. Weiterhin scheinen auch “Sprache”, “Informatik” und “Chomsky” ein Rolle in dem Text zu spielen. Dies trifft auf den wirklichen Inhalt des Textes zu. Möchte man nur die häufigsten Substantive aus dem Text extrahieren, so kann man jetzt auf das zuvor angesprochene Part-of-speech Tag eines Tokens zugreifen.

# Alle vier Schritte des Preprocessing + filtern von tokens die nur Leerzeichen enthalt + nur Substantive
nouns = [token.lemma_.lower() for token in doc if not token.is_stop and 
                                                  not token.is_punct and
                                                  not token.is_space and
                                                  (token.pos_ == "NOUN" or
                                                  token.pos_ == "PROPN")]
# Häufigkeit für jedes Substantiv berechnen
noun_freq = Counter(nouns)
# 10 häufigste Substantive auswählen
most_freq_nouns = noun_freq.most_common(10)

for noun in most_freq_nouns:
    print(noun)
('computerlinguistik', 6)
('begriff', 3)
('sprache', 2)
('informatik', 2)
('chomsky', 2)
('cl', 1)
('datenverarbeitung', 1)
('ldv', 1)
('form', 1)
('sprachdaten', 1)

Named Entity Recognition (NER)

Bei der Named Entity Recognition werden automatisch Eigennamen identifiziert und in bestimmte Kategorien klassifiziert (z.B. Personen, Orte, Organisationen). spaCy nutzt wiederum ein statistisches Modell, um diese Klassifizierung vorzunehmen. Beim hier genutzten deutschen Modell ist eine Einteilung in die Kategorien Person (Einzelperson oder Familie), Ort/Location (Städte, Länder, Berge, etc.), Organisation (Firmen, Regierungseinrichtungen, etc.) oder Verschiedenes/Miscellaneous (z.B. Ereignisse, Nationalitäten, Kunstgegenstände). Die englischen Modelle bieten eine noch detailliertere Einteilung.

Über die Methode .ents eines Doc Objekts kann auf die gefundenen Entitäten zugegriffen werden. Da eine Entität eine Sammlung von Tokens ist, kann wiederum auf deren Methoden zugegriffen werden. Als Beispiel werden zwei kurze Sätze über die trinnovative GmbH betrachtet.

doc = nlp("Die trinnovative GmbH hat ihren Sitz in Regensburg. Die Geschäftsführer sind Andreas Beer, Johann Schenkl und Sebastian Erdenreich.")

for ent in doc.ents:
    print('{0: <25} {1}'.format(ent.text, ent.label_))
trinnovative GmbH         ORG
Regensburg                LOC
Andreas Beer              PER
Johann Schenkl            PER
Sebastian Erdenreich      PER

Wie leicht zu sehen ist wurde “trinnovative GmbH” als Organisation, “Regensburg” als Ort und die Namen der Geschäftsführer als Personen erkannt. Wie auch beim Dependency Parse bietet spaCy die Möglichkeit erkannte Entitäten direkt in einem Text zu visualisieren. Dies geschieht wiederum über den displaCy Visualizer.

spacy.displacy.render(doc, style='ent')
Die trinnovative GmbH ORG hat ihren Sitz in Regensburg LOC . Die Geschäftsführer sind Andreas Beer PER , Johann Schenkl PER und Sebastian Erdenreich PER .

Mehr Details zur Named Entity Recognition mit spaCy können können in der Dokumentation nachgelesen werden.

Zusammenfassung

In dieser kurzen Einführung zu Natural Language Processing mit spaCy wurden folgende Punkte behandelt:

  • Anleitung zur Einrichtung von spaCy
  • Erstes einfaches Beispiel zum Einstieg und kennenlernen des spaCy Doc Objekts
  • Tokenization mit spaCy und verschiedene Attribute von Tokens
  • Lemmatization, Part-of-speech tagging und ein Einblick in einen Dependency Tree
  • Extrahieren der häufigsten Wörter aus einem Text inklusive Preprocessing
  • Einfaches Beispiel zur Named Entity Recognition mit Visualisierung

Auch wenn hier ein Einblick in einige wichtige Funktionen von spaCy und Konzepte des Natural Language Processing geliefert wurden, ist dies nur ein kleiner Teil von dem, was mit spaCy möglich ist. Weitere Features, die hier nicht behandelt wurden, sind zum Beispiel Rule-based Matching, Text Classification oder das Trainieren eines kompletten Modells für eine Sprache. spaCy ermöglicht also einen einfachen Einstieg in das Thema des Natural Language Processing und ist zugleich äußerst umfangreich und anpassbar um individuelle und komplexe Aufgabenstellungen zu bearbeiten.

Für weitere Informationen ist spaCy’s Dokumentation sehr zu empfehlen.