[PYTHON] 100 Sprachverarbeitungsklopfen 2020: Kapitel 4 (morphologische Analyse)

Sprachverarbeitung 100 Knock 2020 Version wurde veröffentlicht, daher habe ich diese Gelegenheit genutzt, um es zu lösen. Da es sich um eine Markdown-Ausgabe von Jupyter handelt, die auf GitHub veröffentlicht wurde, wird das einmal geladene Paket danach nicht mehr geladen. Ich hoffe, Sie können es als eine der Code-Referenzen verwenden.

Da ich ein Anfänger in der Verarbeitung natürlicher Sprache bin, möchte ich während des Studiums fortfahren und die Materialien und Inhalte aufzeichnen, auf die ich mich damals bezog.

Das erste Kapitel ist hier Das dritte Kapitel ist hier

Kapitel 4: Morphologische Analyse

Der Text von Soseki Natsumes Roman "Ich bin eine Katze" (neko.txt) wurde mit MeCab morphologisch analysiert und die Ergebnisse analysiert. Speichern Sie es in einer Datei namens neko.txt.mecab. Verwenden Sie diese Datei, um ein Programm zu implementieren, das die folgenden Fragen beantwortet. Verwenden Sie für die Probleme 37, 38 und 39 matplotlib oder Gnuplot.

Was ist morphologische Analyse? WikipediaAls,

Die morphologische Analyse reicht von Textdaten (Sätzen) in natürlicher Sprache ohne Anmerkungen zu grammatikalischen Informationen bis zu Informationen wie der Grammatik der Zielsprache und den Teiltexten von Wörtern, die als Wörterbücher bezeichnet werden. Ursprünglich ist es die Arbeit, morphologische Elemente in Spalten zu unterteilen (Morpheme, grob gesagt, die kleinste Einheit, die in der Sprache eine Bedeutung hat) und den Teil jedes morphologischen Elements zu unterscheiden.

MeCab-Prinzip

Blick hinter die Kulissen der japanischen morphologischen Analyse! Wie MeCab morphologisch analysiert.

Als einfaches Bild Geben Sie alle möglichen Teilungskandidaten für einen Satz an. Berechnen Sie die Auftrittskosten für jeden Knoten (Element) und die Verbindungskosten für die Teilwörter der Kante. Es scheint, dass der Pfad, der die kumulierten Kosten minimiert, durch die dynamische Planungsmethode berechnet wird. Unbekannte Wörter werden als Wörter für jeden Zeichentyp (z. B. Katakana) hinzugefügt, und die Kosten scheinen für jeden Zeichentyp bestimmt zu sein.

Diese Kosten werden übrigens bei der Installation von MeCab im Voraus ermittelt, aber durch CRF (Conditional Probability Field) modelliert und im Voraus berechnet. Der obige Artikel enthält eine ausführliche Erklärung, aber ich habe die empfohlenen Artikel unten zusammengefasst, um ein wenig mehr von den Grundlagen zu verstehen.

Über CNI

Eines der Merkmale ist, dass es sich um ein "Identifikationsmodell" handelt und "strukturelles Lernen" durchgeführt wird. Es ist ein alter Artikel, aber er basiert auf CRF-Geschichte in 30 Minuten für Leute, die CRF nicht verstehen und krank werden Es scheint gut zu sein, um die Umrisse zu verstehen, die die Grundlage bilden. Um es etwas genauer zu verstehen Dieser Artikel war gut. Für weitere mathematische Inhalte diese Folie War sehr leicht zu verstehen.

Das bedingte Zufallsfeld (Abkürzung: CRF) ist eines der probabilistischen grafischen Modelle, die durch ungerichtete Diagramme dargestellt werden, und ist ein Diskriminanzmodell. (Wikipedia)

CRF ist ein charakteristisch trainiertes stochastisches Markov-Feld (eine Reihe von Markov-Wahrscheinlichkeitsvariablen). (Das Markov-Wahrscheinlichkeitsfeld ist ein ungerichteter Graph.)

