[PYTHON] 100 natürliche Sprachverarbeitung klopft Kapitel 5 Abhängigkeitsanalyse (zweite Hälfte)

Eine Aufzeichnung zur Lösung der Probleme in der zweiten Hälfte von Kapitel 5. Die Zieldatei ist neko.txt, wie auf der Webseite gezeigt.

Verwenden Sie CaboCha, um den Text (neko.txt) von Natsume Sosekis Roman "Ich bin eine Katze" abhängig zu machen und zu analysieren, und speichern Sie das Ergebnis in einer Datei namens neko.txt.cabocha. Verwenden Sie diese Datei, um ein Programm zu implementieren, das die folgenden Fragen beantwortet.

</ i> 45. Extraktion von Verbfallmustern

Ich möchte den diesmal verwendeten Satz als Korpus betrachten und die möglichen Fälle japanischer Prädikate untersuchen. Stellen Sie sich das Verb als Prädikat und das Hilfsverb der Phrase, die sich auf das Verb bezieht, als Fall vor und geben Sie das Prädikat und den Fall in einem durch Tabulatoren getrennten Format aus. Stellen Sie jedoch sicher, dass die Ausgabe den folgenden Spezifikationen entspricht. In einer Phrase, die ein Verb enthält, wird die Grundform des Verbs ganz links als Prädikat verwendet.

  • Der Fall ist das Hilfswort, das sich auf das Prädikat bezieht
  • Wenn das Prädikat mehrere Hilfswörter (Phrasen) enthält, ordnen Sie alle Hilfswörter in Wörterbuchreihenfolge an, die durch Leerzeichen getrennt sind. Speichern Sie die Ausgabe dieses Programms in einer Datei und überprüfen Sie die folgenden Elemente mit UNIX-Befehlen. Eine Kombination von Prädikaten und Fallmustern, die häufig im Korpus vorkommen Fallmuster der Verben "do", "see" und "give" (in der Reihenfolge der Häufigkeit des Auftretens im Korpus anordnen)
# -*- coding: utf-8 -*-
__author__ = 'todoroki'

import problem41


def extractVerbPatern(sentence):
    lst = []
    for chunk in sentence:
        if chunk.include_pos('Verb'):
            src_chunks = [sentence[src] for src in chunk.srcs]
            src_chunks_case = list(filter(lambda src_chunks: src_chunks.morphs_of_pos1('Fallassistent'), src_chunks))
            if src_chunks_case:
                lst.append((chunk, src_chunks_case))
    return lst


if __name__ == "__main__":
    f = open("neko.txt.cabocha", "r")
    sentences = problem41.read_chunk(f)
    verbPatterns = []
    for sentence in sentences:
        verbPatterns.append(extractVerbPatern(sentence))

    for verbPattern in verbPatterns:
        for verb, src_chunks in verbPattern:
            v = verb.morphs_of_pos('Verb')[-1].base
            ps = [src_chunk.morphs_of_pos1('Fallassistent')[-1].base for src_chunk in src_chunks]
            p = " ".join(sorted(ps))
            print "%s\t%s" % (v, p)
    f.close()

Der folgende Befehl sortiert die Ergebnisse des obigen Programms in der Reihenfolge ihrer Erscheinungshäufigkeit und gibt sie aus. Verarbeitung von oben für alle Verben "do", "see" und "give".

python problem45.py | sort | uniq -c | sort -nr
python problem45.py | sort | awk '$1=="Machen"{print $0}' | uniq -c | sort -nr
python problem45.py | sort | awk '$1=="sehen"{print $0}' | uniq -c | sort -nr
python problem45.py | sort | awk '$1=="geben"{print $0}' | uniq -c | sort -nr

</ i> 46. Extraktion von Informationen zum Verbfall

Ändern Sie das Programm> 45 und geben Sie die Begriffe (die Klauseln, die sich auf die Prädikate selbst beziehen) in tabulatorgetrennten Formaten aus, wobei Sie den Prädikaten und Fallmustern folgen. Erfüllen Sie zusätzlich zu den 45 Spezifikationen die folgenden Spezifikationen.

  • Der Begriff ist eine Wortfolge der Klausel, die sich auf das Prädikat bezieht (es ist nicht erforderlich, das nachfolgende Hilfswort zu entfernen).
  • Wenn es mehrere Klauseln gibt, die sich auf das Prädikat beziehen, ordnen Sie sie in derselben Norm und Reihenfolge wie die durch Leerzeichen getrennten Hilfswörter an.
# -*- coding: utf-8 -*-
__author__ = 'todoroki'

import problem41
import problem45

