[Chapitre 4] Introduction à Python avec 100 coups de traitement du langage

Cet article est une suite de mon livre Introduction à Python avec 100 Knock. Je vais vous expliquer 100 coups Chapitre 4.

Tout d'abord, installez l'analyseur morphologique MeCab, téléchargez neko.txt, analysez l'élément morphologique et vérifiez le contenu.

$ mecab < neko.txt > neko.txt.mecab

C'est "Je suis un chat" d'Aozora Bunko.

Le système du dictionnaire par défaut de MeCab est similaire à la grammaire scolaire, mais les verbes adjectifs sont la nomenclature + les verbes auxiliaires, et les verbes sa-variable sont la nomenclature + les verbes. Le format de sortie est probablement le suivant:

Type de surface\t part paroles,Sous-classification des paroles des parties 1,Sous-classification des pièces détachées 2,Sous-classification des paroles des parties 3,Type d'utilisation,Type d'utilisation,Prototype,en train de lire,Forme de prononciation

De plus, les phrases sont séparées par «EOS». À propos, de nombreux analyseurs morphologiques supposent des caractères pleine largeur, il est donc préférable de remplacer les caractères demi-largeur lors de l'analyse de textes Web.

itertools C'est un gros problème, alors familiarisons-nous avec le module itertools. Il existe des méthodes pour créer un itérateur pratique.

islice() Il est également apparu au chapitre 2. Vous pouvez découper un itérateur avec ʻislice (iterable, start, stop, step) . Si step est omis, ce sera 1, et si start est omis, ce sera start = 0. stop = None` signifie jusqu'à la fin. C'est très pratique, alors utilisons-le.

groupby() Vous pouvez faire quelque chose comme la commande Unix ʻuniq`.

from itertools import groupby
a = [1,1,1,0,0,1]
for k, g in groupby(a):
    print(k, list(g))
1 [1, 1, 1]
0 [0, 0]
1 [1]

Passer ʻiterablecomme premier argument de cette manière crée une paire d'itérateurs qui renvoient la valeur de cet élément et de ce groupe. Comme poursort, vous pouvez également spécifier key comme deuxième argument. J'utilise souvent ʻoperator.itemgetter (ce que vous savez si vous lisez Sort HOW TO au chapitre 2) Probablement). Nous utilisons également des expressions lambda qui renvoient des valeurs booléennes. ..

from operator import itemgetter
a = [(3, 0), (4, 0), (2, 1)]
for k, g in groupby(a, key=itemgetter(1)):
    print(k, list(g))
0 [(3, 0), (4, 0)]
1 [(2, 1)]

chain.from_iterable() Vous pouvez aplatir un tableau quadratique dans une dimension.