P({\bf S}|{\bf O})=\frac{1}{Z_o} \exp \left(\sum_{t=1}^{T} \sum_{k=1}^K \lambda_k f_k(s_{t-1},s_t,{\bf o},t)\right)
Z_o=\sum_{s \in {\bf S}} \exp \left(\sum_{t=1}^{T} \sum_{k=1}^K \lambda_k f_k(s_{t-1},s_t,{\bf o},t)\right)

Hier ist fk eine Veranlagungsfunktion und besteht aus einer Übergangsveranlagung und einer Beobachtungsveranlagung. λ ist das Gewicht und die Kosten werden basierend auf diesem Wert berechnet. Da CRF auf dem stochastischen Markov-Feld aufgebaut ist, besteht die Übergangsveranlagung nur aus dem vorherigen Zustand und dem aktuellen Zustand. Die Auftrittskosten von MeCab werden unter Verwendung der zur beobachteten Veranlagung gehörenden Veranlagungsfunktion berechnet, und die Verkettungskosten werden unter Verwendung der zur Übergangsreanimation gehörenden Veranlagungsfunktion berechnet. Da sich das Übergangselement in MeCab nur mit dem Teil des Sprachzustands befasst, scheinen die Verbindungskosten nur die Teil-der-Sprache-Informationen zu berücksichtigen.

Vorverarbeitung

Bevor Sie mit der Lösung des Problems beginnen, importieren Sie matplotlib und führen Sie eine morphologische Analyse mit MeCab durch. MeCab verwendet das von Homebrew installierte.

mecab < ../data/neko.txt > ../data/neko.txt.mecab
import matplotlib.pyplot as plt

30. Lesen der Ergebnisse der morphologischen Analyse

Implementieren Sie ein Programm, das die Ergebnisse der morphologischen Analyse liest (neko.txt.mecab). Jedes morphologische Element wird jedoch in einem Zuordnungstyp mit der Oberfläche, der Grundform (Basis), einem Teil des Wortes (pos) und einem Teil der Wortunterklassifizierung 1 (pos1) als Schlüssel gespeichert, und ein Satz wird als Liste morphologischer Elemente (Zuordnungstyp) ausgedrückt. Machen wir das. Verwenden Sie für die restlichen Probleme in Kapitel 4 das hier erstellte Programm.

Der Zuordnungstyp, in dem jedes Formularelement gespeichert ist, ist "{" Oberfläche ":" de "," Basis ":" da "," pos ":" Hilfsverb "," pos1 ":" * "}".

fname = '../data/neko.txt.mecab'

def read_mecab(fname):
    with open(fname, mode='rt', encoding='utf-8') as f:
        #EOS-Entfernung Listen Sie beim Entfernen die Speicherung Satz für Satz auf
        sentence_list = f.read().split('EOS\n')
        sentence_list = list(filter(lambda x: x != '', sentence_list))
    result_list = []
    for sentence in sentence_list:
        morpheme_list = []
        for word in sentence.split('\n'):
            if word != '':
                (surface, attr) = word.split('\t')
                attr = attr.split(',')
                component_dict = {
                    'surface': surface,
                    'base': attr[6],
                    'pos': attr[0],
                    'pos1': attr[1]
                }
                morpheme_list.append(component_dict)
        result_list.append(morpheme_list)
    return result_list

neko_morpheme = read_mecab(fname)
print(neko_morpheme[:4])

