[PYTHON] 100 traitements du langage frappent l'analyse morphologique apprise au chapitre 4

introduction

Je résous 100 coups sur le traitement du langage lors d'une session d'étude centrée sur les membres de l'entreprise, mais le code de réponse et la solution Ceci est un résumé des astuces que j'ai trouvées utiles dans le processus. La plupart du contenu a été étudié et vérifié par moi-même, mais il contient également des informations partagées par d'autres membres du groupe d'étude.

Jusqu'au chapitre 3, le contenu était utilisable pour toute la programmation Python, mais comme ce chapitre est une analyse morphologique, il devient finalement davantage un traitement de langage.

séries

environnement

code

Prétraitement

Mettez neko.txt dans le même répertoire que le fichier ipynb (ou Python)

!mecab neko.txt -o neko.txt.mecab

Ensuite, le résultat de l'analyse morphologique est enregistré dans neko.txt.mecab.

30. Lecture des résultats de l'analyse morphologique

import re
import itertools

def parse_text(flat=True):
    with open('neko.txt.mecab') as file:
        morphs = []
        sentence = []

        for line in file:
            if re.search(r'EOS', line):
                continue

            surface, rest = line.split('\t')
            arr = rest.split(',')
            sentence.append({
                'surface': surface,
                'base': arr[6],
                'pos': arr[0],
                'pos1': arr[1],
            })
                
            if surface == ' ': #Les blancs ne sont pas considérés comme des éléments morphologiques
                sentence.pop(-1)
            if surface in [' ', '。']: #Considérez les blancs et la ponctuation comme la fin d'une phrase
                morphs.append(sentence)
                sentence = []
        
        if flat:
            return list(itertools.chain.from_iterable(morphs))
        else:
            return morphs

parse_text(flat=False)[:10]

résultat