from itertools import chain
a = [[1,2], [3,4], [5,6]
print(list(chain.from_iterable(a))
[1, 2, 3, 4, 5, 6]

zip_longest() La fonction intégrée zip () convient aux itérables courts, mais utilisez-la si vous voulez qu'elle s'adapte aux itérables longs. Si vous l'utilisez normalement, il sera rempli avec None, mais vous pouvez spécifier la valeur à utiliser pour le remplissage avec le deuxième argument fillvalue.

product() Calculez le produit direct. De plus, les permutations () et les combinaisons () sont difficiles à implémenter par vous-même, donc je pense que cela vaut la peine de le savoir.

Ce ne sont que quelques-uns des «itertools», donc si vous êtes intéressé, lisez la documentation (https://docs.python.org/ja/3/library/itertools.html).

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

Implémentez un programme qui lit les résultats de l'analyse morphologique (neko.txt.mecab). Cependant, chaque élément morphologique est stocké dans un type de mappage avec la clé de la forme de surface (surface), de la forme de base (base), d'une partie du mot (pos) et d'une partie du mot sous-classification 1 (pos1), et une phrase est exprimée sous forme d'une liste d'éléments morphologiques (type de mappage). Faisons le. Pour le reste des problèmes du chapitre 4, utilisez le programme créé ici.

Si vous êtes une personne du langage orienté objet, vous voudrez utiliser une classe, mais c'est au chapitre suivant. Vous pouvez également utiliser Pandas comme dans le chapitre 2, mais je vais l'arrêter car il semble s'écarter de l'intention de l'énoncé du problème.

Voici un exemple de réponse.

q30.py


import argparse
from itertools import groupby, islice
from pprint import pprint
import sys


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('num', type=int)
    args = parser.parse_args()
    for sent_lis in islice(read_mecab(sys.stdin), args.num-1, args.num):
        pprint(sent_lis)

            
def read_mecab(fi):
    for is_eos, sentence in groupby(fi, lambda line: line.startswith('EOS')):
        if not is_eos:
            yield list(map(line2dic, sentence))


def line2dic(line):
    surface, info = line.rstrip().split('\t')
    col = info.split(',')
    dic = {'surface': surface,
          'pos': col[0],
          'pos1': col[1],
          'base': col[6]}
    return dic


if __name__ == '__main__':
    main()

$ python q30.py 2 < neko.txt.mecab

[{'base': '\ u3000', 'pos': 'symbol', 'pos1': 'blank', 'surface': '\ u3000'}, {'base': 'I'm', 'pos': 'Nomenclature', 'pos1': 'Synonymes', 'surface': 'I'm'}, {'base': 'est', 'pos': 'auxiliaire', 'pos1': 'participant', 'surface': 'is'}, {'base': 'cat', 'pos': 'nom', 'pos1': 'general', 'surface': 'cat'}, {'base': 'da', 'pos': 'verbe auxiliaire', 'pos1': '', 'surface': 'in'}, {'base': 'Are', 'pos': 'Verbe auxiliaire', 'pos1': '', 'surface': 'Are'}, {'base':'. ',' pos ':' Symbole ',' pos1 ':' Phrase ',' surface ':'. '}]

main () réduit la sortie. Si vous utilisez pprint.pprint () au lieu de print (), il affichera (jolie impression) avec des sauts de ligne ajustés.

Ce type de format peut être écrit intelligemment en passant une fonction qui retourne si une ligne est ʻEOS à clédegroupby ()`. Vous avez fait «céder» au chapitre 2.

Le problème est list (map ()). map (func, iterable) applique la fonction func à chaque élément de ʻiterableet renvoie un itérateur. Le résultat est le même que[line2sic (x) for x in phrase], mais il semble que Python tarde à appeler sa propre fonction dans l'instruction for, j'ai donc adopté cette notation ([[line2sic (x) for x in phrase]. Référence](https://qiita.com/hi-asano/items/aa2976466739f280b887)).

31. verbe

Extraire toutes les formes de surface du verbe.

Voici un exemple de réponse.

q31.py


from itertools import islice
import sys

from q30 import read_mecab


def main():
    for sent_lis in islice(read_mecab(sys.stdin), 5):
        for word in filter(lambda x: x['pos'] == 'verbe', sent_lis):
            print(word['surface'])

                
if __name__ == '__main__':
    main()

$ python q31.py < neko.txt.mecab

Née Tsuka Shi Pleurs Shi Est

J'essaye de récupérer les N premières phrases. ʻArgpase` est également omis car il a une odeur gênante.

Je n'avais rien d'autre à dire, alors j'ai utilisé de force filter (). Cela équivaut à (x for x in iterable if condition (x)) et ne renvoie que les éléments qui correspondent à la condition. Pour être honnête, il suffit d'utiliser l'instruction ʻif, donc il n'y a pas beaucoup de tours (dans ce cas, je pense que c'est lent à utiliser filter () `).

32. Prototype du verbe

Extraire toutes les formes originales du verbe.

Omis car c'est presque le même que 31.

33. «B de A»

Extraire la nomenclature dans laquelle deux nomenclatures sont reliées par "non".

Il n'y a rien à dire car cela peut être fait en poussant. Voici un exemple de réponse.

q33.py


from itertools import islice
import sys


from q30 import read_mecab


def main():
    for sent_lis in islice(read_mecab(sys.stdin), 20):
        for i in range(len(sent_lis) - 2):
            if (sent_lis[i+1]['base'] == 'de' and sent_lis[i]['pos'] == 'nom'
                and sent_lis[i+2]['pos'] == 'nom'):
                print(''.join(x['surface'] for x in sent_lis[i: i+3]))

                
if __name__ == '__main__':
    main()

$ python q33.py < neko.txt.mecab

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

J'ai mentionné plus tôt que la continuation de ligne est \ en Python, mais vous pouvez librement couper les lignes entre parenthèses. L'expression conditionnelle de l'instruction if est inutilement incluse entre () juste pour dire cela.

34. Concaténation de nomenclature

Extraire la concaténation de la nomenclature (noms qui apparaissent consécutivement) avec la correspondance la plus longue.

Faites simplement group by () avec les paroles de la partie. Voici un exemple de réponse.

q34.py


import sys
from itertools import groupby, islice

from q30 import read_mecab


def main():
    for sent_lis in islice(read_mecab(sys.stdin), 20):
        for key, group in groupby(sent_lis, lambda word: word['pos']):
            if key == 'nom':
                words = [word['surface'] for word in group]
                if len(words) > 1:
                    print(''.join(words))

                
if __name__ == '__main__':
    main()

$ python q34.py < neko.txt.mecab

Chez l'homme Le pire Opportun Un cheveu Puis chat une fois Puupuu et fumée

35. Fréquence d'occurrence des mots

Trouvez les mots qui apparaissent dans la phrase et leur fréquence d'apparition et classez-les par ordre décroissant de fréquence d'apparition.

Utilisez simplement collections.Counter. Voici un exemple de réponse.

q35.py


import sys
from collections import Counter
from pprint import pprint

from q30 import read_mecab


def get_freq():
    word_freq = Counter(word['surface'] for sent_lis in read_mecab(sys.stdin) 
                            for word in sent_lis)
    return word_freq.most_common(10)


if __name__ == '__main__':
    pprint(get_freq())

$ python q35.py < neko.txt.mecab

[('Non', 9194), ('。', 7486), («Te», 6868), ('、', 6772), ("Ha", 6420), ('À', 6243), ('À', 6071), ('Et', 5508), («Ga», 5337), («Ta», 3988)]

matplotlib Maintenant que je dessine un graphique pour la question suivante, il est enfin temps pour ce type. Faisons pip install. Je ne veux pas beaucoup expliquer les modules externes dans l'article "Introduction à Python", et si j'explique cela sérieusement, je peux écrire un livre. Tout d'abord, lisez cet article Qiita pour comprendre la structure hiérarchique de matplotlib. C'est très compliqué, n'est-ce pas? C'est «Pyplot» qui définit la zone de manière appropriée. Cette fois, je ne ferai pas d'ajustements fins à l'apparence, donc je vais le faire de cette façon. Voici un exemple simple.

import matplotlib.pyplot as plt
#Spécifiez le type de graphique et les données
plt.plot([1, 2, 3, 4], [1, 4, 9, 16])
#En quelque sorte réglé
plt.title('example')
plt.ylabel('some numbers')
#dessin
plt.show()

output_28_0.png

La signification de l'instruction d'importation est "Importer le sous-module pyplot du module matplotlib avec le nom plt ".

Tout d'abord, décidez du type de graphique. Pour les graphiques linéaires, plt.plot (), pour les graphiques à barres horizontales, plt.barh (), pour les graphiques en colonnes, plt.bar (), etc. (Iterable est numpy dans pyplot. Il peut être préférable de passer un tableau numpy car il sera converti en tableau seul).

Ensuite, définissez l'apparence de quelque chose. plt.yticks () peut définir la coordonnée y et les caractères pour l'accompagner. Vous pouvez utiliser plt.xlim () pour définir les valeurs maximum et minimum pour l'axe des x. plt.yscale (" log ") fait de l'axe y une échelle logarithmique.

Enfin, le dessin. J'utilise Jupyter, donc j'utilise plt.show (). Ceux qui exécutent le script doivent utiliser plt.savefig (filename) pour sortir le fichier.

Pour être honnête, cette méthode est semblable à MATLAB et non pythonique, mais c'est facile.

Pour afficher le japonais avec matplotlib

Puisque la police par défaut ne prend pas en charge le japonais, elle deviendra tofu. Par conséquent, pour afficher le japonais sur le graphique, vous pouvez définir une police qui prend en charge le japonais, mais en fonction de votre environnement, vous ne trouverez peut-être pas la police japonaise ou vous devrez peut-être l'installer car elle n'est pas incluse en premier lieu. C'est dur. Nous vous faciliterons la tâche sur japanize-matplotlib.

36. Top 10 des mots les plus fréquents

Affichez les 10 mots les plus courants et leur fréquence d'apparition dans un graphique (par exemple, un graphique à barres).

from collections import Counter

from q30 import read_mecab
import matplotlib.pyplot as plt
import japanize_matplotlib

word_freq = Counter(word['base'] for sent_lis in read_mecab(open('neko.txt.mecab')) 
                            for word in sent_lis)
word, count  = zip(*word_freq.most_common(10))
len_word = range(len(word))

plt.barh(len_word, count, align='center')
plt.yticks(len_word, word)
plt.xlabel('frequency')
plt.ylabel('word')
plt.title('36.Top 10 des mots les plus fréquents')
plt.show()

output_31_0.png

Quel est le «*» dans le «zip ()»? Mais ce que je veux faire ici, c'est la translocation. Autrement dit, transformer des données telles que «[[a, b], [c, d]]» en «[[a, c], [b, d]]». Par conséquent, le moyen le plus simple de le transférer est d'écrire zip (* seq). Ceci est équivalent à zip (seq [0], seq [1], ...) (Unpack Argument List # unpacking-argument-lists)). zip ([a, b], [c, d]) est [(a, c), (b, d)], n'est-ce pas? Vous pouvez également utiliser une affectation décompressée pour assigner différentes variables à la fois.

(Ceci est la fin de l'explication de la solution alternative de la fonction ngram au chapitre 1)

Gardez à l'esprit que les principaux mots de la fréquence des mots sont des mots fonctionnels (auxiliaires, signes de ponctuation).

37. Top 10 des mots qui coïncident fréquemment avec "chat"

Afficher 10 mots qui cohabitent souvent avec "chat" (fréquence élevée de cooccurrence) et leur fréquence d'apparition dans un graphique (par exemple, un graphique à barres).

word_freq = Counter()
for sent_lis in read_mecab(open('neko.txt.mecab')):
    for word in sent_lis:
        if word['surface'] == 'Chat':
            word_freq.update(x['base'] for x in sent_lis if x['surface'] != 'Chat')
            break
            
words, count  = zip(*word_freq.most_common(10))
len_word = range(len(words))

plt.barh(len_word, count, align='center')
plt.yticks(len_word, words)
plt.xlabel('frequency')
plt.ylabel('word')
plt.title('37.Top 10 des mots qui coïncident fréquemment avec "chat"')
plt.show()

output_34_0.png

Vous pouvez mettre à jour l'objet Counter avec Counter.update (iterable). Cependant, si vous ne vous concentrez pas sur des mots indépendants, le résultat sera totalement inintéressant.

38. histogramme

Tracez un histogramme de la fréquence d'occurrence des mots (l'axe horizontal représente la fréquence d'occurrence et l'axe vertical représente le nombre de types de mots qui prennent la fréquence d'occurrence sous forme de graphique à barres).

word_freq = Counter(word['base'] for sent_lis in read_mecab(open('neko.txt.mecab')) 
                        for word in sent_lis)
data = Counter(count for count in word_freq.values())

x, y = data.keys(), data.values()

plt.bar(x, y)
plt.title("38.histogramme")
plt.xlabel("frequency")
plt.ylabel("number of the words")
plt.xlim(1, 30)
plt.show()

output_34_0.png

Vous pouvez obtenir toutes les clés avec dict.keys () et toutes les valeurs avec dict.values ().

En regardant le nombre de types de mots, nous pouvons voir que de nombreux mots sont peu fréquents. Il semble que ce soit inversement proportionnel. Dans l'apprentissage en profondeur, le traitement de texte à basse fréquence est également important pour cette raison.

39. Loi de Zipf

Tracez les deux graphiques logarithmiques avec la fréquence d'occurrence des mots sur l'axe horizontal et la fréquence d'occurrence sur l'axe vertical.

word_freq = Counter(word['base'] for sent_lis in read_mecab(open('neko.txt.mecab')) 
                        for word in sent_lis)
_, count = zip(*word_freq.most_common())
plt.plot(range(1, len(count)+1), count)
plt.yscale("log")
plt.xscale("log")
plt.title("39.Loi de Zipf")
plt.xlabel("log(rank)")
plt.ylabel("log(frequency)")
plt.show()

output_37_0.png

La pente des deux graphes logarithmiques est d'environ -1. Cela signifie freq ∝ rank ^ (-1). Cela semble lié au 38e résultat. Cherchons sur Google les détails de la loi de Zipf.

Résumé

Vient ensuite le chapitre 5

Je vais enfin utiliser la classe. Est-ce la prochaine et dernière introduction à Python?

(5/16) J'ai écrit → https://qiita.com/hi-asano/items/5e18e3a5a711a752ad99

Recommended Posts

[Chapitre 5] Introduction à Python avec 100 coups de traitement du langage
[Chapitre 3] Introduction à Python avec 100 coups de traitement du langage
[Chapitre 2] Introduction à Python avec 100 coups de traitement du langage
[Chapitre 4] Introduction à Python avec 100 coups de traitement du langage
[Chapitre 6] Introduction à scicit-learn avec 100 coups de traitement du langage
100 traitements de langage avec Python
100 traitements de langage avec Python (chapitre 3)
100 traitements de langage avec Python (chapitre 2, partie 2)
100 traitements de langage avec Python (chapitre 2, partie 1)
100 coups de traitement du langage ~ Chapitre 1
Introduction au langage Python
Le traitement de 100 langues frappe le chapitre 2 (10 ~ 19)
Démarrer avec Python avec 100 coups sur le traitement du langage
100 coups de traitement du langage avec Python 2015
100 Language Processing Knock Chapitre 1 (Python)
[Traitement du langage 100 coups 2020] Résumé des exemples de réponses par Python
Introduction au traitement parallèle distribué Python par Ray
J'ai essayé de résoudre la version 2020 de 100 problèmes de traitement du langage [Chapitre 3: Expressions régulières 20 à 24]
J'ai essayé de résoudre la version 2020 de 100 coups de traitement de langue [Chapitre 1: Mouvement préparatoire 00-04]
J'ai essayé de résoudre la version 2020 de 100 traitements linguistiques [Chapitre 1: Mouvement préparatoire 05-09]
[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 coups de traitement du langage 2020: Chapitre 4 (analyse morphologique)
[Traitement du langage 100 coups 2020] Chapitre 5: Analyse des dépendances
[Introduction à Python3 Jour 13] Chapitre 7 Chaînes de caractères (7.1-7.1.1.1)
[Introduction à Python3 Jour 14] Chapitre 7 Chaînes de caractères (7.1.1.1 à 7.1.1.4)
Introduction à Protobuf-c (langage C ⇔ Python)
[Traitement du langage 100 coups 2020] Chapitre 1: Mouvement préparatoire
Traitement d'image avec la binarisation Python 100 knocks # 3
[Traitement du langage 100 coups 2020] Chapitre 7: Vecteur Word
[Introduction à Python3 Jour 15] Chapitre 7 Chaînes de caractères (7.1.2-7.1.2.2)
10 fonctions du "langage avec batterie" python
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 traitement d'image par Python Knock # 2 Échelle de gris
100 Language Processing Knock Chapitre 1 par Python
[Traitement du langage 100 coups 2020] Chapitre 4: Analyse morphologique
[Introduction à Python3 Day 21] Chapitre 10 Système (10.1 à 10.5)
Traitement du langage 100 knocks-48: Extraction du chemin du nez à la racine
[Raspi4; Introduction au son] Enregistrement stable de l'entrée sonore avec python ♪
Réhabilitation des compétences Python et PNL à partir de «Knock 100 Language Processing 2015» (chapitre 2 deuxième semestre)
Réhabilitation des compétences Python et PNL à partir de "100 Language Processing Knock 2015" (Chapitre 2 premier semestre)
100 traitements linguistiques frappent 03 ~ 05
100 coups de traitement linguistique (2020): 40
Bases du traitement d'images binarisées par Python
100 coups de traitement linguistique (2020): 32
Résumé du chapitre 2 de l'introduction aux modèles de conception appris en langage Java
Système de notation IPynb réalisé avec TA d'introduction à la programmation (Python)
J'ai fait 100 traitements linguistiques Knock 2020 avec GiNZA v3.1 Chapitre 4
100 coups de traitement linguistique (2020): 35
100 coups de traitement linguistique (2020): 47
100 coups de traitement linguistique (2020): 39
[Introduction à Python3, jour 17] Chapitre 8 Destinations de données (8.1-8.2.5)
Chapitre 4 Résumé de l'introduction aux modèles de conception appris en langage Java
100 traitement de langue knock-22: Extraction du nom de la catégorie
100 coups de traitement linguistique (2020): 26