[[{'Oberfläche': 'Eins', 'Basis': 'Eins', 'Pos': 'Nomen', 'Pos1': 'Zahl'}], [{'Oberfläche': '\ u3000', 'Basis' ':' \ u3000 ',' pos ':' symbol ',' pos1 ':' blank '}, {' surface ':' my ',' base ':' my ',' pos ':' noun ',' pos1 ':' Synonyme '}, {' Oberfläche ':' ist ',' Basis ':' ist ',' pos ':' Hilfs ',' pos1 ':' Teilnehmer '}, {' Oberfläche ':' Katze ',' base ':' cat ',' pos ':' noun ',' pos1 ':' general '}, {' surface ':' at ',' base ':' da ',' pos ':' auxiliary verb ',' pos1 ':' * '}, {' Oberfläche ':' Sind ',' Basis ':' Sind ',' Pos ':' Hilfsverb ',' Pos1 ':' * '}, {' Oberfläche ': '. ',' base ':'. ',' pos ':' symbol ',' pos1 ':' Interpunktion '}], [{' Oberfläche ':' Name ',' Basis ':' Name ',' pos ':' Nomenklatur ',' pos1 ': 'Allgemein'}, {'Oberfläche': 'ist', 'Basis': 'ist', 'pos': 'Hilfs', 'pos1': 'Teilnehmer'}, {'Oberfläche': 'noch', ' Basis ':' noch ',' pos ':' Zusatz ',' pos1 ':' Hilfsverbindung '}, {' Oberfläche ':' nicht ',' Basis ':' nicht ',' pos ':' Adjektiv ' , 'pos1': 'Independence'}, {'Oberfläche': '. ',' base ':'. ',' pos ':' symbol ',' pos1 ':' Interpunktion '}], [{' Oberfläche ':' \ u3000 ',' Basis ':' \ u3000 ',' pos ':' Symbol ',' pos1 ':' Leer '}, {' Oberfläche ':' Wo ',' Basis ':' Wo ',' Pos ':' Nomenklatur ',' Pos1 ':' Synonyme '}, {' Oberfläche ':' De ',', 'Basis': 'de', 'pos': 'Hilfs', 'pos1': 'Fallassistent'}, {'Oberfläche': 'geboren', 'Basis': 'geboren', 'pos': 'Verb ',' pos1 ':' Unabhängigkeit '}, {' Oberfläche ':' ta ',' Basis ':' ta ',' pos ':' Hilfsverb ',' pos1 ':' * '}, {' Oberfläche ': 'Ka', 'Basis': 'Ka', 'Pos': 'Auxiliary', 'Pos1': 'Subaddition / Parallel Assistant / Final Auxiliary'}, {'Oberfläche': 'Tonto', 'Base': ' Tonto ',' pos ':' adjunct ',' pos1 ':' general '}, {' surface ':' register ',' base ':' register ',' pos ':' noun ',' pos1 ':' Sahen-Verbindung '}, {' Oberfläche ':' ist ',' Basis ':' ist ',' pos ':' Hilfs ',' pos1 ':' Fallhilfsmittel '}, {' Oberfläche ':' Tsuka ',' Basis ':' Tsuku ',' Pos ':' Verb ',' Pos1 ':' Unabhängigkeit '}, {' Oberfläche ':' Nu ',' Basis ':' Nu ',' Pos ':' Hilfsverb ',' pos1 ':' * '}, {' Oberfläche ':'. ',' base ':'. ',' pos ':' symbol ',' pos1 ':' Interpunktion '}]]

31. Verb

Extrahieren Sie alle Oberflächensysteme von Verben.

pos extrahiert die Oberfläche des Verbs. Vorerst musste ich nur die Verben extrahieren, also habe ich die Liste für jeden Satz einmal abgeflacht und verarbeitet. Die Ausgabe ist eine Liste, aber wenn Sie keine doppelten Elemente benötigen, können Sie sie auf set setzen. Mach einfach set (verbose_list).

from itertools import chain

def extract_verbose(target):
    flatten_list = list(chain.from_iterable(target))
    return [word['surface'] for word in flatten_list if word['pos'] == 'Verb']
    
verbose_list = extract_verbose(neko_morpheme)
print(verbose_list[:10])

['Geburt', 'Tsuka', 'Shi', 'Weinen', 'Shi', 'Ich', 'Anfang', 'Sehen', 'Hören', 'Erfassen']

32. Prototyp des Verbs

Extrahieren Sie alle Originalformen des Verbs