if __name__ == "__main__":
    f = open("neko.txt.cabocha", "r")
    sentences = problem41.read_chunk(f)
    f.close()
    verbPatterns = []
    for sentence in sentences:
        verbPatterns.append(problem45.extractVerbPatern(sentence))

    for verbPattern in verbPatterns:
        for verb, src_chunks in verbPattern:
            col1 = verb.morphs_of_pos('Verb')[-1].base
            tmp = [(src_chunk.morphs_of_pos1('Fallassistent')[-1].base, str(src_chunk)) for src_chunk in src_chunks]
            tmp = sorted(tmp, key=lambda x:x[0])
            col2 = " ".join([col[0] for col in tmp])
            col3 = " ".join([col[1] for col in tmp])
            print "%s\t%s\t%s" % (col1, col2, col3)

</ i> 47. Funktionelles Verbsyntax-Mining

Ich möchte nur dann aufpassen, wenn das Verb wo case ein sa-varianten-Verbindungsnomen enthält. Ändern Sie 46 Programme, um die folgenden Spezifikationen zu erfüllen. ――Nur wenn die Phrase, die aus "Sahen-Verbindungsnomen + (Hilfsverb)" besteht, mit dem Verb zusammenhängt

  • Das Prädikat lautet "Sahen-Verbindungsnomen + ist die Grundform von + Verb". Wenn die Phrase mehrere Verben enthält, verwenden Sie das Verb ganz links.
  • Wenn das Prädikat mehrere Hilfswörter (Phrasen) enthält, ordnen Sie alle Hilfswörter in Wörterbuchreihenfolge an, die durch Leerzeichen getrennt sind.
  • Wenn das Prädikat mehrere Klauseln enthält, ordnen Sie alle durch Leerzeichen getrennten Begriffe an (richten Sie sie nach der Reihenfolge der Hilfswörter aus).

Speichern Sie die Ausgabe dieses Programms in einer Datei und überprüfen Sie die folgenden Elemente mit UNIX-Befehlen. --Predikate, die häufig im Korpus vorkommen (Sahen-Verbindungsnomenklatur + + Verb) --Predikate und Verbmuster, die häufig im Korpus vorkommen

# -*- coding: utf-8 -*-
__author__ = 'todoroki'

import problem41
import problem45

def extractSahen(src_chunks):
    for i, src_chunk in enumerate(src_chunks):
        morphs = src_chunk.morphs
        if len(morphs) > 1:
            if morphs[-2].pos1 == "Verbindung ändern" and morphs[-1].pos == "Partikel" and morphs[-1].base == "Zu":
                src_chunks.pop(i)
                return src_chunk, src_chunks
    return None

if __name__ == "__main__":
    f = open("neko.txt.cabocha", "r")
    sentences = problem41.read_chunk(f)
    f.close()
    verbPatterns = []
    for sentence in sentences:
        verbPatterns.append(problem45.extractVerbPatern(sentence))

    for verbPattern in verbPatterns:
        for verb, src_chunks in verbPattern:
            sahen_chunks_set = extractSahen(src_chunks)
            if sahen_chunks_set:
                sahen_chunk, other_chunks = sahen_chunks_set
                col1 = str(sahen_chunk) + verb.morphs_of_pos('Verb')[-1].base
                tmp = [(other_chunk.morphs_of_pos1('Fallassistent')[-1].base, str(other_chunk)) for other_chunk in other_chunks]
                tmp = sorted(tmp, key=lambda x: x[0])
                col2 = " ".join([col[0] for col in tmp])
                col3 = " ".join([col[1] for col in tmp])
                print "%s\t%s\t%s" % (col1, col2, col3)

Ein Befehl, der Prädikate ausgibt, die häufig im Korpus vorkommen (sa-variante Verbindungsnomenklatur + + Verb).

python problem47.py | cut -f 1 | sort | uniq -c | sort -nr

Ein Befehl, der Prädikate und Verbmuster ausgibt, die häufig im Korpus vorkommen.

python problem47.py | cut -f 1,2 | sort | uniq -c | sort -nr

</ i> 48. Extrahieren von Pfaden von der Nomenklatur zu den Wurzeln

Extrahieren Sie für eine Klausel, die die gesamte Nomenklatur des Satzes enthält, den Pfad von dieser Klausel zur Wurzel des Syntaxbaums. Der Pfad im Syntaxbaum muss jedoch die folgenden Spezifikationen erfüllen.

  • Jede Klausel wird durch eine morphologische Sequenz (der Oberflächenschicht) dargestellt.
  • Verketten Sie die Ausdrücke jeder Klausel mit "->" von der Startklausel bis zur Endklausel des Pfads.
