Markov Chain Artificielle Brainless avec Python + Janome (3) Yuya Ozaki Freedom Haiku Generator

Préface

Deux fois avant Markov Chain Artificial Brainless (1) Introduction à Janome avec Python + Janome Dernière fois [Chaîne de Markov artificielle sans cervelle avec Python + Janome (2) Introduction à la chaîne de Markov] (https://qiita.com/GlobeFish/items/17dc25f7920bb580d298)

Enfin, nous implémenterons sérieusement la génération de phrases. Tout matériel peut être utilisé pour la génération de phrases, mais si la phrase est trop cohérente L'impression est que l'incohérence ressort. Une longueur modérée, moelleuse et contextuelle est souhaitable. Donc, cette fois, j'ai préparé un haïku de forme libre de Yuya Ozaki. "Je suis seul même si je tousse".

Saisie des données

Tout d'abord, préparez un fichier texte. Cette fois, j'ai préparé ceci. Sélection Ozaki Yuya (Aozora Bunko)

DL et placez le fichier texte dans le même répertoire. Le contenu est comme ça.

Collection de phrases sélectionnées par Yuya Ozaki
Yuya Ozaki

Préface de l'édition Aozora Bunko

Dans ce fichier texte, avec Taneda Yamatohi, les œuvres d'Ozaki Hosai, un poète qui représente le soi-disant haïku à rythme libre, sont classées par ordre chronologique. L'essai de Hoya a commencé tôt au collège, et les étapes menant à sa mort à l'âge de 41 ans sont divisées en dix périodes.
Bien sûr, je n'ai publié ici qu'une petite partie de la phrase, pas la totalité. Les choix ont été faits aussi clairement que possible, dans l'espoir qu'ils seraient lus par les jeunes. De plus, au début de chaque chapitre, un bref commentaire sur la sortie de cette période est joint.
Il existe de nombreuses phrases publiées avec des notations différentes. Pour la numérisation, basée sur "Ozaki Yuya Phrasebook" (Yao Shobo) et "Ozaki Ryoya Zenkushu" (Shunshusha), les deux sont affichés si la notation est différente. La notation de la phrase avec () est basée sur "Ozaki Yuya Complete Phrasebook". <Edit-Aozora Bunko / Hamano>

[Lycée]
Yuya Ozaki est né le 20 janvier 1858 à Yoshikata-cho, Emi-gun, préfecture de Tottori (actuellement la ville de Tottori) en tant que deuxième fils de Shinzo Ozaki et de sa mère. Vrai nom Hideo. Entré au lycée préfectoral de Daiichi en 1897. L'écriture de phrases a commencé à cette époque.

Fil de cerf-volant coupé branche de prune suspendue

Une maison calme avec eau et yanagi d'été

Je me demande si le plancher de pêche est vu d'entre les arbres

Je me demande si c'est le déjeuner en fonction du bureau d'une bonne personne

Huttes et villes de Hagi avec beaucoup de rosée

Le coin du champ qui demande des chrysanthèmes froids et des poulets

Est-ce le deuxième étage où se trouvent les jeunes feuilles sur le parapet?

Le printemps comme une dépression malade

J'ai écrit une fonction qui ne prend que le haïku à rythme libre et le stocke dans un tableau. En bref, scoop des phrases qui ne sont ni la fin d'un signe de ponctuation ni écrites entre []. ~~ (Il était difficile d'absorber une partie de l'en-tête et du pied de page, donc j'ai supprimé manuellement ceci du fichier d'origine) ~~

import re

def haiku_reader(textfile):
    f = open(textfile, 'r')
    pre_haiku_set = [line.rstrip('\n') for line in f.readlines() if line != '\n']

    pre_haiku_set2 = [line for line in pre_haiku_set if re.findall(r'[.*|(.*',line) == []]
    haiku_set = [line + '.' for line in pre_haiku_set2 if re.findall(r'.*?。',line) == []]
    return haiku_set

pre_haiku_set est un tableau de phrases dont les sauts de ligne à la fin de la phrase sont supprimés. pre_haiku_set2 stocke les phrases qui n'incluent pas d'écriture [] et (). Enfin, les phrases sans ponctuation sont rassemblées dans haiku_set et complétées. Puisqu'il est pratique d'avoir un signal pour terminer plus tard, je mets un «.» À la fin du haïku ici. Le contenu de haiku_set ressemble à ceci.

['Fil de cerf-volant coupé branche de prune suspendue.', 'Une maison calme avec eau et yanagi d'été.', 'Je me demande si le plancher de pêche est vu d'entre les arbres.', 'Je me demande si c'est le déjeuner en fonction du bureau d'une bonne personne.', 'Huttes et villes de Hagi avec beaucoup de rosée.', 'Le coin du champ qui demande des chrysanthèmes froids et des poulets.', 'Est-ce le deuxième étage où se trouvent les jeunes feuilles sur le parapet?.', 'Le printemps comme une dépression malade.', 'Yukiharu et la bien-aimée Tsukushi Koto de sa mère.',
(Omis)
'Pas blancs Nagisa.', 'Pauvres et alignés dans des pots de fleurs.', 'Givre et oiseaux brillants.', 'Thé chaud
Boutique.', 'Une forêt avec de la neige approchant de la forêt.', 'C'est un os épais qui rend la viande mince..', 'Mettez une boisson chaude et laissez-la aller.', 'Mettez le corps mince sur la fenêtre et le sifflet du navire.', 'Devenez malade et le fil de saule est soufflé.', 'Montagne de printemps
L'épée est sortie du blanc.']

Ensuite, définissons une fonction qui crée un tableau qui les stocke séparément.

def barashi(text):
    t = Tokenizer()
    parted_text = ''
    for haiku in haiku_reader(text):
        for token in t.tokenize(haiku):
            parted_text += str(token.surface)
            parted_text += '|'
    word_list = parted_text.split('|') 
    word_list.pop()
    return word_list

C'est la même chose que Chapitre précédent sauf qu'il est fonctionnalisé. Il n'y a rien de spécial à ce sujet.

Introduction au type deque

La dernière fois, nous avons implémenté une chaîne de Markov simple avec N = 1, mais généralisons cette fois-ci. Pour implémenter le Nième ordre, utilisez le ** type deque ** du module collections, qui est une bibliothèque Python standard. Il s'agit d'une structure de données qui convient mieux aux files d'attente et aux piles qu'aux listes, et constitue un excellent moyen d'insérer et de supprimer facilement des deux extrémités.

from collections import deque

queue = deque([9,9],3)

for i in range(10):
    print(queue)
    queue.append(i)

Vous pouvez créer un objet deque avec deque (). Vous pouvez spécifier la valeur initiale dans le premier argument et le nombre maximal d'éléments dans le deuxième argument. Si vous spécifiez le nombre maximum d'éléments, les éléments seront supprimés du côté opposé au côté ajouté. Exécutons le code ci-dessus.

deque([9, 9], maxlen=3)
deque([9, 9, 0], maxlen=3)
deque([9, 0, 1], maxlen=3)
deque([0, 1, 2], maxlen=3)
deque([1, 2, 3], maxlen=3)
deque([2, 3, 4], maxlen=3)
deque([3, 4, 5], maxlen=3)
deque([4, 5, 6], maxlen=3)
deque([5, 6, 7], maxlen=3)
deque([6, 7, 8], maxlen=3)

Implémentation de la chaîne de Markov au Nième étage (dictionnaire)

Définissons une fonction qui crée un dictionnaire qui associe un groupe de N mots aux mots qui les suivent.

def dictionary_generator(text,order):
    dictionary = {}
    queue = deque([],order)
    word_list = barashi(text)
    for word in word_list:
        if len(queue) == order and '.' not in queue:
            key = tuple(queue)
            if key not in dictionary:
                dictionary[key] = []
                dictionary[key].append(word)
            else:
                dictionary[key].append(word)
        queue.append(word)
    
    return dictionary

La structure de base est la même que le chapitre précédent, seule la clé du dictionnaire est deque. Cependant, il existe une restriction selon laquelle la clé du dictionnaire doit pouvoir être hachée. Lors de l'ajout d'un élément, il est converti en un tuple hachable. Le contenu du dictionnaire lorsque N = 2 ressemble à ceci.

{('Couper', 'cerf-volant'): ['de'], ('cerf-volant', 'de'): ['fil'], ('de', 'fil'): ['Prendre', 'Mais'], ('fil', 'Prendre'): ['Keri'], ('Prendre', 'Keri'): ['prune'], ('Keri', 'prune'): ['de'], ('prune', 'de'): ['branche'], ('de', 'branche'): ['.'], ('eau', 'la grève'): ['main'], ('la grève', 'main'): ['silencieux'], ('main', 'silencieux'): ['Nana'], ('silencieux', 'Nana'): ['Maison'], 
(Omis)

Implémentation de la chaîne de Markov au Nième étage (génération de phrases)

C'est finalement une fonction de génération de phrases.

def text_generator(dictionary,order):
    start = random.choice(list(dictionary.keys()))
    t = Tokenizer()
    token = list(t.tokenize(start[0]))
    part_of_speech = str(token[0].part_of_speech)
    while re.match(r'nom|adjectif|Des mots impressionnants|Coalm',part_of_speech) == None:
        start = random.choice(list(dictionary.keys()))
        token = list(t.tokenize(start[0]))
        part_of_speech = str(token[0].part_of_speech)
    now_word = deque(start,order)
    sentence = ''.join(now_word)
    for i in range (1000):
        if now_word[-1] == '.':
            break
        elif tuple(now_word) not in dictionary:
            break
        else:
            next_word = random.choice(dictionary[tuple(now_word)])
            now_word.append(next_word)
            sentence += next_word
    return sentence

=========== Remarque ci-dessous ===========

def text_generator(dictionary,order):
    start = random.choice(list(dictionary.keys()))
    t = Tokenizer()
    token = list(t.tokenize(start[0]))
    part_of_speech = str(token[0].part_of_speech)
    while re.match(r'nom|adjectif|Des mots impressionnants|Coalm',part_of_speech) == None:
        start = random.choice(list(dictionary.keys()))
        token = list(t.tokenize(start[0]))
        part_of_speech = str(token[0].part_of_speech)
    now_word = deque(start,order)
    sentence = ''.join(now_word)

J'en apporterai un au hasard à partir de la clé du dictionnaire que j'ai créé plus tôt. Cependant, si cela commence par un assistant, cela ne ressemble pas à une phrase, donc ça n'a pas l'air bien. Je vais redessiner la nomenclature, les adjectifs, les mots émotionnels ou les compléments avec une phrase longue jusqu'à ce que le début soit écrit. (À propos, la plupart des recueils de chansons originaux étaient des haïkus avec une nomenclature.) Le jeton contient le premier mot qui a été transformé en un objet janome.tokenizer.Token. La partie du premier mot est acquise par le jeton [0] .part_of_speech. Si vous apportez un joli tableau d'exportation, placez-le dans la file d'attente now_word Stockez la chaîne combinée dans la phrase.

    for i in range (1000):
        if now_word[-1] == '.':
            break
        elif tuple(now_word) not in dictionary:
            break
        else:
            next_word = random.choice(dictionary[tuple(now_word)])
            now_word.append(next_word)
            sentence += next_word
    return sentence

・ Si vous venez à '.', Vous avez terminé ・ Si vous ne trouvez pas le mot suivant, terminez-le. Nous mettons les contraintes en premier. La seconde moitié est la même que le chapitre précédent, sauf que les mots suivants sont choisis au hasard et ajoutés à la phrase.

Résumé

from collections import deque
from janome.tokenizer import Tokenizer
import re
import random


def haiku_reader(textfile):
    f = open(textfile, 'r')
    pre_haiku_set = [line.rstrip('\n') for line in f.readlines() if line != '\n']

    pre_haiku_set2 = [line for line in pre_haiku_set if re.findall(r'[.*|(.*',line) == []]
    haiku_set = [line + '.' for line in pre_haiku_set2 if re.findall(r'.*?。',line) == []]
    return haiku_set


def barashi(text):
    t = Tokenizer()
    parted_text = ''
    for haiku in haiku_reader(text):
        for token in t.tokenize(haiku):
            parted_text += str(token.surface)
            parted_text += '|'
    word_list = parted_text.split('|') 
    word_list.pop()
    return word_list

def dictionary_generator(text,order):
    dictionary = {}
    queue = deque([],order)
    word_list = barashi(text)
    for word in word_list:
        if len(queue) == order and '.' not in queue:
            key = tuple(queue)
            if key not in dictionary:
                dictionary[key] = []
                dictionary[key].append(word)
            else:
                dictionary[key].append(word)
        queue.append(word)
    
    return dictionary


def text_generator(dictionary,order):
    start = random.choice(list(dictionary.keys()))
    t = Tokenizer()
    token = list(t.tokenize(start[0]))
    part_of_speech = str(token[0].part_of_speech)
    while re.match(r'nom|adjectif|Des mots impressionnants|Coalm',part_of_speech) == None:
        start = random.choice(list(dictionary.keys()))
        token = list(t.tokenize(start[0]))
        part_of_speech = str(token[0].part_of_speech)
    now_word = deque(start,order)
    sentence = ''.join(now_word)
    for i in range (1000):
        if now_word[-1] == ".":
            break
        elif tuple(now_word) not in dictionary:
            break
        else:
            next_word = random.choice(dictionary[tuple(now_word)])
            now_word.append(next_word)
            sentence += next_word
    return sentence


text = "ozaki_hosai_senkushu.txt"
order = 2
dictionary = dictionary_generator(text,order)

print(text_generator(dictionary,order))
print(text_generator(dictionary,order))
print(text_generator(dictionary,order))

Résultat d'exécution de N = 3

Élevez le visage du feu.
Les lanternes volent vers le feu.
Vendre à la femme le matin avec la fenêtre ouverte.

Ça ressemble à ça! Quand j'étais ravi, j'ai été surpris parce que le deuxième et le ** mystérieux troisième étaient réels. Ce qui suit est N = 2. Je me demande si c'est la limite de l'originalité.

Avant.
Mettez le visage du mendiant sur le bol de feu.
Mort sous une grande tour de pierre.

C'était aussi la troisième partie de la vraie chose. Je ne sais pas ~

Point addictif

from janome.tokenizer import Tokenizer

t = Tokenizer()
s = "Phrase"
print(type(t.tokenize(s)))
#<class 'generator'>

t.tokenize () est la classe du générateur par défaut. En regardant les documents sur Janome, · Liste par défaut -Devenir un générateur en définissant l'argument stream sur True On a dit qu'il semble qu'il soit devenu un générateur depuis le début lorsque le flux a disparu récemment. Pour faire une liste, placez-la simplement dans list ().

De côté

C'est une bonne idée, je vais donc en énumérer quelques-uns.

Jeter un si bon mois seul.
Une grosse fourmi noire est accrochée au tatami.
Le corps du saké est plein de Kuzumizu.
Hibiki est mort et solitaire dans le jardin.
J'ai deux oreilles que je veux serrer.
Le toit est lourd.

C'est devenu plutôt réel ... J'ai essayé de générer diverses choses, mais personnellement

Lâcher à la mer sans poulet.

C'était un succès.

Recommended Posts

Markov Chain Artificielle Brainless avec Python + Janome (3) Yuya Ozaki Freedom Haiku Generator
Markov Chain Artificial Brainless avec Python + Janome (1) Introduction à Janome
Chaîne de Markov artificielle sans cervelle avec Python + Janome (2) Introduction à la chaîne de Markov
générateur de nombres aléatoires français avec python
Python - Simulation de transition d'état de chaîne de Markov