def extract_verb_base(target):
    flatten_list = list(chain.from_iterable(target))
    return [word['base'] for word in flatten_list if word['pos'] == 'Verb']

verb_base_list = extract_verb_base(neko_morpheme)
print(verb_base_list[:10])

['Geburt', 'Tsuku', 'Do', 'Cry', 'Do', 'I', 'Start', 'See', 'Listen', 'Catch']

33. "B von A"

Extrahieren Sie die Nomenklatur, in der zwei Nomenklaturen durch "Nein" verbunden sind.

Sie müssen jeden Satz verarbeiten. Fügen Sie die verkettete Nomenklatur als Wörterbuch der Form {A: B} zur Liste hinzu.

def extract_connected_by_of(target):
    result_list = []
    for dict in target:
        for i in range(1, len(dict)-1):
            if dict[i-1]['pos'] == 'Substantiv' and dict[i]['base'] == 'von' and dict[i+1]['pos'] == 'Substantiv':
                result_list.append({dict[i-1]['surface']: dict[i+1]['surface']})
    return result_list

a_of_b_list = extract_connected_by_of(neko_morpheme)
print(a_of_b_list[:10])

[{'He': 'Palm'}, {'Palm': 'Upper'}, {'Shosei': 'Face'}, {'Should': 'Face'}, {'Face': 'Middle'} , {'Hole': 'Middle'}, {'Shosei': 'Palm'}, {'Palm': 'Back'}, {'What': 'Thing'}, {'Important': 'Mother'} ]]

34. Verkettung der Nomenklatur

Extrahieren Sie die Verkettung der Nomenklatur (Substantive, die nacheinander erscheinen) mit der längsten Übereinstimmung.

Solange die Nomenklatur verbunden ist, müssen alle Nomenklaturen zum Ergebnis hinzugefügt werden.

def extract_chain_noun(target_list):
    result_list = []
    temp_list = []
    for d in target_list:
        for word in d:  
            if word['pos'] == 'Substantiv':
                temp_list.append(word['surface'])
            elif len(temp_list) > 1 :
                result_list.append(temp_list)
                temp_list = []
            else:
                temp_list = []
    return result_list

chain_noun_list = extract_chain_noun(neko_morpheme)

for i in chain_noun_list[:10]:
    print(i)

