EKI07 - Natural Language Processing

Von den NLP-Aufgaben (Textklassifikation, QA, Uebersetzung ...) ueber das Bag-of-Words-Modell und tf-idf bis zu scikit-learn-Pipelines und spaCy.

Ueberblick

Natural Language Processing (NLP) ist der Teilbereich der KI, der sich mit der Verarbeitung natuerlicher Sprache beschaeftigt. In der KI-Landkarte (nach B. Humm) gehoert NLP zum Bereich Communicating ("Applying intelligence") und liegt an der Schnittstelle von nicht-symbolischer KI (Machine Learning) und symbolischer, wissensbasierter KI.

Dieser Foliensatz behandelt:

  • Die verschiedenen Bereiche/Aufgaben des NLP
  • Das Bag-of-Words-Modell als einfachen NLP-Ansatz
  • tf-idf und das n-Gramm-Modell als Erweiterungen
  • Ein Beispiel zur Textklassifikation mit scikit-learn (Vorhersage des Filmgenres)
  • Die Bibliothek spaCy und ihre Funktionalitaet
  • Ein Beispiel zu einfachem Question Answering

Als durchgaengiges Beispiel dient in fast allen Folien der Film "A Beautiful Mind" (2001).

Gliederung des Foliensatzes (Aufbau)

  1. Ueberblick
  2. Das Bag-of-Words-Modell
  3. Beispiel Textklassifikation
  4. spaCy
  5. Beispiel Einfaches Question Answering
  6. Mini-Test

Bereiche der Verarbeitung natuerlicher Sprache

Die Folien nennen sechs Bereiche des NLP. Jeder Bereich laesst sich ueber sein Eingabe-/Ausgabe-Verhalten charakterisieren.

Bereich (dt.)EnglischAufgabeEingabe -> Ausgabe
Information RetrievalIRAbrufen relevanter Dokumente. Laut Folie waere "document retrieval" der bessere Begriff.Text -> relevante Dokumente (z. B. HTML- oder MP4-Dokument)
Textklassifikationtext classificationKlassifizieren natuerlichsprachlicher Texte, z. B. nach Sprache, Thema oder Stimmung (sentiment).Text -> Klassifikation (z. B. EN/DE)
Information ExtractionIEVerstehen von geschriebenen oder gesprochenen Texten; Aufbau von Wissensgraphen aus Texten.Text -> Wissensgraph
Question AnsweringQABeantworten von natuerlichsprachigen Fragen.Fragetext -> Antworttext
Maschinelles Uebersetzenmachine translationUebersetzen von Texten zwischen verschiedenen natuerlichen Sprachen.Text in Sprache A -> Text in Sprache B
Texterzeugungtext generationErzeugen von geschriebenen oder gesprochenen Texten; Zusammenfassen von Texten.Wissensgraph -> Text

Illustrierende Beispiele aus den Folien

  • Information Retrieval: Eine Suchmaschinen-Anfrage "a beautiful mind" liefert relevante Dokumente (Wikipedia-HTML-Seite, YouTube-MP4-Trailer usw.).
  • Textklassifikation (Spracherkennung): Der englische Uebersichtstext wird als EN klassifiziert, der deutsche als DE.
  • Information Extraction: Aus dem Satz "A Beautiful Mind is a movie which belongs to the genre drama." wird ein Wissensgraph aufgebaut.
graph LR
    M["Movie_453"] -->|a| MC["Movie"]
    M -->|title| T["A Beautiful Mind"]
    M -->|genres| G18["Genre_18"]
    G18 -->|a| GC["Genre"]
    G18 -->|name| DR["Drama"]
  • Question Answering: Auf die Frage "Wer drehte den Film 'A Beautiful Mind'?" lautet die Antwort "Ron Howard".
  • Maschinelle Uebersetzung: Werkzeugbeispiel DeepL (Englisch -> Deutsch).
  • Texterzeugung: Umgekehrt zu IE - aus dem Wissensgraphen wird wieder Text erzeugt.

Hinweis: In der Textzeile der Folie zu Information Extraction steht "gespochenen" (Tippfehler); gemeint ist "gesprochenen". Ausserdem wird das Zusammenfassen von Texten (Summarization) nicht als eigener Bereich gefuehrt, sondern unter Texterzeugung genannt.


