[PYTHON] Le traitement du langage naturel à 100 coups

Un enregistrement de la résolution des problèmes dans la seconde moitié du chapitre 5. Le fichier cible est neko.txt comme indiqué sur la page Web.

Utilisez CaboCha pour intercepter et analyser le texte (neko.txt) du roman de Natsume Soseki "Je suis un chat" et enregistrer le résultat dans un fichier appelé neko.txt.cabocha. Utilisez ce fichier pour implémenter un programme qui répond aux questions suivantes.

</ i> 45. Extraction de modèles de casse verbale

Je voudrais considérer la phrase utilisée cette fois comme un corpus et enquêter sur les cas possibles de prédicats japonais. Considérez le verbe comme un prédicat et le verbe auxiliaire de la phrase liée au verbe comme une casse, et affichez le prédicat et la casse dans un format délimité par des tabulations. Cependant, assurez-vous que la sortie répond aux spécifications suivantes. Dans une phrase contenant un verbe, la forme de base du verbe le plus à gauche est utilisée comme prédicat. --La casse est le mot auxiliaire lié au prédicat --S'il y a plusieurs mots auxiliaires (phrases) liés au prédicat, arrangez tous les mots auxiliaires dans l'ordre du dictionnaire, séparés par des espaces. Enregistrez la sortie de ce programme dans un fichier et vérifiez les éléments suivants à l'aide des commandes UNIX. Une combinaison de prédicats et de modèles de cas qui apparaissent fréquemment dans le corpus Modèles de casse des verbes "faire", "voir" et "donner" (organiser par ordre de fréquence d'apparition dans le corpus)

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

import problem41


def extractVerbPatern(sentence):
    lst = []
    for chunk in sentence:
        if chunk.include_pos('verbe'):
            src_chunks = [sentence[src] for src in chunk.srcs]
            src_chunks_case = list(filter(lambda src_chunks: src_chunks.morphs_of_pos1('Assistant de cas'), 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('verbe')[-1].base
            ps = [src_chunk.morphs_of_pos1('Assistant de cas')[-1].base for src_chunk in src_chunks]
            p = " ".join(sorted(ps))
            print "%s\t%s" % (v, p)
    f.close()

La commande suivante trie les résultats du programme ci-dessus par ordre de fréquence d'apparition et les sort. Depuis le haut, traitement pour tous les verbes, "faire", "voir" et "donner".

python problem45.py | sort | uniq -c | sort -nr
python problem45.py | sort | awk '$1=="Faire"{print $0}' | uniq -c | sort -nr
python problem45.py | sort | awk '$1=="à voir"{print $0}' | uniq -c | sort -nr
python problem45.py | sort | awk '$1=="donner"{print $0}' | uniq -c | sort -nr

</ i> 46. Extraction des informations sur le cadre de la casse verbale

Modifiez le programme> 45 et affichez les termes (les clauses liées aux prédicats eux-mêmes) au format délimité par des tabulations en suivant les prédicats et les modèles de cas. En plus des 45 spécifications, répondez aux spécifications suivantes. --Le terme est une chaîne de mots de la clause liée au prédicat (il n'est pas nécessaire de supprimer le mot auxiliaire de fin)

  • S'il y a plusieurs clauses liées au prédicat, arrangez-les dans le même standard et dans le même ordre que les mots auxiliaires, séparés par des espaces.
# -*- 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('verbe')[-1].base
            tmp = [(src_chunk.morphs_of_pos1('Assistant de cas')[-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. Exploration de la syntaxe des verbes fonctionnels

Je voudrais prêter attention uniquement au cas où le verbe wo case contient une nomenclature de connexion sa-variant. Modifiez 46 programmes pour répondre aux spécifications suivantes. ――Uniquement lorsque la phrase consistant en "Sahen connectant le nom + (auxiliaire)" est liée au verbe --Le prédicat est "nom de connexion sahen + est la forme de base de + verbe", et s'il y a plusieurs verbes dans la phrase, utilisez le verbe le plus à gauche --S'il y a plusieurs mots auxiliaires (phrases) liés au prédicat, arrangez tous les mots auxiliaires dans l'ordre du dictionnaire, séparés par des espaces. --S'il y a plusieurs clauses liées au prédicat, arrangez tous les termes séparés par des espaces (alignez-vous sur l'ordre des mots auxiliaires).

Enregistrez la sortie de ce programme dans un fichier et vérifiez les éléments suivants à l'aide des commandes UNIX. --Prédicats qui apparaissent fréquemment dans le corpus (nomenclature de connexion sahénienne + + verbe)

  • Prédicats et modèles verbaux qui apparaissent fréquemment dans le corpus
# -*- 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 == "Changer de connexion" and morphs[-1].pos == "Particule" and morphs[-1].base == "À":
                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('verbe')[-1].base
                tmp = [(other_chunk.morphs_of_pos1('Assistant de cas')[-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)

Une commande qui génère des prédicats qui apparaissent fréquemment dans le corpus (nomenclature de connexion variant sa + + verbe).

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

Une commande qui génère des prédicats et des modèles de verbes qui apparaissent fréquemment dans le corpus.

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

</ i> 48. Extraction des chemins de la nomenclature aux racines

Pour une clause contenant toute la nomenclature de la phrase, extrayez le chemin de cette clause jusqu'à la racine de l'arbre de syntaxe. Cependant, le chemin sur l'arbre de syntaxe doit satisfaire aux spécifications suivantes. --Chaque clause est représentée par une séquence morphologique (de la couche superficielle) --Concaténer les expressions de chaque clause avec "->" de la clause de début à la clause de fin du chemin.

# -*- 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('nom') and chunk.dst != -1:
                paths.append(extractPath(chunk, sentence))

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

</ i> 49. Extraction de chemins de dépendances entre nomenclature

Extraire le chemin de dépendance le plus court qui relie toutes les paires de nomenclatures de la phrase. Cependant, lorsque les numéros de clause de la paire de nomenclatures sont i et j (i <j), le chemin de dépendance doit satisfaire aux spécifications suivantes. --Similaire au problème 48, le chemin est exprimé en concaténant les expressions (éléments morphologiques de surface) de chaque phrase de la clause de début à la clause de fin avec "->". --Remplacer la nomenclature contenue dans les clauses i et j par X et Y, respectivement.

De plus, la forme du chemin de dépendance peut être considérée des deux manières suivantes. --Si la clause j existe sur le chemin de la clause i à la racine de l'arbre de syntaxe: Afficher le chemin de la clause i à la clause j --Autre que ce qui précède, lorsque la clause i et la clause j se croisent en une clause commune k sur le chemin de la clause j à la racine de l'arbre syntaxique: le chemin immédiatement avant la clause i vers la clause k et le chemin immédiatement avant la clause j vers la clause k, Affichez le contenu de k en les concaténant avec "|"

# -*- 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 != 'symbole':
                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('nom')]
        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, "nom", "X")
        y = posReplace(path.Y, "nom", "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