Alles ist möglich: NLP-Probleme mit Spacy lösen





Die Verarbeitung natürlicher Sprache ist mittlerweile allgegenwärtig: Sprachschnittstellen und Chat-Bots entwickeln sich rasant, Modelle für die Verarbeitung großer Textdaten werden entwickelt und die maschinelle Übersetzung entwickelt sich weiter.



In diesem Artikel werden wir uns die relativ neue SpaCy-Bibliothek ansehen, die derzeit eine der beliebtesten und bequemsten Lösungen für die Textverarbeitung in Python ist. Mit seiner Funktionalität können Sie eine Vielzahl von Aufgaben lösen: von der Identifizierung von Wortarten über das Extrahieren benannter Entitäten bis hin zur Erstellung eigener Modelle für die Analyse.



Schauen wir uns zunächst an, wie Daten in SpaCy verarbeitet werden. Der zur Verarbeitung geladene Text durchläuft nacheinander verschiedene Verarbeitungskomponenten und wird als Instanz des Doc-Objekts gespeichert:







Doc ist die zentrale Datenstruktur in SpaCy, in der Wortfolgen oder, wie sie auch genannt werden, Token gespeichert werden. Innerhalb des Doc-Objekts können zwei andere Objekttypen unterschieden werden: Token und Span. Token ist eine Verknüpfung zu einzelnen Wörtern eines Dokuments, und Span ist eine Verknüpfung zu einer Folge von mehreren Wörtern (Sie können sie selbst erstellen):







Eine weitere wichtige Datenstruktur ist das Vocab-Objekt, in dem eine Reihe von Nachschlagetabellen gespeichert sind, die allen Dokumenten gemeinsam sind. Dies spart Speicher und bietet eine einzige Informationsquelle für alle verarbeiteten Dokumente.



Dokumenttoken werden über einen Hash mit dem Vocab-Objekt verbunden, mit dem Sie die Anfangsformen von Wörtern oder andere lexikalische Attribute von Token







abrufen können : Jetzt wissen wir, wie die Speicherung und Verarbeitung von Daten in der SpaCy-Bibliothek funktioniert. Wie können die sich daraus ergebenden Möglichkeiten genutzt werden? Werfen wir einen Blick auf die Operationen, mit denen Text nacheinander verarbeitet werden kann.



1. Grundlegende Operationen



Bevor Sie mit Text arbeiten, sollten Sie das Sprachmodell importieren. Für die russische Sprache gibt es ein offizielles Modell von SpaCy, das die Tokenisierung (Aufteilen von Text in separate Token) und eine Reihe anderer grundlegender Operationen unterstützt:



from spacy.lang.ru import Russian
      
      





Nach dem Importieren und Instanziieren des Sprachmodells können Sie mit der Verarbeitung des Texts beginnen. Dazu müssen Sie nur den Text an die erstellte Instanz übergeben:



nlp = Russian()
doc = nlp("     ,   .")
      
      





Die Arbeit mit dem resultierenden Doc-Objekt ist der Arbeit mit Listen sehr ähnlich: Sie können über den Index auf das gewünschte Token zugreifen oder aus mehreren Token Slices erstellen. Um den Text eines Tokens oder Slice abzurufen, können Sie das Textattribut verwenden:



token = doc[0]
print(token.text)

span = doc[3:6]
print(span.text)


  
      
      





Für weitere Informationen darüber, welche Art von Informationen im Token enthalten sind, können die folgenden Attribute verwendet werden:



  1. is_alpha - Überprüfen Sie, ob das Token nur alphabetische Zeichen enthält
  2. is_punct - Überprüfen Sie, ob das Token ein Interpunktionszeichen ist
  3. like_num - prüfe, ob ein Token eine Zahl ist


print("is_alpha:    ", [token.is_alpha for token in doc])
print("is_punct:    ", [token.is_punct for token in doc])
print("like_num:    ", [token.like_num for token in doc])

      
      





Betrachten wir ein weiteres Beispiel, bei dem alle Token vor dem Punkt auf dem Bildschirm angezeigt werden. Um dieses Ergebnis zu erhalten, überprüfen Sie beim Durchlaufen von Token das folgende Token mit dem Attribut token.i:



for token in doc:
    if token.i+1 < len(doc):
        next_token = doc[token.i+1]
        if next_token.text == ".":
            print(token.text)


      
      





2. Operationen mit Syntax



Andere Modelle werden für komplexere Textverarbeitungsvorgänge verwendet. Sie sind speziell für Aufgaben im Zusammenhang mit Syntax, Extraktion benannter Entitäten und Arbeiten mit Wortbedeutungen geschult. Für Englisch gibt es beispielsweise 3 offizielle Modelle, die sich in der Größe unterscheiden. Für die russische Sprache ist das offizielle Modell derzeit noch nicht trainiert, aber es gibt bereits ein ru2-Modell aus Quellen von Drittanbietern, das mit der Syntax arbeiten kann.



