En utilisant le moteur d'analyse morphologique japonais Janome écrit en Pure Python et la bibliothèque de chaînes de Markov markovify, les phrases japonaises sont apprises et générées automatiquement.
Fondamentalement Apprenez des phrases japonaises avec markovify et générez des phrases par chaîne de Markov C'est basé sur.
Cela fait un moment que je n'ai pas touché à Python, donc c'est assez lâche. Notez s'il vous plaît.
En fait, il n'y a pas de précédent pour l'apprentissage et la génération automatique de phrases japonaises à l'aide de markovify, mais la plupart d'entre eux utilisent MeCab, et en raison de son introduction, il est trivial dans l'environnement Windows et certains environnements virtuels. Cela prend du temps et des efforts (Heroku).
À cet égard, Janome est facile à installer même sous Windows, et il existe également un article qui présente en fait comment l'utiliser pour la génération automatique [après tout](https://omedstu.jimdofree.com/2018/05/06/%E3%83% 9E% E3% 83% AB% E3% 82% B3% E3% 83% 95% E9% 80% A3% E9% 8E% 96% E3% 81% AB% E3% 82% 88% E3% 82% 8B% E6% 96% 87% E6% 9B% B8% E7% 94% 9F% E6% 88% 90 /), mais je n'ai pas pu trouver une combinaison de markovify et de Janome (trop de niche). Il est plus facile d'utiliser markovify pour améliorer le naturel de la phrase générée, je voudrais donc l'utiliser si possible.
Donc cette fois, j'ai essayé de rendre possible la génération de phrases en utilisant les deux, donc je vais le mettre à la place d'un mémo. Eh bien, si vous voulez l'utiliser ensemble, je pense que vous pouvez le réécrire vous-même, donc ce n'est vraiment qu'un mémo ...
Janome et markovify peuvent être installés avec pip install ''. (
Pip3 '' selon l'environnement)
Tout d'abord. Pour la partie textGen, Référence 1 est détournée à plus de la moitié.
janomeGen.py
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from janome.tokenizer import Tokenizer
import markovify
def split(text):
#Sauts de ligne, espaces, remplacement de caractères problématiques
table = str.maketrans({
'\n': '',
'\r': '',
'(': '(',
')': ')',
'[': '[',
']': ']',
'"':'”',
"'":"’",
})
text = text.translate(table)
t = Tokenizer()
result = t.tokenize(text, wakati=True)
#Examinez chaque élément du formulaire, insérez un espace demi-largeur entre eux et insérez un saut de ligne à la fin de la phrase.
splitted_text = ""
for i in range(len(result)):
splitted_text += result[i]
if result[i] != '。' and result[i] != '!' and result[i] != '?':
splitted_text += ' '
if result[i] == '。' or result[i] == '!' or result[i] == '?':
splitted_text += '\n'
return splitted_text
def textGen(file):
f = open(file, 'r', encoding="utf-8")
text = f.read()
sentence = None
while sentence == None: #Des phrases vides peuvent être générées en fonction du matériau, donc des contre-mesures
#Diviser en un formulaire qui peut traiter du texte
splitted_text = split(text)
#Génération de modèle
text_model = markovify.NewlineText(splitted_text, state_size=3)
#Générer des phrases basées sur le modèle
sentence = text_model.make_sentence()
#Sauvegarde des données d'entraînement
with open('learned_data.json', 'w') as f:
f.write(text_model.to_json())
#Lors de la réutilisation des données
"""
with open('learned_data.json') as f:
text_model = markovify.NewlineText.from_json(f.read())
"""
#Renvoie sous la forme d'une série de chaînes combinées
return ''.join(sentence.split())
Ci-dessous, nous les examinerons dans l'ordre.
table = str.maketrans({
'\n': '',
'\r': '',
'(': '(',
')': ')',
'[': '[',
']': ']',
'"':'”',
"'":"’",
})
text = text.translate(table)
Remplacez certains caractères pour que markovify puisse être lu. Puisque les sauts de ligne et les espaces sont respectivement utilisés pour indiquer les sauts de phrase et les sauts de mots, ils sont supprimés une fois (les phrases japonaises mélangées avec des phrases anglaises ne peuvent pas être traitées correctement, mais cette fois elles sont ignorées).
Remplacez également les "mauvais caractères", qui affectent le fonctionnement de markovify, par des caractères inoffensifs pleine largeur. (Depuis markovify v0.7.2, vous pouvez spécifier s'il faut ignorer les phrases contenant des caractères incorrects avec le paramètre well_formed de markovify.Text, mais il est inutile d'ignorer la phrase entière, elle est donc remplacée à l'avance.)
t = Tokenizer()
result = t.tokenize(text, wakati=True)
splitted_text = ""
for i in range(len(result)):
splitted_text += result[i]
if result[i] != '。' and result[i] != '!' and result[i] != '?':
splitted_text += ' '
if result[i] == '。' or result[i] == '!' or result[i] == '?':
splitted_text += '\n'
Ce que vous faites est presque le même que l'article de référence 1, il est donc plus juste d'y faire référence.
Si vous tokenize comme ça avec le Tokenizer de Janome, il sera renvoyé sous forme de liste séparée par morphologie.
Si "je mange une pomme", alors `['je', 'est', 'pomme', 'est', 'une', 'mange', '. Cela ressemble à ']
. C'est plus facile et plus pratique que MeCab pour ceux qui ne veulent que le corps principal de la morphologie.
Cette fois, lisez les éléments morphologiques un par un pour que markovify puisse les lire, divisez-les par un espace demi-largeur, et lorsqu'ils arrivent à la fin de la phrase, séparez-les par un saut de ligne (comme la phrase anglaise). Dans l'article de référence, je l'ai coupé uniquement avec des signes de ponctuation, mais cette fois! Quand? Mais j'ai essayé de le couper. La façon de diviser les points de lecture dépend de votre préférence, mais ici nous les avons divisés en un seul mot. Si vous voulez le rendre similaire à l'anglais, remplacez l'instruction if
if i+1 < len(result):
if result[i] != '。' and result[i] != '!' and result[i] != '?' and result[i+1] != '、':
splitted_text += ' '
if result[i] == '。' or result[i] == '!' or result[i] == '?':
splitted_text += '\n'
else:
if result[i] != '。' and result[i] != '!' and result[i] != '?':
splitted_text += ' '
if result[i] == '。' or result[i] == '!' or result[i] == '?':
splitted_text += '\n'
Si vous le réécrivez d'une manière ou d'une autre, cela devrait fonctionner. peut être.
def textGen(file):
f = open(file, 'r', encoding="utf-8")
text = f.read()
sentence = None
while sentence == None: #Aucun ne peut être retourné en fonction du matériau, donc contre-mesures
#Diviser en un formulaire qui peut traiter du texte
splitted_text = split(text)
#Génération de modèle
text_model = markovify.NewlineText(splitted_text, state_size=3)
#Générer des phrases basées sur le modèle
sentence = text_model.make_sentence()
#Sauvegarde des données d'entraînement
with open('learned_data.json', 'w') as f:
f.write(text_model.to_json())
#Renvoie sous la forme d'une série de chaînes combinées
return ''.join(sentence.split())
Cette fois, je l'ai écrit pour la génération à partir de quelque chose qui n'est pas Aozora Bunko, alors j'omets le traitement pour cela et je le lis simplement. Puisqu'il s'agit d'une procédure standard pour markovify, autre que cela, elle suit à peu près la référence 1.
De plus, None peut parfois être retourné en raison de state_size et de la quantité de texte matériel (markovify Issue # 96, [Issue # 22]. ](Https://github.com/jsvine/markovify/issues/22)), donc je l'ai retourné jusqu'à ce que je retourne facilement quelque chose qui n'est pas None. Je ne pense pas que ce sera une boucle infinie s'il y a une certaine quantité de texte.
De plus, il est possible de le traiter dans une certaine mesure en spécifiant le nombre d'essais avec le mot-clé argument essais de make_sentence. (Code ci-dessous)
#Diviser en un formulaire qui peut traiter du texte
splitted_text = split(text)
#Génération de modèle
text_model = markovify.NewlineText(splitted_text, state_size=3)
#Générer des phrases basées sur le modèle
sentence = text_model.make_sentence(tries=100)
Pour les tests, de Bochan d'Aozora Bunko à [delruby.exe](https://www.aokids.jp/others/ J'ai supprimé le ruby en utilisant delruby.html) et j'ai essayé de le générer en fonction de celui qui exclut les parties inutiles.
- Si vous pensez qu'il manque une personne, tout le monde dans le monde est comme cet élève, celui qui n'aime pas les insectes est gentil et élégant, mais il n'y a pas d'autre choix que de venir avec un pauvre homme, alors faites une voix forte Je vais l'éteindre.
Il semble que le but a été atteint.
Janome et MeCab ont des fonctions similaires dans le sens où ils effectuent une analyse morphologique japonaise, j'ai donc pu les implémenter avec seulement une réécriture mineure. Il semble qu'il puisse être utilisé lors de la création d'un Bot.
Recommended Posts