Das Bag-of-Words-Modell

Das Bag-of-Words-Modell (BoW) ist ein einfacher NLP-Ansatz, der in manchen Anwendungen (z. B. Textklassifikation) erstaunlich gute Ergebnisse liefert.

Grundidee: Ein Text wird als ein Multi-Set (bag) von Worten mit ihren Haeufigkeiten repraesentiert, ohne die Grammatik oder die Reihenfolge der Worte zu beruecksichtigen.

Beispiel (Quelle: Wikipedia, Bag-of-words model):

"John likes to watch movies. Mary likes movies too."

BoW = {"John":1, "likes":2, "to":1, "watch":1, "movies":2, "Mary":1, "too":1}

"John" taucht einmal auf, "likes" zweimal, "movies" zweimal usw.

Anwendung: Feature-Vektoren fuer ML

Das Bag-of-Words-Modell wird verwendet, um Feature-Vektoren fuer Machine Learning zu erzeugen. In der einfachsten Form ist jeder Vektoreintrag die Worthaeufigkeit (term frequency) eines Wortes im Text.

Beispiel-Feature-Matrix (jede Zeile = ein Text t, letzte Spalte = Klassen-Label):

IDJohnlikestowatchmoviesMarytoo...Label
t11211211...A
t20020001...C
..............................
Tn0122300...A

Die Spalten bilden das Vokabular des Korpus; jede Zelle zaehlt, wie oft das Wort im jeweiligen Text vorkommt. t1 entspricht genau dem BoW aus dem Beispiel oben.


tf-idf (term frequency - inverse document frequency)

Worte, die haeufig in einem Text vorkommen, sind nicht unbedingt die wichtigsten - Beispiel im Englischen: "the", "a", "to". Solche haeufigen Fuellwoerter sollten weniger Gewicht bekommen.

Grundidee: Normalisiere die Worthaeufigkeit mit ihrer inversen Dokumenthaeufigkeit.

  • Die Worthaeufigkeit (term frequency, tf) gibt an, wie oft ein Wort im betrachteten Text vorkommt.
  • Die Dokumenthaeufigkeit (document frequency, df) gibt an, in wie vielen Texten des gesamten Korpus (corpus) ein Wort vorkommt.

Kommt ein Wort in fast allen Dokumenten vor (hohe df), ist es wenig informativ und wird abgewertet. Kommt es nur in wenigen Dokumenten vor, ist es unterscheidungsstark und wird aufgewertet.

Formel

Die Folie verweist darauf, dass es mehrere Formeln fuer tf-idf gibt (siehe Wikipedia "Tf-idf"). Das Gewicht eines Terms tt in einem Dokument dd eines Korpus DD ist grundsaetzlich das Produkt aus term frequency und inverse document frequency:

tfidf(t,d,D)=tf(t,d)idf(t,D)\text{tfidf}(t, d, D) = \text{tf}(t, d) \cdot \text{idf}(t, D)

Eine gaengige Variante der inversen Dokumenthaeufigkeit lautet:

idf(t,D)=logN{dD:td}\text{idf}(t, D) = \log \frac{N}{|\{d \in D : t \in d\}|}

Dabei ist N=DN = |D| die Gesamtzahl der Dokumente und der Nenner die Zahl der Dokumente, die den Term tt enthalten (= df).

Hinweis: Die Folie gibt bewusst keine einzelne feste Formel an, sondern verweist auf Wikipedia ("Es gibt mehrere Formeln fuer tf-idf"). Die hier gezeigte log(N/df)\log(N/df)-Form ist die verbreitete Standardvariante; scikit-learns TfidfTransformer nutzt eine leicht abgewandelte, geglaettete Form. Fuer die Pruefung genuegt das Grundprinzip "tf mal idf" und die Rolle von Wort- und Dokumenthaeufigkeit.

Worked Example (Prinzip)

Angenommen der Korpus hat N=100N = 100 Dokumente.

  • Das Wort "the" kommt in nahezu allen Dokumenten vor, z. B. df=100df = 100: idf=log(100/100)=0\text{idf} = \log(100/100) = 0. -> Gewicht 0, egal wie oft es im Text steht.
  • Das Wort "cryptography" kommt nur in df=5df = 5 Dokumenten vor: idf=log(100/5)=log(20)1,3\text{idf} = \log(100/5) = \log(20) \approx 1{,}3. -> deutliches Gewicht.