Am Ende dieses Artikels wird erläutert, wie Sie eigene Modelle erstellen oder vorhandene Modelle zusätzlich trainieren, damit sie für bestimmte Aufgaben besser funktionieren.



Um die Funktionen von SpaCy vollständig zu veranschaulichen, werden wir die englischen Sprachmodelle in diesem Artikel verwenden. Lassen Sie uns ein kleines en_core_web_sm-Modell einrichten, das sich hervorragend zur Demonstration der Möglichkeiten eignet. Um es in der Befehlszeile zu installieren, müssen Sie Folgendes eingeben:



python -m spacy download en_core_web_sm
      
      





Mit diesem Modell können wir für jedes der Token einen Teil der Sprache, eine Rolle in einem Satz und ein Token erhalten, von dem es abhängt:



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("New Apple MacBook set launch tomorrow")

for token in doc:
    token_text = token.text
    token_pos = token.pos_
    token_dep = token.dep_
    token_head = token.head.text
    print(f"{token_text:<12}{token_pos:<10}" \
          f"{token_dep:<10}{token_head:<12}")
      
      





New         PROPN     compound  MacBook     
Apple       PROPN     compound  MacBook     
MacBook     PROPN     nsubj     set         
set         VERB      ROOT      set         
to          PART      aux       launch      
launch      VERB      xcomp     set         
tomorrow    NOUN      npadvmod  launch 
      
      





Abhängigkeiten lassen sich bei weitem nicht erkennen, indem Sie nicht die Textdaten lesen, sondern einen Syntaxbaum erstellen. Die Displacy-Funktion kann dabei helfen. Sie müssen lediglich das Dokument übertragen:



from spacy import displacy
displacy.render(doc, style='dep', jupyter=True)
      
      





Als Ergebnis der Ausführung des Codes erhalten wir einen Baum, in dem sich alle syntaktischen Informationen zum Satz befinden:







Um die Tag-Namen zu entschlüsseln, können Sie die EXPLAIN-Funktionen verwenden:



print(spacy.explain("aux"))
print(spacy.explain("PROPN"))
auxiliary
proper noun
      
      





Hier werden die Abkürzungen auf dem Bildschirm angezeigt, aus denen hervorgeht, dass Aux für ein Hilfsteilchen (Auxiliary) und PROPN für ein Eigenname steht.



SpaCy implementiert auch die Fähigkeit, die Anfangsform eines Wortes für eines der Token herauszufinden (-PRON- wird für Pronomen verwendet):



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("I saw a movie yesterday")
print(' '.join([token.lemma_ for token in doc]))

'-PRON- see a movie yesterday'
      
      





3. Markieren Sie benannte Entitäten



Um mit Text arbeiten zu können, müssen Sie häufig die im Text erwähnten Entitäten hervorheben. Das Attribut doc.ents wird verwendet, um die benannten Entitäten im Dokument aufzulisten, und das Attribut ent.label_ wird verwendet, um die Bezeichnung für diese Entität abzurufen:



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("Apple is looking at buying U.K. startup for 1$ billion")
for ent in doc.ents:
    print(ent.text, ent.label_)


Apple ORG
U.K. GPE
1$ billion MONEY
      
      





Sie können hier auch das EXPLAIN-Attribut verwenden, um die Dekodierung benannter Entitätsbezeichnungen herauszufinden:



print(spacy.explain("GPE"))

      
      





Länder, Städte, Bundesstaaten

Und die Displacy-Funktion hilft Ihnen dabei, die Listen der Entitäten direkt im Text zu visualisieren:



aus Spacy-Import Displacy

Displacy.render (doc, style = 'ent', jupyter = True)







4. Erstellen Sie Ihre eigenen Vorlagen für die Textsuche



Das spaCy-Modul enthält ein sehr nützliches Tool, mit dem Sie Ihre eigenen Textsuchvorlagen erstellen können. Insbesondere können Sie nach Wörtern eines bestimmten Teils der Sprache suchen, alle Formen eines Wortes anhand seiner ursprünglichen Form, und nach der Art des Inhalts im Token suchen. Hier ist eine Liste der Hauptparameter:







Versuchen wir, eine eigene Vorlage zum Erkennen einer Folge von Token zu erstellen. Nehmen wir an, wir möchten aus den Textzeilen über die FIFA- oder ICC-Cricket-Weltmeisterschaften mit der Erwähnung des Jahres extrahieren:



import spacy
from spacy.matcher import Matcher

