[Python3] Génération automatique de texte avec janome et markovify

introduction

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.

but de fond

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 ...

Préparation

Janome et markovify peuvent être installés avec pip install ''. ( Pip3 '' selon l'environnement)

code

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.

Préparation du texte

    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.)

Texte fractionné

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.

Génération de phrases

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)   

Résultat de la génération

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.

Épilogue

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.

référence

  1. Apprenez des phrases japonaises avec markovify et générez des phrases par chaîne de Markov
  2. Comment apprendre des phrases et les générer automatiquement en utilisant [Python] MeCab et la bibliothèque de chaînes Markov markovify
  3. [Génération de phrases par le saladier Markov chain-Knowledge](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 /)

Recommended Posts

[Python3] Génération automatique de texte avec janome et markovify
Clustering et visualisation à l'aide de Python et CytoScape
[PyTorch] Génération de phrases japonaises à l'aide de Transformer
[Jouons avec Python] Viser la génération automatique de phrases ~ Achèvement de la génération automatique de phrases ~
[Jouons avec Python] Viser la génération automatique de phrases ~ Lisez .txt et faites-en une unité de phrase ~
Notes utilisant cChardet et python3-chardet dans Python 3.3.1.
Collecte automatique des cours boursiers à l'aide de python
De Python à l'utilisation de MeCab (et CaboCha)
Utilisation de Python et MeCab avec Azure Databricks
[Jouons avec Python] Viser la génération automatique de phrases ~ Effectuer une analyse morphologique ~
J'utilise tox et Python 3.3 avec Travis-CI
Estimation de l'orientation de la tête avec Python et OpenCV + dlib
J'ai essayé le web scraping en utilisant python et sélénium
Remarques sur l'installation de Python3 et l'utilisation de pip sous Windows7
Développer et déployer des API Python à l'aide de Kubernetes et Docker
Flux de développement Python avec Poetry, Git et Docker
J'ai essayé la détection d'objets en utilisant Python et OpenCV
Créer une carte Web en utilisant Python et GDAL
[Phrase courte] [Python] Formater et imprimer des listes et des dictionnaires
Essayez d'utiliser tensorflow ① Créez un environnement python et introduisez tensorflow
Génération de configuration de réseau de modèles avec Python et Jinja2
Essayez d'utiliser l'API ChatWork et l'API Qiita en Python
Commencez à utiliser Python
Génération automatique de mosaïques
Scraping à l'aide de Python
Paramètres initiaux pour l'utilisation de Python3.8 et pip sur CentOS8
Recherche de balises pixiv et enregistrement d'illustrations à l'aide de Python
Squelettes extensibles pour Vim utilisant Python, Click et Jinja2
Essayez de créer un fichier compressé en utilisant Python et zlib
Agréger les journaux Git à l'aide de Git Python et analyser les associations à l'aide d'Orange
Suivi automatique sur Twitter avec python et sélénium! (RPA)
Implémentation d'un générateur en utilisant Python> link> yield et next ()> yield
Obtenez et automatisez le contrôle ASP Datepicker à l'aide de Python et Selenium
Lire et écrire des balises NFC avec python en utilisant PaSoRi
Procédure de transcription vocale à l'aide de Python et de l'API Google Cloud Speech
Récupérer des fichiers depuis Linux en utilisant paramiko et scp [Python]
Serveur HTTP et client HTTP utilisant Socket (+ navigateur Web) --Python3