So werden seltene, aussagekraeftige Woerter gegenueber allgegenwaertigen Fuellwoertern hervorgehoben.


n-Gramm-Modell

Das einfache Bag-of-Words-Modell beruecksichtigt nur einzelne Worte (1-Gramme, Unigramme). Als Erweiterung kann man Sequenzen aus N aufeinanderfolgenden Worten (n-gram) betrachten.

Beispiel fuer N=2 (2-Gramme / Bigramme) - zusaetzlich zu den 1-Grammen kommen Spalten fuer Wortpaare hinzu:

IDJohnlikesto...John likeslikes toto watch...Label
t1121...111...A
t2002...001...C
..............................
tn012...012...A

Wichtige Punkte:

  • n-Gramme koennen genutzt werden, um Feature-Vektoren zu generieren.
  • n-Gramme koennen ebenfalls mit tf-idf kombiniert werden.
  • Vorteil: Ein Stueck Wortreihenfolge/Kontext wird erfasst (im Gegensatz zum reinen BoW).

Diskussion des Bag-of-Words-Modells

Die Folie stellt die offene Frage nach Vor- und Nachteilen. Aus dem Foliensatz ableitbar:

  • Vorteile: einfacher Ansatz, erstaunlich gute Ergebnisse in manchen Anwendungen (z. B. Textklassifikation), leicht in Feature-Vektoren fuer ML ueberfuehrbar.
  • Nachteile: Grammatik und Wortreihenfolge gehen verloren; haeufige Fuellwoerter dominieren (Motivation fuer tf-idf); die Vektoren werden sehr hochdimensional und duenn besetzt (sparse). n-Gramme mildern den Reihenfolge-Verlust teilweise.

Beispiel: Textklassifikation mit scikit-learn

Aufgabe: Vorhersage des Genres eines Films aus seinem Uebersichtstext (Overview). Konkret binaere Klassifikation "Drama" (1) vs. "nicht Drama" (0).

  • Eingabe: Uebersichtstext eines Films (z. B. von TMDB).
  • Ausgabe: Genre (Kategorie), hier binaer.
  • Trainingsdaten: Movie_Overview_Classification.csv mit Spalten id, overview und genre_Drama (0/1).

1. Daten aus CSV laden (pandas)

import pandas as pd

data = pd.read_csv('data/Movie_Overview_Classification.csv',
                   encoding='utf8',
                   delimiter=',',
                   quotechar='|',
                   quoting=csv.QUOTE_MINIMAL)

2. Bag-of-Words mit dem CountVectorizer

Der CountVectorizer von scikit-learn uebernimmt Tokenisierung, Zaehlen und Filtern von Stoppwoertern in einem Schritt und baut daraus Feature-Vektoren (Wortzaehlungen).

from sklearn.feature_extraction.text import CountVectorizer

count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(twenty_train.data)
X_train_counts.shape
# (2257, 35788)

count_vect.vocabulary_.get(u'algorithm')
# 4690

Der CountVectorizer unterstuetzt auch das Zaehlen von N-Grammen von Worten oder aufeinanderfolgenden Zeichen. Der Indexwert eines Wortes im Vokabular ist mit seiner Haeufigkeit im gesamten Trainingskorpus verknuepft.

3. tf-idf-Transformation mit dem TfidfTransformer

Reine Zaehlungen benachteiligen kurze Dokumente. Deshalb teilt man durch die Gesamtzahl der Woerter (-> tf) und skaliert Woerter herunter, die in vielen Dokumenten vorkommen (-> tf-idf).

from sklearn.feature_extraction.text import TfidfTransformer

tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
X_train_tf = tf_transformer.transform(X_train_counts)

# fit und transform in einem Schritt (mit idf):
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
X_train_tfidf.shape
# (2257, 35788)

4. Training mit MultinomialNB (Naive Bayes)

Fuer Wortzaehlungen eignet sich die multinomiale Variante von Naive Bayes als solide Baseline.

from sklearn.naive_bayes import MultinomialNB

clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)