nlp = spacy.load("en_core_web_sm")
matcher = Matcher(nlp.vocab)
pattern = [
    {"IS_DIGIT": True}, 
    {"LOWER": {"REGEX": "(fifa|icc)"}},
    {"LOWER": "cricket", "OP": "?"},
    {"LOWER": "world"},
    {"LOWER": "cup"}
]
matcher.add("fifa_pattern", None, pattern)
doc = nlp("2018 ICC Cricket World Cup: Afghanistan won!")
matches = matcher(doc)
for match_id, start, end in matches:
    matched_span = doc[start:end]
    print(matched_span)
      
      





2018 ICC Cricket World Cup
      
      





In diesem Codeblock haben wir ein spezielles Matcher-Objekt importiert, um eine Reihe von benutzerdefinierten Vorlagen zu speichern. Nach der Initialisierung haben wir eine Vorlage erstellt, in der wir die Reihenfolge der Token angegeben haben. Beachten Sie, dass wir reguläre Ausdrücke verwendet haben, um zwischen ICC und FIFA zu wählen, und für das Cricket-Token einen Schlüssel, der das optionale Vorhandensein dieses Tokens anzeigt.



Nachdem Sie eine Vorlage erstellt haben, müssen Sie sie mithilfe der Funktion add zum Set hinzufügen und in den Parametern eine eindeutige Vorlagen-ID angeben. Die Suchergebnisse werden in Form einer Tupelliste angezeigt. Jedes der Tupel besteht aus der Übereinstimmungs-ID und den Start- und Endindizes des im Dokument gefundenen Slice.



5. Bestimmung der semantischen Nähe



Zwei Wörter können in ihrer Bedeutung sehr ähnlich sein, aber wie messen Sie ihre Nähe? Bei solchen Aufgaben können semantische Vektoren zur Rettung kommen. Wenn zwei Wörter oder ausführliche Ausdrücke ähnlich sind, liegen ihre Vektoren nahe beieinander.



Die Berechnung der semantischen Nähe von Vektoren in SpaCy ist nicht schwierig, wenn das Sprachmodell zur Lösung solcher Probleme trainiert wurde. Das Ergebnis hängt stark von der Größe des Modells ab. Nehmen wir für diese Aufgabe ein größeres Modell:



import spacy
      
      





nlp = spacy.load("en_core_web_md")
doc1 = nlp("I like burgers")
doc2 = nlp("I like pizza")
print(doc1.similarity(doc2))
      
      





0.9244169833828932
      
      





Der Wert kann zwischen null und eins liegen: Je näher an eins, desto größer die Ähnlichkeit. Im obigen Beispiel haben wir zwei Dokumente verglichen. Sie können jedoch einzelne Token und Slices auf dieselbe Weise vergleichen.



Die Bewertung der semantischen Nähe kann zur Lösung vieler Probleme hilfreich sein. Sie können damit beispielsweise ein Empfehlungssystem einrichten, das dem Benutzer ähnliche Texte basierend auf dem bietet, was er bereits gelesen hat.



Es ist wichtig, sich daran zu erinnern, dass die semantische Affinität sehr subjektiv ist und immer vom Kontext der Aufgabe abhängt. Zum Beispiel sind die Sätze „Ich liebe Hunde“ und „Ich hasse Hunde“ ähnlich, da beide Meinungen über Hunde äußern, sich aber gleichzeitig in der Stimmung stark unterscheiden. In einigen Fällen müssen Sie zusätzliche Sprachmodelle trainieren, damit die Ergebnisse mit dem Kontext Ihres Problems korrelieren.



6. Erstellen Sie Ihre eigenen Verarbeitungskomponenten



Das SpaCy-Modul unterstützt eine Reihe integrierter Komponenten (Tokenizer, Hervorhebung benannter Entitäten), ermöglicht Ihnen jedoch auch die Definition Ihrer eigenen Komponenten. Tatsächlich werden Komponenten nacheinander als Funktionen bezeichnet, die ein Dokument als Eingabe verwenden, ändern und zurücksenden. Neue Komponenten können mit dem Attribut add_pipe hinzugefügt werden:



import spacy

def length_component(doc):
    doc_length = len(doc)
    print(f"This document is {doc_length} tokens long.")
    return doc

nlp = spacy.load("en_core_web_sm")
nlp.add_pipe(length_component, first=True)
print(nlp.pipe_names)
doc = nlp("This is a sentence.")
      
      





['length_component', 'tagger', 'parser', 'ner']
This document is 5 tokens long.
      
      





Im obigen Beispiel haben wir eine eigene Funktion erstellt und hinzugefügt, die die Anzahl der Token im verarbeiteten Dokument anzeigt. Mit dem Attribut nlp.pipe_names haben wir die Ausführungsreihenfolge der Komponenten erhalten: Wie wir sehen können, ist die erstellte Komponente die erste in der Liste. Mit den folgenden Optionen können Sie angeben, wo eine neue Komponente hinzugefügt werden soll: Das