['Mensch', 'Mittel'] ['Ichiban', 'Evil'] ['Zeit', 'Geheimnisvoll'] ['Eins', 'Haar'] ['Nach', 'Katze'] ['einmal'] ['Puuputo', 'Rauch'] ['Haus', 'Innen'] ['Drei', 'Haare'] ['Shosei', außer ']

35. Häufigkeit des Auftretens von Wörtern

Suchen Sie die im Satz vorkommenden Wörter und ihre Häufigkeit des Auftretens und ordnen Sie sie in absteigender Reihenfolge der Häufigkeit des Auftretens an.

Verwenden Sie den "Zähler" der Standard-Python-Bibliothekssammlungen, um eine Liste der Wörter und Vorkommen von Tapples zu erhalten.

#from itertools import chain
from collections import Counter

def extract_word_frequency(target):
    flatten_list = list(chain.from_iterable(target))
    word_list = [word['surface'] for word in flatten_list]
    counted_list = Counter(word_list).most_common()
    return counted_list

word_counted_list = extract_word_frequency(neko_morpheme)
word, counts = zip(*word_counted_list)
print(word[:20])

('', '.', 'Te', ',', 'ist', 'zu', 'zu', 'und', 'ist', ' "',' Auch ',' nicht ',' da ',' shi ',' von ',' sind ',' na ')

36. Top 10 der häufigsten Wörter

Zeigen Sie die 10 am häufigsten vorkommenden Wörter und ihre Häufigkeit des Auftretens in einem Diagramm an (z. B. einem Balkendiagramm).

# import matplotlib.pyplot as plt
import japanize_matplotlib

plt.figure(figsize=(12, 8))
plt.barh(word[:10], counts[:10])
plt.title('Top 10 Wörter nach Häufigkeit')
plt.xlabel('Anzahl der Auftritte')
plt.ylabel('Wort')
plt.show()

output_15_0.png

37. Top 10 Wörter, die häufig zusammen mit "Katze" vorkommen

Zeigen Sie 10 Wörter an, die häufig zusammen mit "cat" (hohe Häufigkeit des gemeinsamen Auftretens) und deren Häufigkeit des Auftretens in einem Diagramm (z. B. einem Balkendiagramm) vorkommen.

Zuerst müssen wir darüber nachdenken, wie die Häufigkeit des gemeinsamen Auftretens definiert werden soll, aber hier haben wir es so interpretiert, dass Wörter extrahiert werden, die im selben Satz vorkommen.

Dies erfolgt in 3 Schritten.

def extract_cooccurrence_list(target):
    cooccurrence_list = []
    for sentence in target:
        #Wenn die Oberfläche Katzen enthält, fügen Sie diese der Liste hinzu.
        word_list = [word['surface'] for word in sentence]
        if "Katze" in word_list:
            cooccurrence_list.extend([word for word in word_list if word != "Katze"])
    return cooccurrence_list

def caluculate_word_frequence(target):
    counted_list = Counter(target).most_common()
    word, counts = zip(*counted_list)
    return word, counts


def main():
    cat_frequence_list = extract_cooccurrence_list(neko_morpheme)
    neko_word, neko_count = caluculate_word_frequence(cat_frequence_list)
    plt.figure(figsize=(12, 8))
    plt.barh(neko_word[:10], neko_count[:10])
    plt.title('Top 10 Wörter, die häufig zusammen mit Katzen vorkommen')
    plt.xlabel('Anzahl der Auftritte')
    plt.ylabel('Wort')
    plt.show()

if __name__ == '__main__':
    main()

output_17_0.png

38. Histogramm

Zeichnen Sie ein Histogramm der Häufigkeit des Auftretens von Wörtern (die horizontale Achse repräsentiert die Häufigkeit des Auftretens und die vertikale Achse repräsentiert die Anzahl der Arten von Wörtern, die die Häufigkeit des Auftretens als Balkendiagramm verwenden).

Verwenden Sie die in 35 berechnete Zählliste. Wenn Sie später so darauf verweisen, sollten Sie ihm einen etwas besseren Namen geben. Dieses Mal haben wir bis zu 100 Erscheinungsfrequenzen aufgezeichnet.

plt.figure(figsize = (12,8))
plt.hist(counts, bins=20, range=(1,100))
plt.show()

output_19_0.png

39. Zipfs Gesetz

Zeichnen Sie beide logarithmischen Diagramme mit der Häufigkeit des Auftretens von Wörtern auf der horizontalen Achse und der Häufigkeit des Auftretens auf der vertikalen Achse.

Die in 35 erfasste Zählliste ist nach Rang geordnet.

#Erstellen Sie eine Liste mit Erscheinungsrankings
rank_list = [i+1 for i in range(len(counts))]

plt.figure(figsize = (12,8))
plt.scatter(rank_list, counts)
plt.xscale('log')
plt.yscale('log')
plt.grid(which='major',color='black')

plt.show()

output_21_0.png

Recommended Posts

100 Sprachverarbeitungsklopfen 2020: Kapitel 4 (morphologische Analyse)
[Sprachverarbeitung 100 Schläge 2020] Kapitel 4: Morphologische Analyse
Sprachverarbeitung 100 Schläge Kapitel 4: Morphologische Analyse 31. Verben
100 Sprachverarbeitung klopft Morphologische Analyse in Kapitel 4 gelernt
100 Sprachverarbeitung Knock 2020 Kapitel 4: Morphologische Analyse
[Sprachverarbeitung 100 Schläge 2020] Kapitel 5: Abhängigkeitsanalyse
100 Sprachverarbeitung Knock Kapitel 4: Morphologische Analyse
100 Language Processing Knock 2015 Kapitel 4 Morphologische Analyse (30-39)
100 natürliche Sprachverarbeitung klopft Kapitel 4 Morphologische Analyse (zweite Hälfte)
100 Sprachverarbeitungsklopfen ~ Kapitel 1
100 Sprachverarbeitung klopft Kapitel 2 (10 ~ 19)
Verarbeitung natürlicher Sprache 1 Morphologische Analyse
100 Sprachverarbeitungsklopfen 03 ~ 05
100 Sprachverarbeitungsklopfen (2020): 32
100 Sprachverarbeitung Knock 2015 Kapitel 5 Abhängigkeitsanalyse (40-49)
100 Sprachverarbeitungsklopfen (2020): 35
[Sprachverarbeitung 100 Schläge 2020] Kapitel 3: Reguläre Ausdrücke
100 Sprachverarbeitungsklopfen (2020): 47
100 Sprachverarbeitungsklopfen (2020): 39
100 Klicks in der Verarbeitung natürlicher Sprache Kapitel 4 Kommentar
[Sprachverarbeitung 100 Schläge 2020] Kapitel 6: Maschinelles Lernen
100 Sprachverarbeitungsklopfen (2020): 22
100 Sprachverarbeitungsklopfen (2020): 26
100 Sprachverarbeitungsklopfen (2020): 34
100 Sprachverarbeitungsklopfen (2020): 42
100 Sprachverarbeitungsklopfen (2020): 29
100 Sprachverarbeitungsklopfen (2020): 49
100 Sprachverarbeitungsklopfen 06 ~ 09
100 Sprachverarbeitungsklopfen (2020): 43
100 Sprachverarbeitungsklopfen (2020): 24
[Sprachverarbeitung 100 Schläge 2020] Kapitel 1: Vorbereitende Bewegung
100 Sprachverarbeitungsklopfen (2020): 45
100 Sprachverarbeitungsklopfen (2020): 10-19
[Sprachverarbeitung 100 Schläge 2020] Kapitel 7: Wortvektor
100 Sprachverarbeitungsklopfen (2020): 30
100 Sprachverarbeitung Knock 2020 Kapitel 5: Abhängigkeitsanalyse
100 Sprachverarbeitungsklopfen (2020): 00-09
100 Sprachverarbeitung klopfen 2020: Kapitel 3 (regulärer Ausdruck)
100 Sprachverarbeitungsklopfen (2020): 31
[Sprachverarbeitung 100 Schläge 2020] Kapitel 8: Neuronales Netz
100 Sprachverarbeitungsklopfen (2020): 48
[Sprachverarbeitung 100 Schläge 2020] Kapitel 2: UNIX-Befehle
100 Sprachverarbeitungsklopfen (2020): 44
100 Sprachverarbeitungsklopfen (2020): 41
100 Sprachverarbeitungsklopfen (2020): 37
[Sprachverarbeitung 100 Schläge 2020] Kapitel 9: RNN, CNN
100 Sprachverarbeitungsklopfen (2020): 25
100 Sprachverarbeitungsklopfen (2020): 23
100 Sprachverarbeitungsklopfen (2020): 33
100 Sprachverarbeitungsklopfen (2020): 20
100 Sprachverarbeitungsklopfen (2020): 27
100 natürliche Sprachverarbeitung klopft Kapitel 5 Abhängigkeitsanalyse (zweite Hälfte)
100 Sprachverarbeitungsklopfen (2020): 46
100 Sprachverarbeitungsklopfen (2020): 21
100 natürliche Sprachverarbeitung klopft Kapitel 5 Abhängigkeitsanalyse (erste Hälfte)
100 Sprachverarbeitungsklopfen (2020): 36
100 Amateur-Sprachverarbeitungsklopfen: 41
100 Amateur-Sprachverarbeitungsklopfen: 71
100 Amateur-Sprachverarbeitungsklopfen: 56
100 Amateur-Sprachverarbeitungsklopfen: 24
100 Amateur-Sprachverarbeitungsklopfen: 50