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 pour
sort, 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).
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éde
groupby ()`. 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)).
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 () `).
Extraire toutes les formes originales du verbe.
Omis car c'est presque le même que 31.
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.
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
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()
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.
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.
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()
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).
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()
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.
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()
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.
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()
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.
itertools
map()
, filter()
matplotlib
--Transfertdict.keys()
, dict.values()
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