Handhabung von NLTK und Gensim#


Wiederholung zu Teil 2 der Schulung zum Thema “Natural Language Processing mit Python”


Für die Analyse von Textdaten existieren verschiedene Python-Bibliotheken, welche gängige Textverarbeitungs- und Analyseverfahren sowie hilfreiche Werkzeuge und Datensätze bereitstellen. Zwei verbreitete davon sind:

Beide Bibliotheken können insb. für die Vorverarbeitung oder Transformation von Textdaten für ML-Pipelines eingesetzt werden.

NLTK#

NLTK benötigt für viele der verfügbaren NLP-Verfahren spezifische Datensätze oder vortrainierte Modelle, z.B. für das Erkennen von Stopwörtern in der englischen Sprache. Für den Download dieser Daten wird z.B. die Methode download() bereitgestellt. Wird hier kein Parameter (z.B. Name eines Datensatzes) angegeben, erscheint ein Dialog für die Auswahl der zu ladenden Daten.

Die Collection popular umfasst dabei z.B. gängige Korpora, Datensätze, vortrainierte Modelle, etc.

import nltk
# Bekanntgabe eines individuellen Ordners für den Download
nltk.data.path.append('/Users/matthias/.cache/nltk_data')
# Potenziell doppelte Einträge aus der Liste der Speicherpfade für NLTK entfernen
nltk.data.path = list(set(nltk.data.path))

Wird nltk.download() ohne Argumente aufgerufen, öffnet sich eine Download Dialog anzeigen.
Der individuelle Ordner für den Download kann dort im Feld “Download Directory” angegeben werden.
Daten für den Download, z.b. die Collection “popular”, können mit den Pfeiltasten (hoch/runter) ausgewählt werden

# nltk.download()

Alternativ kann man nltk.download() auch den gewünschten Namen der herunterzuladenden Collection übergeben.
Eine XML mit den verfügbaren Dateien findet sich hier: https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/index.xml
Zudem lässt sich mittels download_dir= der individuelle Download-Ordner bestimmen.

# Befehl, um die gängigsten Corpora, Modelle, Tokenizer etc herunterzuladen, ca. 400MB
nltk.download('popular', download_dir='/Users/matthias/.cache/nltk_data')
# Test des erfolgreichen Downloads, Zugriff auf geladenen Korpus "gutenberg"
from nltk.corpus import gutenberg
gutenberg.words()
['[', 'Emma', 'by', 'Jane', 'Austen', '1816', ']', ...]
# Erstellen eines Beispielsatzes
doc = "Life is like riding a bicycle. To keep your balance, you must keep moving."

Tokenization#

Für die Tokenization laden wir uns zusätzlich den Tokenizer punkt_tab.

nltk.download('punkt_tab', download_dir='/Users/matthias/.cache/nltk_data')
[nltk_data] Downloading package punkt_tab to
[nltk_data]     /Users/matthias/.cache/nltk_data...
[nltk_data]   Unzipping tokenizers/punkt_tab.zip.
True
from nltk.tokenize import sent_tokenize, word_tokenize
import string
# Tokenization für Sätze
sentences = sent_tokenize(doc)
print(sentences)
['Life is like riding a bicycle.', 'To keep your balance, you must keep moving.']
# Tokenization für Wörter, Entfernen von Satzzeichen
tokens = word_tokenize(doc)
tokens = [token for token in tokens if token not in string.punctuation]
print(tokens)
['Life', 'is', 'like', 'riding', 'a', 'bicycle', 'To', 'keep', 'your', 'balance', 'you', 'must', 'keep', 'moving']

Stopword removal#

from nltk.corpus import stopwords
# Laden der englischen Stopwort-Liste
eng_stop_words = set(stopwords.words('english'))
print('Anzahl der englischen Stopwords: ', len(eng_stop_words))
Anzahl der englischen Stopwords:  198
filtered_tokens = [token for token in tokens if token.casefold() not in eng_stop_words]
print(filtered_tokens)
['Life', 'like', 'riding', 'bicycle', 'keep', 'balance', 'must', 'keep', 'moving']

Stemming#

from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
stemmed_tokens = [stemmer.stem(token) for token in filtered_tokens]
print(stemmed_tokens)
['life', 'like', 'ride', 'bicycl', 'keep', 'balanc', 'must', 'keep', 'move']

Gensim#

Gensim baut auf vier grundlegenden Konzepten auf:

  • Dokument: Sammlung von Text

  • Korpus: Sammlung von Dokumenten

  • Vektoren: Numerische Repräsentation eines Dokuments

  • Modell: Algorithmus zur Transformation von einer Repräsentation in eine andere