# Vorhersage fuer neue Dokumente (nur transform, nicht fit_transform):
docs_new = ['God is love', 'OpenGL on the GPU is fast']
X_new_counts = count_vect.transform(docs_new)
X_new_tfidf = tfidf_transformer.transform(X_new_counts)
predicted = clf.predict(X_new_tfidf)

5. Zusammengesetzter Classifier mit einer Pipeline

Um die Kette Vectorizer -> Transformer -> Classifier bequem zu handhaben, bietet scikit-learn die Pipeline-Klasse, die sich wie ein zusammengesetzter Classifier verhaelt.

from sklearn.pipeline import Pipeline

text_clf = Pipeline([
    ('vect',  CountVectorizer()),
    ('tfidf', TfidfTransformer()),
    ('clf',   MultinomialNB()),
])

text_clf.fit(twenty_train.data, twenty_train.target)

Die Namen vect, tfidf und clf sind frei waehlbar und koennen spaeter z. B. fuer Grid-Search der Hyperparameter genutzt werden. Das gesamte Modell wird mit einem einzigen Befehl trainiert.

graph LR
    A["Rohtext (overview)"] --> B["CountVectorizer (Bag of Words)"]
    B --> C["TfidfTransformer (tf-idf)"]
    C --> D["MultinomialNB (Classifier)"]
    D --> E["Genre-Label (Drama / nicht Drama)"]

6. Kreuzvalidierung: Treffergenauigkeit

from sklearn.model_selection import cross_val_score

scores = cross_val_score(model, X, y)
print(f'Accuracy: {scores.mean()}')

Die Kreuzvalidierung (cross validation) liefert die durchschnittliche Treffergenauigkeit (Accuracy) ueber mehrere Datenaufteilungen.


spaCy

spaCy ist eine freie Open-Source-Python-Bibliothek fuer fortgeschrittenes NLP (im Foliensatz vorgestellt im Kontext Question Answering). Sie ist auf den Produktiveinsatz ausgelegt und verarbeitet grosse Textmengen effizient.

Funktionalitaet von spaCy

FunktionBeschreibung
TokenizationSegmentieren von Text in Woerter, Satzzeichen usw.
Part-of-speech (POS) TaggingZuweisen von Wortarten zu Tokens, z. B. Verb oder Nomen.
Dependency ParsingZuweisen syntaktischer Abhaengigkeits-Labels (Beziehungen wie Subjekt/Objekt).
LemmatizationZuweisen der Grundform eines Wortes (Lemma von "was" ist "be", von "rats" ist "rat").
Sentence Boundary Detection (SBD)Finden und Segmentieren einzelner Saetze.
Named Entity Recognition (NER)Erkennen benannter Objekte der realen Welt, z. B. Personen, Firmen, Orte.
Entity Linking (EL)Aufloesen textueller Entitaeten zu eindeutigen IDs in einer Wissensbasis.
SimilarityVergleichen von Woertern, Textspannen und Dokumenten und wie aehnlich sie sind.
Text ClassificationZuweisen von Kategorien/Labels zu ganzen Dokumenten oder Teilen davon.
Rule-based MatchingFinden von Token-Sequenzen anhand von Text und linguistischen Annotationen (aehnlich Regex).
TrainingAktualisieren und Verbessern der Vorhersagen eines statistischen Modells.
SerializationSpeichern von Objekten in Dateien oder Byte-Strings.

Hinweis: Die Folienueberschrift bezeichnet spaCy als "Bibliothek fuer Question Answering". spaCy ist eine allgemeine NLP-Bibliothek; QA ist hier nur der konkrete Anwendungsfall des Foliensatzes. Die Funktionsliste zeigt, dass spaCy weit mehr abdeckt.

Modelle installieren und Text verarbeiten

python3 -m pip install --user spacy
python3 -m spacy download en_core_web_sm
python3 -m spacy download de_core_news_sm
import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("Hello, World. Here are two sentences.")
print([t.text for t in doc])
# ['Hello', ',', 'World', '.', 'Here', 'are', 'two', 'sentences', '.']

Aehnlichkeitsmetrik mit Wortvektoren (word vectors)