# -*- coding: utf-8 -*-
__author__ = 'todoroki'

import problem41

def extractPath(chunk, sentence):
    path = [chunk]
    dst = chunk.dst
    while dst != -1:
        path.append(sentence[dst])
        dst = sentence[dst].dst
    return path

if __name__ == "__main__":
    f = open("neko.txt.cabocha", "r")
    sentences = problem41.read_chunk(f)
    f.close()
    paths = []
    for sentence in sentences:
        for chunk in sentence:
            if chunk.include_pos('Substantiv') and chunk.dst != -1:
                paths.append(extractPath(chunk, sentence))

    for path in paths:
        print " -> ".join([str(chunk) for chunk in path])

</ i> 49. Extraktion von Abhängigkeitspfaden zwischen Nomenklaturen

Extrahieren Sie den kürzesten Abhängigkeitspfad, der alle Nomenklaturpaare im Satz verbindet. Wenn jedoch die Klauselnummern des Nomenklaturpaars i und j sind (i <j), muss der Abhängigkeitspfad die folgenden Spezifikationen erfüllen.

  • Ähnlich wie bei Problem 48 wird der Pfad ausgedrückt, indem die Ausdrücke (oberflächenmorphologische Elemente) jeder Phrase von der Startklausel bis zur Endklausel mit "->" verkettet werden.
  • Ersetzen Sie die in den Abschnitten i und j enthaltene Nomenklatur durch X bzw. Y.

Darüber hinaus kann die Form des Abhängigkeitspfads auf zwei Arten betrachtet werden. --Wenn Klausel j auf dem Pfad von Klausel i zum Stammverzeichnis des Syntaxbaums vorhanden ist: Zeigen Sie den Pfad von Klausel i zu Klausel j an

  • Anders als oben, wenn sich Klausel i und Klausel j an einer gemeinsamen Klausel k auf dem Pfad von Klausel j zur Wurzel des Syntaxbaums überschneiden: der Pfad unmittelbar vor Klausel i zu Klausel k und der Pfad unmittelbar vor Klausel j zu Klausel k, Klausel Zeigen Sie den Inhalt von k an, indem Sie ihn mit "|" verketten.
# -*- coding: utf-8 -*-
__author__ = 'todoroki'

from collections import namedtuple
from itertools import combinations
import problem41

def extractPathIndex(i_chunk, sentence):
    i, chunk = i_chunk
    path_index = [i]
    dst = chunk.dst
    while dst != -1:
        path_index.append(dst)
        dst = sentence[dst].dst
    return path_index

def posReplace(chunks, pos, repl, k=1):
    replaced_str = ""
    for morph in chunks[0].morphs:
        if morph.pos == pos and k > 0:
            replaced_str += repl
            k -= 1
        else:
            if morph.pos != 'Symbol':
                replaced_str += morph.surface
    return [replaced_str] + [str(chunk) for chunk in chunks[1:]]


if __name__ == "__main__":
    f = open("neko.txt.cabocha", "r")
    sentences = problem41.read_chunk(f)
    f.close()
    paths = []
    N2Npath = namedtuple('N2Npath', ['X', 'Y', 'is_linear'])
    for sentence in sentences:
        noun_chunks = [(i, chunk) for i, chunk in enumerate(sentence) if chunk.include_pos('Substantiv')]
        if len(noun_chunks) > 1:
            for former, latter in combinations(noun_chunks, 2):
                f_index = extractPathIndex(former, sentence)
                l_index = extractPathIndex(latter, sentence)
                f_i, l_i = list(zip(reversed(f_index), reversed(l_index)))[-1]
                linear_flag = (f_i == l_i)
                if linear_flag:
                    f_index2 = f_index[:f_index.index(f_i)+1]
                    l_index2 = l_index[:l_index.index(l_i)+1]
                else:
                    f_index2 = f_index[:f_index.index(f_i)+2]
                    l_index2 = l_index[:l_index.index(l_i)+2]
                X = [sentence[k] for k in f_index2]
                Y = [sentence[k] for k in l_index2]
                paths.append(N2Npath(X=X, Y=Y, is_linear=linear_flag))

    for path in paths:
        x = posReplace(path.X, "Substantiv", "X")
        y = posReplace(path.Y, "Substantiv", "Y")
        if path.is_linear:
            x[-1] = "Y"
            print " -> ".join(x)
        else:
            print "%s | %s | %s" % (" -> ".join(x[:-1]), " -> ".join(y[:-1]), path.X[-1])

Recommended Posts