[[{'surface': 'je', 'base': 'je', 'pos': 'nom', 'pos1': '代nom'},
  {'surface': 'Est', 'base': 'Est', 'pos': 'Particule', 'pos1': '係Particule'},
  {'surface': 'Chat', 'base': 'Chat', 'pos': 'nom', 'pos1': 'Général'},
  {'surface': 'alors', 'base': 'Est', 'pos': 'Verbe auxiliaire', 'pos1': '*'},
  {'surface': 'y a-t-il', 'base': 'y a-t-il', 'pos': 'Verbe auxiliaire', 'pos1': '*'},
  {'surface': '。', 'base': '。', 'pos': 'symbole', 'pos1': 'Phrase'}],
 [{'surface': 'Nom', 'base': 'Nom', 'pos': 'nom', 'pos1': 'Général'},

Ce problème nécessite «d'exprimer une phrase comme une liste d'éléments morphologiques (type de mappage)», mais lors de l'utilisation de cette fonction dans les problèmes 31 et suivants, la valeur de retour a été aplatie (non imbriquée). ) Est plus facile à gérer, j'ai donc décidé de préparer un argument formel appelé flat. La valeur par défaut de ce «flat» est «True», mais dans ce numéro, je passe l'argument «flat = False» car je veux une liste non aplatie.

La dernière ligne dit «[: 10]» parce que c'était juste que le nombre d'éléments à afficher pour confirmation était d'environ 10, donc il n'y a pas de nécessité particulière.

31. verbe

import numpy as np

def extract_surface():
    verbs = list(filter(lambda morph: morph['pos'] == 'verbe', parse_text()))
    return [verb['surface'] for verb in verbs]

print(extract_surface()[:100])

résultat


['Née', 'Tsuka', 'Shi', 'Pleurs', 'Shi', 'Est', 'début', 'Vous voyez', 'Ecoutez', 'Capture', 'Bouilli', 'Manger', 'Pensées', 'Chargement', 'Être', 'Ascenseur', 'Être', 'Shi', 'Ah', 'Calmez-vous', 'Vous voyez', 'Vous voyez', 'Pensées', 'Restant', 'Est', 'Sa', 'Ré', 'Shi', 'Rencontrer', 'Rencontrer', 'Shi', 'seulement', 'Si', 'Shi', 'Est', 'Coup', 'Ensemble', 'Faible', 'boire', 'Connaître', 'Asseyez-vous', 'Oh', 'Faire', 'Shi', 'début', 'Bouge toi', 'Bouge toi', 'Comprendre', 'Faire le tour', 'Devenir', 'De l'assistant', 'Pensées', 'Est', 'Saり', 'Shi', 'En dehors', 'Shi', 'Est', 'PenséesEn dehorsそ', 'Comprendre', 'Avec', 'Vous voyezる', 'je', 'Oh', 'Vous voyezえ', '隠Shi', 'Shiまっ', 'Différent', '明je', 'je', 'Être', '這jeEn dehorsShi', 'Vous voyezる', 'Désinvolte', 'Être', '這jeEn dehorsす', 'y a-t-il', 'Asseyez-vous', 'Shi', 'Pensées', 'Vous voyez', 'En dehors', 'Shi', 'Pleurs', 'À venir', 'くRéる', 'PenséesAvec', 'finalement', 'Vous voyez', 'À venir', 'Franchi', 'Prendre', 'Diminué', 'À venir', 'Pleurs', 'En dehors', 'y a-t-il', 'y a-t-il', 'Shi', 'Il est temps']

La valeur de retour peut également être créée comme list (map (lambda morph: morph ['surface'], verbs)), mais l'utilisation de la notation d'inclusion comme ci-dessus est un code plus concis.

En outre, cela dépend de la façon dont vous interprétez l'énoncé du problème, mais si vous ne souhaitez pas autoriser les éléments en double dans la liste de retour, mettez la dernière ligne de la fonction.

return set([verb['surface'] for verb in verbs])

Il existe des méthodes telles que.

32. Prototype du verbe

def extract_base():
    verbs = list(filter(lambda morph: morph['pos'] == 'verbe', parse_text()))
    return [verb['base'] for verb in verbs]

print(extract_base()[:100])

résultat


['Être né', 'Tsukuri', 'Faire', 'cri', 'Faire', 'Est', 'début', 'à voir', 'Ecoutez', 'Capturer', 'Ébullition', 'Manger', 'pense', 'Mettre', 'Être', 'ascenseur', 'Être', 'Faire', 'y a-t-il', '落ちTsukuri', 'à voir', 'à voir', 'pense', 'Rester', 'Est', 'Faire', 'Être', 'Faire', 'Rencontrer', 'rencontrer', 'Faire', 'Nomu', 'Devenir', 'Faire', 'Est', 'Coup', 'Faire', 'Faible', 'boire', 'connaître', 'Asseyez-vous', 'Oru', 'Faire', 'Faire', 'début', 'Bouge toi', 'Bouge toi', 'Comprendre', 'Faire le tour', 'Devenir', 'Être sauvé', 'pense', 'Est', 'Saru', 'Faire', 'Sortez', 'Faire', 'Est', 'Montez', 'Comprendre', 'Attacher', 'à voir', 'Est', 'Oru', 'apparaître', 'cacher', 'Finir', 'Faux', 'Pour être clair', 'Est', 'Être', 'Ramper', 'à voir', 'Jeter', 'Être', 'Ramper', 'y a-t-il', 'Asseyez-vous', 'Faire', 'Pense', 'à voir', 'Sortez', 'Faire', 'cri', 'viens', 'くÊtre', '考えAttacher', 'faire', 'à voir', 'viens', 'Traverser', 'Prendre', 'diminution', 'viens', 'cri', 'Sortez', 'y a-t-il', 'y a-t-il', 'Faire', 'Se raser']

Presque le même que 31.

33. Sahen substantif

def extract_sahens():
    return list(filter(lambda morph: morph['pos1'] == 'Changer de connexion', parse_text()))

extract_sahens()[:20]

résultat


[{'surface': 'S'inscrire', 'base': 'S'inscrire', 'pos': 'nom', 'pos1': 'Changer de connexion'},
 {'surface': 'Mémoire', 'base': 'Mémoire', 'pos': 'nom', 'pos1': 'Changer de connexion'},
 {'surface': 'Parler', 'base': 'Parler', 'pos': 'nom', 'pos1': 'Changer de connexion'},
 {'surface': 'Décoration', 'base': 'Décoration', 'pos': 'nom', 'pos1': 'Changer de connexion'},
 {'surface': 'Saillie', 'base': 'Saillie', 'pos': 'nom', 'pos1': 'Changer de connexion'},
 ...

Presque le même que 31.

34. «B de A»

def extract_noun_phrases():
    morphs = parse_text()
    phrases = []

    for i, morph in enumerate(morphs):
        if morph['surface'] == 'de' and morphs[i - 1]['pos'] == 'nom' \
                and morphs[i + 1]['pos'] == 'nom':
            phrases.append(
                morphs[i - 1]['surface'] + 'de' + morphs[i + 1]['surface'])

    return phrases
    
print(extract_noun_phrases()[:100])

résultat


['Sa paume', 'Sur la paume', 'Visage de l'élève', 'Devrait faire face', 'Au milieu du visage', 'Dans le trou', 'Palmier de calligraphie', 'L'arrière de la paume', 'Quoi', 'Mère essentielle', 'Sur la paille', 'À Sasahara', 'Devant l'étang', 'Sur l'étang', 'Trou dans la clôture', 'Trois voisins', 'Passage du temps', 'À l'intérieur de la maison', 'Son élève', 'Humains autres que', 'Étudiant précédent', 'Ta chance', 'Trois d'entre vous', 'Des démangeaisons thoraciques', 'Gouvernante', 'Maître', 'Sous le nez', 'Mon visage', 'Ma maison', 'Mon mari', 'Trucs pour la maison', 'Les notres', 'Son étude', 'Sur le livre', 'Couleur de peau', 'Sur le livre', 'Son tous les soirs', 'Autre que', 'À côté de mon mari', 'Son genou', 'Sur le genou', 'Sur l'expérience', 'Sur le bol de riz', 'Sur le 炬 燵', 'D'ici', 'Lit accompagné', 'Entre eux', 'Un compagnon', 'Exemple de nerf', 'Maître sexuel', 'Chambre voisine', 'Égoïste', 'Pour moi', 'Entre les planches de la cuisine', 'Respect pour moi', 'Mukai blanc', 'Comme une balle', 'Maison là', 'Étudiant à domicile', 'Bassin arrière', 'L'amour parent-enfant', 'Plus de discussion', 'Tête de couteau', 'Parapluie de 鰡', 'Pour eux', 'Maison militaire', 'Maître du remplaçant', 'Maison du professeur', 'Temps de chat', 'Ma maison', 'Gouvernante', 'Plein d'anglais', 'Faible habitude d'estomac', 'Dans le rack arrière', 'Hira no Sect', 'Salaire mensuel', 'Pour le moment', 'Comme ci-dessous', 'Comme maintenant', 'Mémoire du maître', 'Son ami', 'Lunettes à monture dorée', 'Le visage du maître', 'L'imagination à l'intérieur', 'Traduit', 'Bailleur d'intérêt', 'Derrière le bord d'or', 'Derrière moi', 'Son ami', 'Mon cercle', 'Autour du visage', 'Le résultat de l'ajout', 'Caractéristiques du visage', 'Autres chats', 'Serviteur maladroit', 'Mon mari', 'Chat de la même production', 'Peau tachetée', 'Coloration du maître', 'Muscles relatifs']

En utilisant ʻenumerate () , vous pouvez gérer les informations dans lesquelles morph se trouve dans morphs` comme une variable, qui est un code soigné.

35. Concaténation de nomenclature

def extract_continuous_nouns():
    morphs = parse_text()
    continuous_nouns = []

    for i, morph in enumerate(morphs):
        if morph['pos'] == 'nom' and morphs[i + 1]['pos'] == 'nom':
            continuous_noun = morph['surface'] + morphs[i + 1]['surface']
            
            j = 1
            while morphs[i + 1 + j]['pos'] == 'nom':
                continuous_noun += morphs[i + 1 + j]['surface']
                j += 1

            continuous_nouns.append(continuous_noun)
            
    return continuous_nouns

print(extract_continuous_nouns()[:100])

résultat


['Chez l'homme', 'Opportun', 'Puis chat', 'Puupuu et fumée', 'À l'intérieur du manoir', 'Trois cheveux', 'Autre que étudiant', 'Quarante-cinq poule', 'Gohen', 'L'autre jour', 'Mima', 'Votre cuisine', 'Maman de retour', 'Maison d'habitation', 'Étude d'une journée', 'Bosseur', 'Bosseur', 'Diligent', 'Quelques pages', 'Trois pages', 'Autre que mon mari', 'Autant que je suis', 'Maître du matin', 'Deux personnes', 'Dernier dur', '--Chat', 'Faiblesse neurogastrique', 'Faiblesse de l'estomac', 'Doigt', 'Terrible cul', 'Pause linguistique', 'Ma femme', 'Global', 'Direction musculaire', 'Shiro', 'À chaque fois', 'Shiro', 'Le bal de l'autre jour', 'Quatre', 'troisième jour', 'journée', 'Quatre', 'Shiro', 'Nos chats', 'Etc.', 'Chats', 'La vie de famille', 'La vie', 'Trois cheveux君', 'Mao', 'La possession', 'Entre nous', 'Entre la même famille', 'Coup d'œil', 'Ils humains', 'nous', 'je', 'Shiro', 'Trois cheveux君', 'Mao', 'Plein d'erreurs', 'M. Hoshi', 'Munemori', 'Munemori', 'Date du salaire mensuel', 'Peinture aquarelle', 'Chaque jour, chaque jour d'étude', 'Etude quotidienne', 'personne', 'Brossez vous-même', 'Sur des lunettes', 'Itari', 'Propriétaire Andrea del Salt', 'Rosée', 'Froid 鴉', 'Cette largeur', 'Peinture en direct', 'Le jour suivant', 'Bâton épicé', 'Maintenant je', 'Maintenant je', 'Produit Wave', 'Merveille', 'Chat aveugle', 'Secret dans mon coeur', 'Combien Andrea del Salt', 'Un autre grand', 'Pause', 'Mec stupide', 'Mec stupide', 'Bâton épicé', 'Mec stupideAppel', 'Appelez un bâtard', 'Appel', 'Hirai', 'Mec stupide', 'Tout le monde grandit', 'Où aller', 'Plusieurs fois', '10 tsubo']

36. Fréquence d'occurrence des mots

import pandas as pd

def sort_by_freq():
    words = [morph['base'] for morph in parse_text()]
    
    return pd.Series(words).value_counts()

sort_by_freq()[:20]

résultat


9194
。     7486
6868
、     6772
Est 6420
...

Comme solution alternative, importez la bibliothèque standard collections comme indiqué ci-dessous.

from collections import Counter

Vous pouvez également utiliser la méthode most_common () de l'objet Counter () (au lieu de value_counts () des pandas).

return Counter(words).most_common()

résultat


[('de', 9194),
 ('。', 7486),
 ('main', 6868),
 ('、', 6772),
 ('Est', 6420),
 ...

La différence entre ces deux solutions est que value_counts () renvoie Series, tandis que most_common () renvoie un tableau de tapples, donc lequel doit être utilisé pour un traitement ultérieur plus facile. N'est-ce pas bon?

37. Top 10 des mots les plus fréquents

import japanize_matplotlib

def draw_bar_graph():
    sort_by_freq()[:10].plot.bar()

draw_bar_graph()

bar.png

L'affichage du japonais prend du temps, mais il était facile d'utiliser la bibliothèque appelée japanize_matplotlib présentée dans l'article ici.

Aussi, en ce qui concerne le contenu de la fonction, je voulais l'écrire brièvement, j'ai donc utilisé .plot.bar () pour l'objet Series.

import matplotlib.pyplot as plt

Après avoir importé matplotlib en tant que, cela fonctionne même si vous écrivez comme suit.

morph_freqs = sort_by_freq()[:10]
plt.bar(morph_freqs.index, morph_freqs)

38. histogramme

import matplotlib.pyplot as plt

def draw_hist():
    plt.xlabel('Fréquence d'apparition')
    plt.ylabel('Nombre de types de mots')
    plt.hist(sort_by_freq(), bins=200)
    
draw_hist()

hist.png

Si vous voulez afficher le tout, ce sera un tel code, mais c'est un peu difficile à voir, il peut donc être plus réaliste de limiter la plage d'affichage comme suit.

def draw_hist_2():
    plt.xlabel('Fréquence d'apparition')
    plt.ylabel('Nombre de types de mots')
    plt.title('Fréquence d'apparence 20 ou moins')
    plt.hist(sort_by_freq(), bins=20, range=(1, 20))

draw_hist_2()

hist2.png

39. Loi de Zipf

def draw_log_graph():
    plt.xscale('log')
    plt.yscale('log')
    plt.xlabel('Classement de fréquence d'apparence')
    plt.ylabel('Fréquence d'apparition')
    plt.scatter(range(1, len(sort_by_freq()) + 1), sort_by_freq(), s=10)
    
draw_log_graph()

zipf.png

Lors de l'appel de la méthode «scatter», vous pouvez spécifier la taille des points avec l'option «s». La valeur par défaut est 20, mais c'était un peu gros, donc je l'ai réglé sur 10.

Résumé

MeCab est un logiciel open source, mais il était intéressant de savoir qu'il peut encore faire tant de choses.

D'un autre côté, j'ai également estimé que la précision de l'analyse n'était pas parfaite avec cela seul (par exemple, "Puuputo" renvoyé car le résultat de sortie à 35 n'est pas une nomenclature mais un complément). Afin de résoudre ce problème, je pense qu'il est nécessaire d'essayer différents dictionnaires et de les personnaliser par vous-même.

C'est tout pour ce chapitre, mais si vous faites une erreur, veuillez commenter.

Recommended Posts

100 traitements du langage frappent l'analyse morphologique apprise au chapitre 4
100 coups de traitement du langage 2020: Chapitre 4 (analyse morphologique)
[Traitement du langage 100 coups 2020] Chapitre 4: Analyse morphologique
Traitement du langage 100 coups Chapitre 4: Analyse morphologique 31. Verbes
100 Language Processing Knock 2020 Chapitre 4: Analyse morphologique
[Traitement du langage 100 coups 2020] Chapitre 5: Analyse des dépendances
100 Traitement du langage Knock Chapitre 4: Analyse morphologique
100 Language Processing Knock 2015 Chapitre 4 Analyse morphologique (30-39)
100 traitements du langage naturel frappent Chapitre 4 Analyse morphologique (première moitié)
100 traitements du langage naturel frappent Chapitre 4 Analyse morphologique (seconde moitié)
100 coups de traitement du langage ~ Chapitre 1
Le traitement de 100 langues frappe le chapitre 2 (10 ~ 19)
100 Commandes de traitement du langage Knock UNIX apprises au chapitre 2
100 Traitement du langage Knock Expressions régulières apprises au chapitre 3
Le traitement du langage naturel à 100 coups
100 points de traitement du langage naturel Chapitre 5 Analyse des dépendances (premier semestre)
100 Language Processing Knock 2015 Chapitre 5 Analyse des dépendances (40-49)
[Traitement du langage 100 coups 2020] Chapitre 3: Expressions régulières
100 traitements du langage naturel frappent le chapitre 4 Commentaire
[Traitement du langage 100 coups 2020] Chapitre 6: Machine learning
100 Language Processing Knock Chapitre 1 en Python
[Traitement du langage 100 coups 2020] Chapitre 1: Mouvement préparatoire
[Traitement du langage 100 coups 2020] Chapitre 7: Vecteur Word
100 Language Processing Knock 2020 Chapitre 5: Analyse des dépendances
100 Language Processing Knock 2020: Chapitre 3 (expression régulière)
[Traitement du langage 100 coups 2020] Chapitre 8: Réseau neuronal
[Traitement du langage 100 coups 2020] Chapitre 2: Commandes UNIX
[Traitement du langage 100 coups 2020] Chapitre 9: RNN, CNN
100 traitements linguistiques frappent 03 ~ 05
100 coups de traitement linguistique (2020): 40
100 coups de traitement linguistique (2020): 32
100 coups de traitement linguistique (2020): 35
100 coups de traitement linguistique (2020): 39
100 coups de traitement linguistique (2020): 22
100 coups de traitement linguistique (2020): 26
100 coups de traitement linguistique (2020): 34
100 coups de traitement linguistique (2020): 42
100 coups de traitement linguistique (2020): 29
Le traitement de 100 langues frappe 06 ~ 09
100 coups de traitement linguistique (2020): 43
100 coups de traitement linguistique (2020): 24
100 coups de traitement linguistique (2020): 45
100 coups de traitement linguistique (2020): 10-19
100 coups de traitement linguistique (2020): 30
100 coups de traitement linguistique (2020): 00-09
100 coups de traitement linguistique (2020): 31
100 coups de traitement linguistique (2020): 48
100 coups de traitement linguistique (2020): 44
100 coups de traitement linguistique (2020): 41
100 coups de traitement linguistique (2020): 37
100 coups de traitement linguistique (2020): 25
100 coups de traitement linguistique (2020): 23
100 coups de traitement linguistique (2020): 33
100 coups de traitement linguistique (2020): 20
100 coups de traitement linguistique (2020): 27
100 coups de traitement linguistique (2020): 46
100 coups de traitement linguistique (2020): 21
100 coups de traitement linguistique (2020): 36
100 coups de traitement du langage amateur: 71
100 coups de traitement du langage amateur: 56
100 coups de traitement du langage amateur: 24