Die Aehnlichkeit (similarity) wird durch Vergleich von Wortvektoren (word vectors / word embeddings) bestimmt - mehrdimensionale Bedeutungsrepraesentationen eines Wortes, die z. B. mit einem Algorithmus wie word2vec erzeugt werden koennen. Fuer Vektoren braucht man ein grosses Modell:

python3 -m spacy download en_core_web_lg  # grosses package
import spacy

nlp = spacy.load("en_core_web_lg")
doc = nlp("Mango and ananas are similar. Pizza and dogs aren't.")

mango  = doc[0]
ananas = doc[2]
pizza  = doc[6]
dogs   = doc[8]

print("mango vs. ananas", mango.similarity(ananas))  # ~ 0.524
print("pizza vs. dogs",  pizza.similarity(dogs))      # ~ 0.030
print(mango.has_vector, ananas.has_vector, pizza.has_vector, dogs.has_vector)
print(mango.vector)

Aehnliche Begriffe (Mango/Ananas) erhalten einen hohen Aehnlichkeitswert, unaehnliche (Pizza/Hunde) einen niedrigen.

Fortgeschrittenes NLP: Saetze parsen

Mit displacy kann man den Dependency Parse eines Satzes visualisieren:

from spacy import displacy

doc = nlp("This is a sentence.")
displacy.render(doc, style="dep")

Ergebnis (Wortarten und Abhaengigkeiten): "This" (PRON) ist per nsubj mit "is" (AUX) verbunden, "is" hat "sentence" (NOUN) als attr, und "a" (DET) haengt per det an "sentence".

graph LR
    IS["is (AUX)"] -->|nsubj| THIS["This (PRON)"]
    IS -->|attr| SENT["sentence (NOUN)"]
    SENT -->|det| A["a (DET)"]

spaCy Architektur und Ueberblick

Die Verarbeitung startet mit einem Language-Objekt (konventionell nlp genannt), das Text ueber den Tokenizer und eine Pipeline von Komponenten in ein Doc-Objekt ueberfuehrt. Vocab (mit StringStore und Vectors) wird geteilt.

Zentrale Container-Objekte:

ObjektBeschreibung
DocContainer fuer den Zugriff auf linguistische Annotationen.
DocBinSammlung von Doc-Objekten fuer effiziente binaere Serialisierung (auch fuer Trainingsdaten).
ExampleSammlung von Trainingsannotationen aus zwei Doc-Objekten: Referenzdaten und Vorhersagen.
LanguageVerarbeitungsklasse, die Text in Doc-Objekte umwandelt (Variable meist nlp).
LexemeEintrag im Vokabular - ein Worttyp ohne Kontext (kein POS-Tag, kein Parse).
SpanEin Ausschnitt (Slice) aus einem Doc-Objekt.
SpanGroupBenannte Sammlung von Spans eines Doc.
TokenEinzelnes Token, d. h. ein Wort, Satzzeichen, Whitespace usw.
graph TD
    TEXT["Text"] --> NLP["Language (nlp)"]
    VOCAB["Vocab (StringStore, Vectors)"] --> NLP
    NLP --> TOK["Tokenizer"]
    TOK --> COMP["Pipeline-Komponenten (Model + Weights)"]
    COMP --> DOC["Doc"]
    DOC --> TOKEN["Token (doc[i])"]
    DOC --> SPAN["Span (doc[a:b])"]

Beispiel: Einfaches Question Answering

Aufgabe: Einfache Fragen ueber den Film "A Beautiful Mind" beantworten. Grundlage ist ein Wikipedia-Absatz ueber den Film.

  • Eingabe: Fragetext, z. B. "Which price was John Nash awarded?"
  • Ausgabe: Antworttext, z. B. "The Nobel price in Economics".
  • Textbasis: "[...] biography of the mathematician John Nash, a Nobel Laureate in Economics."

Ansatz: FAQ als Wissensbasis

Die Trainingsdaten sind eine FAQ-Wissensbasis (QA_train_data.csv) mit Spalten Question und Answer, z. B.:

QuestionAnswer
From which country is the film A Beautiful Mind?America
When was the film A Beautiful Mind released?2001
Of which genre is the film A Beautiful Mind?biographical drama
What is John Nash's profession?mathematician
Which prices did John Nash win?Nobel price in Economics and Abel Prize
At which university was Nash a graduate student?Princeton University
What disease did Nash develop?paranoid schizophrenia