Hinzufügen benutzerdefinierter Komponenten ist ein sehr leistungsfähiges Tool zur Optimierung der Verarbeitung für Ihre Anforderungen.



7. Modelle trainieren und aktualisieren



Statistische Modelle machen Vorhersagen basierend auf den Beispielen, an denen sie trainiert wurden. In der Regel kann die Genauigkeit solcher Modelle verbessert werden, indem sie zusätzlich an für Ihre Aufgabe spezifischen Beispielen geschult werden. Zusätzliche Schulungen zu vorhandenen Modellen können sehr nützlich sein (z. B. zur Erkennung oder Analyse benannter Entitäten).



Zusätzliche Trainingsbeispiele können direkt in der SpaCy-Oberfläche hinzugefügt werden. Die Beispiele selbst sollten aus Textdaten und einer Liste von Beschriftungen für dieses Beispiel bestehen, auf denen das Modell trainiert.



Erwägen Sie zur Veranschaulichung, das Modell zu aktualisieren, um benannte Entitäten abzurufen. Um ein solches Modell zu aktualisieren, müssen Sie viele Beispiele übergeben, die Text, eine Angabe der Entitäten und ihrer Klasse enthalten. In den Beispielen müssen Sie ganze Klauseln verwenden, da das Modell beim Extrahieren von Entitäten stark vom Kontext der Klausel abhängt. Es ist sehr wichtig, das Modell vollständig zu trainieren, damit es Nicht-Entity-Token erkennen kann.



Zum Beispiel:



("What to expect at Apple's 10 November event", {"entities": [(18,23,"COMPANY")]})
("Is that apple pie I smell?", {"entities": []})
      
      





Im ersten Beispiel wird ein Unternehmen erwähnt: Für Schulungen markieren wir die Positionen, an denen sein Name beginnt und endet, und setzen dann unser Label, dass dieses Unternehmen ein Unternehmen ist. Im zweiten Beispiel sprechen wir von einer Frucht, daher gibt es keine Entitäten.



Die Daten für das Training des Modells werden normalerweise von Personen markiert. Diese Arbeit kann jedoch mithilfe der eigenen Suchvorlagen in SpaCy oder speziellen Markup-Programmen (z. B. Prodigy ) leicht automatisiert werden .



Nachdem die Beispiele vorbereitet wurden, können Sie direkt mit dem Training des Modells fortfahren. Damit das Modell effektiv trainieren kann, müssen Sie eine Reihe von mehreren Trainings durchführen. Mit jedem Training optimiert das Modell die Gewichte bestimmter Parameter. Die Modelle in SpaCy verwenden die stochastische Gradientenabstiegstechnik. Daher empfiehlt es sich, die Beispiele bei jedem Training zu mischen und sie auch in kleinen Portionen (Paketen) zu übertragen. Dies erhöht die Zuverlässigkeit der Gradientenschätzungen.







import spacy
import random
from spacy.lang.en import English

TRAINING_DATA = [
    ("What to expect at Apple's 10 November event", 
    {"entities": [(18,23,"COMPANY")]})
    #  ...
]

nlp = English()

for i in range(10):
    random.shuffle(TRAINING_DATA)
    for batch in spacy.util.minibatch(TRAINING_DATA):
        texts = [text for text, annotation in batch]
        annotations = [annotation for text, annotation in batch]
        nlp.update(texts, annotations)
        
nlp.to_disk("model")
      
      





Im obigen Beispiel bestand die Schleife aus 10 Trainings. Nach Abschluss der Schulung wurde das Modell auf der Festplatte im Modellordner gespeichert.



In Fällen, in denen nicht nur aktualisiert, sondern auch ein neues Modell erstellt werden muss, sind vor Beginn des Trainings eine Reihe von Vorgängen erforderlich.



Betrachten Sie den Prozess des Erstellens eines neuen Modells, um benannte Entitäten hervorzuheben:



nlp = spacy.blank("en")
ner = nlp.create_pipe("ner")
nlp.add_pipe(ner)
ner.add_label("COMPANY")
nlp.begin_training()
      
      





Zuerst erstellen wir ein leeres Modell mit der Funktion spacy.blank ("en"). Das Modell enthält nur Sprachdaten und Tokenisierungsregeln. Anschließend fügen wir eine ner-Komponente hinzu, die für das Hervorheben benannter Entitäten verantwortlich ist, und fügen mithilfe des Attributs add_label Beschriftungen für die Entitäten hinzu. Dann verwenden wir die Funktion nlp.begin_training (), um das Modell für das Training mit einer zufälligen Gewichtsverteilung zu initialisieren. Nun, dann reicht es aus, das Modell zu trainieren, wie im vorherigen Beispiel gezeigt.



All Articles