title | description | prev | next | type | id |
---|---|---|---|---|---|
Kapitel 2: Großangelegte Datenanalyse mit spaCy |
In diesem Kapitel verwendest du deine neuen Skills, um konkrete Informationen aus großen Textmengen zu extrahieren. Du lernst außerdem, spaCys Datenstrukturen optimal zu nutzen sowie statistische und regelbasierte Strategien für Textanalyse effektiv zu kombinieren. |
/chapter1 |
/chapter3 |
chapter |
2 |
- Schlage den String "Katze" in
nlp.vocab.strings
nach, um den Hash zu erhalten. - Schlage den Hash nach, um wieder den String zu erhalten.
- Du kannst den String-Speicher in
nlp.vocab.strings
wie ein reguläres Python-Dictionary verwenden.nlp.vocab.strings["Einhorn"]
zum Beispiel gibt den Hash zurück. Und das Nachschlagen des Hashes gibt wiederum den String zurück.
- Schlage als String-Label "PER" (verwendet für Personen-Entitäten im deutschen
Modell) in
nlp.vocab.strings
nach, um den Hash zu erhalten. - Schlage den Hash nach, um wieder den String zu erhalten.
- Du kannst den String-Speicher in
nlp.vocab.strings
wie ein reguläres Python-Dictionary verwenden.nlp.vocab.strings["Einhorn"]
zum Beispiel gibt den Hash zurück. Und das Nachschlagen des Hashes gibt wiederum den String zurück.
Warum führt dieser Code zu einer Fehlermeldung?
import spacy
# Erstelle ein englisches und deutsches nlp-Objekt
nlp = spacy.blank("en")
nlp_de = spacy.blank("de")
# Schlage die ID für den String "Bowie" nach
bowie_id = nlp.vocab.strings["Bowie"]
print(bowie_id)
# Schlage die ID für "Bowie" im Vokabular nach
print(nlp_de.vocab.strings[bowie_id])
Hashes können nicht umgekehrt werden. Um dieses Problem zu vermeiden, füge das Wort zum neuen Vokabular hinzu, zum Beispiel, indem du einen Text verarbeitest oder den String hinzufügst, oder benutze dasselbe Vokabular, um den Hash wieder in einen String umzuwandeln.
Jeder String kann in einen Hash umgewandelt werden.
Der Name der Variable nlp
ist nur einen Konvention. Wenn der Code die Variable
nlp
statt nlp_de
verwenden würde, würde dies das vorhandene nlp
-Objekt
überschreiben, und damit ebenfalls das Vokabular.
Lass uns ein paar Doc
-Objekte manuell erstellen!
- Importiere das
Doc
vonspacy.tokens
. - Erstelle ein
Doc
mit denwords
undspaces
. Vergiss nicht, das gemeinsame Vokabular als Argument anzugeben.
Die Klasse Doc
akzeptiert drei Argumente: das gemeinsame Vokabular,
typischerweise nlp.vocab
, eine Liste von words
und eine Liste von spaces
,
boolesche Werte, die angeben, ob auf das Wort ein Leerzeichen folgt.
- Importiere das
Doc
vonspacy.tokens
. - Erstelle ein
Doc
mit denwords
undspaces
. Vergiss nicht, das gemeinsame Vokabular als Argument anzugeben.
Schau dir die einzelnen Wörter im erwarteten Text-Output an und siehe nach, ob
auf das Wort ein Leerzeichen folgt. Wenn ja, sollte der Leerzeichen-Wert an
dieser Stelle True
sein. Wenn nicht, sollte er False
sein.
- Importiere das
Doc
vonspacy.tokens
. - Ergänze die
words
undspaces
, um den gewünschten Text zu erzielen, und erstelle eindoc
.
Beachte die einzelnen Tokens. Um zu sehen, wie spaCy diesen String
typischerweise tokenisiert, kannst du es in Python ausprobieren und die
einzelnen Tokens für nlp("Was, echt?!")
drucken.
In dieser Übung wirst du die Doc
- und Span
-Objekte von Hand erstellen und
die Entitäten aktualisieren – genauso wie es spaCy hinter den Kulissen macht.
Ein gemeinsames nlp
-Objekt wurde bereits für dich erstellt.
- Importiere die Klassen
Doc
undSpan
vonspacy.tokens
. - Verwende die Klasse
Doc
direkt, um eindoc
auf Basis der Wörter und Leerzeichen zu erstellen. - Erstelle eine
Span
für "David Bowie", basierend auf demdoc
, und weise ihm das Label"PER"
("Person") zu. - Überschreibe die
doc.ents
mit einer Liste einer Entität: diespan
"David Bowie".
- Das
Doc
wird mit drei Argumenten initialisiert: das gemeinsame Vokabular, z.B.nlp.vocab
, eine Liste von Wörtern und eine Liste von booleschen Werten, die angeben, ob auf ein Wort ein Leerzeichen folgt. - Die Klasse
Span
akzeptiert vier Argumente: das Referenz-Doc
, den Start-Token-Index, den End-Token-Index und ein optionales Label. - Die
doc.ents
sind schreibbar, das heißt du kannst dem Attribut eine Liste bestehend ausSpan
-Objekten zuweisen.
Der Code in diesem Beispiel versucht, einen Text zu analysieren und alle Eigennamen (proper nouns) zu finden, auf die ein Verb folgt.
import spacy
nlp = spacy.load("de_core_news_sm")
doc = nlp("Berlin gefällt mir sehr gut")
# Finde alle Tokens und Wortarten
token_texts = [token.text for token in doc]
pos_tags = [token.pos_ for token in doc]
for index, pos in enumerate(pos_tags):
# Teste, ob der aktuelle Token ein Eigenname ist
if pos == "PROPN":
# Teste, ob der nächste Token ein Verb ist
if pos_tags[index + 1] == "VERB":
result = token_texts[index]
print("Eigenname vor Verb gefunden:", result)
Warum ist der Code schlecht geschrieben?
Es sollte nicht nötig sein, Strings wieder in Token
-Objekte umzuwandeln.
Versuche stattdessen zu vermeiden, Tokens in Strings umzuwandeln, wenn du nach
wie vor auf ihre Attribute und Beziehungen zueinander zugreifen möchtest.
Wandle die Ergebnisse stets so spät wie möglich in Strings um, und versuche, eingebaute Token-Attribute zu verwenden, um den Code einheitlich zu halten.
Das Attribut .pos_
gibt die grobe Wortart zurück und "PROPN"
ist der
korrekte Tag für Eigennamen.
- Schreibe den Code um und verwende die eingebauten Token-Attribute statt die
String-Listen
token_texts
undpos_tags
. - Iteriere über die
token
s imdoc
und schaue dir dastoken.pos_
-Attribut an. - Verwende
doc[token.i + 1]
, um den nächsten Token und sein Attribut.pos_
zu erhalten. - Wenn ein Eigenname (proper noun) vor einem Verb gefunden wurde, drucke seinen
token.text
.
- Lösche die Variablen
token_texts
undpos_tags
– wir müssen keine Listen von Strings im Voraus erstellen! - Statt über die
pos_tags
, iteriere über dietoken
s imdoc
und verwende dastoken.pos_
-Attribut. - Um zu testen, ob der nächste Token ein Verb ist, schaue dir
doc[token.i + 1].pos_
an.
In dieser Übung wirst du eine größere englische Pipeline verwenden, die ca. 20.000 Wortvektoren enthält. Das Pipeline-Package ist bereits vorinstalliert.
- Lade die mittelgroße Pipeline
"en_core_web_md"
mit Wortvektoren. - Drucke den Vektor für
"bananas"
mithilfe des Attributstoken.vector
.
- Um eine Pipeline zu laden, rufe
spacy.load
mit dem String-Namen der Pipeline auf. - Um auf einen Token in einem Doc zuzugreifen, kannst du seinen Index verwenden,
zum Beispiel
doc[4]
.
In dieser Übung wirst du spaCy's similarity
-Methoden verwenden, um Doc
-,
Token
- und Span
-Objekte zu vergleichen und Ähnlichkeitswerte zu erhalten.
- Verwende die Methode
doc.similarity
, umdoc1
mitdoc2
zu vergleichen, und drucke das Ergebnis.
Die Methode doc.similarity
erwartet ein Argument: das andere Objekt, mit dem
das aktuelle Objekt verglichen werden soll.
- Verwende die Methode
token.similarity
, umtoken1
mittoken2
zu vergleichen, und drucke das Ergebnis.
Die Methode token.similarity
erwartet ein Argument: das andere Objekt, mit dem
das aktuelle Objekt verglichen werden soll.
- Erstelle Spans für "great restaurant" und "really nice bar".
- Verwende die Methode
span.similarity
, um die Spans zu vergleichen, und drucke das Ergebnis.
Die Methode span.similarity
erwartet ein Argument: das andere Objekt, mit dem
das aktuelle Objekt verglichen werden soll.
Warum findet dieses Pattern die Tokens "Silicon Valley" nicht im doc
?
pattern = [{"LOWER": "silicon"}, {"TEXT": " "}, {"LOWER": "valley"}]
doc = nlp("Im Silicon Valley herrscht nach wie vor eine männerdominierte Kultur.")
Das Attribut "LOWER"
im Pattern beschreibt Tokens, deren kleingeschriebene
Form einem entsprechenden Wert gleicht. Das heißt, {"LOWER": "valley"}
findet
Tokens wie "Valley", "VALLEY", "valley" usw.
Der Tokenizer sorgt bereits dafür, dass Leerzeichen abgespalten werden, und jedes Dictionary im Pattern beschreibt einen Token.
Standardmäßig werden alle Tokens, die von einem Pattern beschrieben werden, genau einmal gefunden. Operatoren sind nur notwending, wenn dieses Verhalten geändert werden soll – zum Beispiel, um einen Token 0 Mal oder öfter zu finden.
In dieser Übung geht es zur Abwechslung um einen englischen Text. Beide Patterns
enthalten Fehler und finden Tokens nicht wie erwartet. Kannst du sie
korrigieren? Falls du nicht weiter weißt, drucke die Tokens im doc
, um zu
sehen, wie der Text aufgeteilt wurde, und justiere das Pattern entsprechend,
sodass jedes Dictionary einen Token repräsentiert.
- Ändere
pattern1
, sodass es korrekt alle Erwähnungen von"Amazon"
(Groß- und Kleinschreibung), plus einen Eigennamen (proper noun) beginnend mit einem Großbuchstaben findet. - Ändere
pattern2
, sodass es korrekt alle Erwähnungen von"ad-free"
(Groß- und Kleinschreibung), plus das folgende Nomen findet.
- Versuche mal, die Strings, die gefunden werden sollen, mit dem
nlp
-Objekt zu verarbeiten – zum Beispiel,[token.text for token in nlp("ad-free viewing")]
. - Inspiziere die Tokens und achte darauf, dass jedes Dictionary korrekt einen einzelnen Token beschreibt.
Manchmal ist es effizienter, exakte Strings zu suchen, anstatt Patterns für
einzelne Tokens zu schreiben. Dies ist vor allem der Fall, wenn es eine
begrenzte Anzahl an Dingen gibt, die gefunden werden sollen – wie zum Beispiel
alle Länder der Welt. Es gibt bereits eine Liste aller Länder, die wir als Basis
für unser Skript zum Extrahieren von Informationen verwenden können. Eine Liste
von String-Namen ist verfügbar als Variable COUNTRIES
.
- Importiere den
PhraseMatcher
und initialisiere ihn mit dem gemeinsamenvocab
als Variablematcher
. - Füge die
patterns
hinzu und wende den Matcher auf dasdoc
an.
Das gemeinsame vocab
ist verfügbar unter nlp.vocab
.
In der vorherigen Übung hast du ein Skript geschrieben, das spaCys
PhraseMatcher
verwendet, um Ländernamen im Text zu finden. Lass uns nun diesen
Länder-Matcher mit einem längeren Text verwenden, den Satzbau analysieren und
die Entitäten des aktuellen Dokuments mit den gefundenen Ländern aktualisieren.
- Iteriere über die Resultate und erstelle eine
Span
mit dem label"LOC"
(Location). - Überschreibe die Entitäten in
doc.ents
und füge die gefundene Span hinzu. - Wähle den Kopf-Token (head) des Root-Tokens der Span aus.
- Drucke den Text des Kopf-Tokens und der Span.
- Denke daran, dass der Text in der Variable
text
verfügbar ist. - Der Root-Token ist verfügbar als
span.root
. Der Kopf-Token eines Tokens ist verfügbar als das Attributtoken.head
.