Kernidee: Antworten auf aehnliche Fragen finden

Eine neue Frage wird mit den FAQ-Fragen verglichen. Ist eine bekannte Frage hinreichend aehnlich, wird deren Antwort zurueckgegeben.

Beispiel:

  • FAQ: "Which prices did John Nash win?" -> "Nobel price in Economics and Abel prize"
  • Neue Frage: "Which prices was John Nash awarded?" -> aehnlich? Falls ja: gleiche Antwort.
graph LR
    Q["Neue Frage"] --> SIM{"Aehnlich zu einer FAQ-Frage?"}
    SIM -->|"ja (genug Konfidenz)"| A["Antwort der FAQ-Frage zurueckgeben"]
    SIM -->|nein| N["None (keine Antwort)"]

Die Testdaten (QA_test_data.csv) enthalten viele Umformulierungen derselben Fragen (z. B. "Where was the film A Beautiful Mind made?", "In which country was the film ... made?"), die alle dieselbe Antwort haben sollen - damit wird die Robustheit des Aehnlichkeitsvergleichs geprueft.

Code-Geruest

import pandas as pd

train_data = pd.read_csv('data/QA_train_data.csv')
test_data  = pd.read_csv('data/QA_test_data.csv')

def predict_answer(question: str) -> str:
    """
    Predicts an answer to a given question
    :param question: question string
    :return: answer string or None if insufficient confidence
    """
    # Your code...

# Predict
predicted = test_data['Question'].apply(lambda q: predict_answer(q))
actual    = test_data['Answer']

# Evaluate
score = evaluate_results(predicted, actual)

predict_answer gibt bei zu geringer Konfidenz None zurueck. Die Umsetzung ist als Uebung offen gelassen; naheliegend ist ein Aehnlichkeitsvergleich (z. B. spaCy-similarity oder tf-idf-basierte Cosinus-Aehnlichkeit) zwischen neuer Frage und FAQ-Fragen.


Pruefungsrelevanz

  • Sechs NLP-Bereiche samt Eingabe/Ausgabe kennen: Information Retrieval, Textklassifikation, Information Extraction, Question Answering, Maschinelles Uebersetzen, Texterzeugung. Aufgabe der Textklassifikation = Texte klassifizieren (Sprache, Thema, Stimmung/sentiment).
  • Bag-of-Words: Text als Multi-Set von Worten mit Haeufigkeiten, ohne Grammatik und Reihenfolge; erzeugt Feature-Vektoren fuer ML. Beispiel "John likes to watch movies. Mary likes movies too." reproduzieren koennen.
  • tf-idf: Motivation (haeufige Woerter sind nicht die wichtigsten), Grundidee (tf mit inverser df normalisieren), Unterschied Worthaeufigkeit vs. Dokumenthaeufigkeit; Formel tfidf=tfidf\text{tfidf} = \text{tf} \cdot \text{idf} mit idf=log(N/df)\text{idf} = \log(N/df).
  • n-Gramm-Modell: Sequenzen aus N aufeinanderfolgenden Worten; erweitert BoW um Kontext; kombinierbar mit tf-idf.
  • scikit-learn-Pipeline: Kette CountVectorizer -> TfidfTransformer -> MultinomialNB als zusammengesetzter Classifier; Kreuzvalidierung mit cross_val_score.
  • spaCy-Funktionalitaet: Tokenization, POS-Tagging, Dependency Parsing, Lemmatization, SBD, NER, Entity Linking, Similarity (Wortvektoren), Text Classification, Rule-based Matching.
  • Question Answering (einfach): Aehnlichste FAQ-Frage finden und deren Antwort zurueckgeben.

Mini-Test

  1. Benennen und erklaeren Sie die verschiedenen Bereiche des NLP.
  2. Was ist die Aufgabe der Textklassifikation?
  3. Erklaeren Sie das Bag-of-Words-Modell.
  4. Erklaeren Sie tf-idf.
  5. Erklaeren Sie das n-Gramm-Modell.
  6. Wie benutzt man Pipelines in scikit-learn?
  7. Was ist die NLP-Aufgabe Question Answering?
  8. Erklaeren Sie die Funktionalitaet von spaCy.