Für die grundlegende Vorverarbeitung von Text (z.b. Tokenization, Stopwords, POS, etc) bieten sich Verfahren aus NLTK an.

ACHTUNG:

Bei der Installation und dem nachfolgenden Import von Gensim kann es unter Umständen zu folgendem Fehler kommen:

  • "ImportError: cannot import name 'triu' from 'scipy.linalg'"

Dabei wird auf ein fehlendes, von Gensim genutztes Modul der Bibliothek scipy verwiesen, welches in der aktuellsten Version von scipy nicht mehr vorhanden ist. Dies lässt sich mit conda reparieren:

  • Öffne ein Terminal in Jupyter Lab (“File -> New -> Terminal”)

  • Führe in diesem Terminal diesen Befehl aus, um die korrekten Abhängigkeiten für Gensim zu installieren:

    • conda update scipy gensim

  • Lade den Python-Kernel für dieses Notebook neu (kreisförmiger Pfeil in den Notebook-Funktionen mit “Restart the kernel”)

  • Führe alle Codezellen des Notebooks danach wieder aus

import gensim

Embeddings und Vektoren für Text#

Wir wollen hier im Speziellen die Möglichkeit ansehen, mit Gensim sog. Embeddings - also numerische Vektor-Repräsentationen - für Text zu erstellen.
Hierzu laden wir mit common_texts zunächst einen kleinen Testdatensatz, dieser beinhaltet 9 Dokumente.

from gensim.test.utils import common_texts
print(common_texts)
[['human', 'interface', 'computer'], ['survey', 'user', 'computer', 'system', 'response', 'time'], ['eps', 'user', 'interface', 'system'], ['system', 'human', 'system', 'eps'], ['user', 'response', 'time'], ['trees'], ['graph', 'trees'], ['graph', 'minors', 'trees'], ['graph', 'minors', 'survey']]

Weiterhin laden wir das Embedding-Modell Word2Vec, welches Vektor-Repräsentationen von Wörtern erzeugt.
Gensim stellt mit Doc2Vec zudem auch Möglichkeiten bereit, vollständige Paragraphen bzw ganze Dokumente in eine Vektor-Repräsentation zu überführen.

from gensim.models import Word2Vec

model = Word2Vec(sentences=common_texts, vector_size=100, window=3, min_count=1, workers=4)
# Vektor-Repräsentation für ein Wort des Vocabulars erhalten
vector = model.wv['computer']
print(vector)
[-0.00515774 -0.00667028 -0.0077791   0.00831315 -0.00198292 -0.00685696
 -0.0041556   0.00514562 -0.00286997 -0.00375075  0.0016219  -0.0027771
 -0.00158482  0.0010748  -0.00297881  0.00852176  0.00391207 -0.00996176
  0.00626142 -0.00675622  0.00076966  0.00440552 -0.00510486 -0.00211128
  0.00809783 -0.00424503 -0.00763848  0.00926061 -0.00215612 -0.00472081
  0.00857329  0.00428459  0.0043261   0.00928722 -0.00845554  0.00525685
  0.00203994  0.0041895   0.00169839  0.00446543  0.0044876   0.0061063
 -0.00320303 -0.00457706 -0.00042664  0.00253447 -0.00326412  0.00605948
  0.00415534  0.00776685  0.00257002  0.00811905 -0.00138761  0.00808028
  0.0037181  -0.00804967 -0.00393476 -0.0024726   0.00489447 -0.00087241
 -0.00283173  0.00783599  0.00932561 -0.0016154  -0.00516075 -0.00470313
 -0.00484746 -0.00960562  0.00137242 -0.00422615  0.00252744  0.00561612
 -0.00406709 -0.00959937  0.00154715 -0.00670207  0.0024959  -0.00378173
  0.00708048  0.00064041  0.00356198 -0.00273993 -0.00171105  0.00765502
  0.00140809 -0.00585215 -0.00783678  0.00123305  0.00645651  0.00555797
 -0.00897966  0.00859466  0.00404816  0.00747178  0.00974917 -0.0072917
 -0.00904259  0.0058377   0.00939395  0.00350795]
# Suche die ähnlichsten Worte zu einem vorgegebenen Wort auf Basis der Vektorähnlichkeit
sims = model.wv.most_similar('computer', topn=5)
print(sims)
[('system', 0.21617142856121063), ('survey', 0.044698115438222885), ('interface', 0.015025205910205841), ('time', 0.001951074693351984), ('trees', -0.03284316137433052)]