Une histoire sur la création d'une courte chanson par hasard avec Sudachi Py

Qu'est-ce qu'une chanson courte par hasard?

C'est twitter bot qui extrait et publie la partie qui se trouve être 57757 du texte de wikipedia. Ici a été créé en 2015. L'original semble être fait de rubis + MeCab, donc cette fois je vais le réimprimer avec Python et Sudachi. Merci et respect pour vos aînés.

environnement

Windows10 Home (64bit)

python 3.7.4 SudachiDict-full==20191224 SudachiPy==0.4.2

L'environnement a été construit avec pipenv

Pourquoi Sudachi

Dans Sudachi, vous pouvez spécifier le mode de division et vous pouvez décomposer les pièces en une unité aussi grande que possible. Si vous utilisez MeCab, il sera décomposé en tout petits morceaux, il est donc possible que des divisions étranges telles que "Tokyo Sky" dans la phrase supérieure et "Tree" dans la phrase inférieure soient prises en compte. Sudachi réduit ce risque.

Ci-dessous, à partir du GitHub de Sudachi.

Mode Split Sudachi propose trois modes split, A, B et C, en commençant par le plus court. A est équivalent à l'unité courte UniDic, C est équivalent à l'expression propre et B est une unité intermédiaire entre A et C.

Un exemple est présenté ci-dessous.

(Lors de l'utilisation du dictionnaire principal)

A: Élection / Gestion / Comité / Réunion B: Élection / Administration / Comité C: Commission électorale

A: Chambre d'hôtes / équipage / personnel B: Chambre d'hôtes / équipage C: Équipage chambre d'hôtes

C'est une sensation, mais l'emboîtement A est à peu près le même que MeCab.

Installation de SudachiPy

Installez SudachiPy et le dictionnaire en vous référant à GitHub of SudachiPy Il existe trois types de dictionnaires: petit, principal et complet. Cette fois, j'ai installé un dictionnaire complet avec beaucoup de vocabulaire.

pip install SudachiPy
pip install https://object-storage.tyo2.conoha.io/v1/nc_2520839e1f9641b08211a5c85243124a/sudachi/SudachiDict_full-20191224.tar.gz

Lier le dictionnaire

En ce qui concerne le dictionnaire, il semble y avoir une méthode à spécifier à partir de json dans la source et une méthode pour lier le dictionnaire par défaut à partir de la commande. Cette fois, j'ai choisi ce dernier. Je ne l'ai pas écrit dans le document, mais quand je l'ai fait normalement, j'ai eu une erreur d'autorisation, alors exécutez la commande suivante ** à partir d'une invite avec des privilèges d'administrateur. Hamari pointe ici. (Ce qui se passe sous Linux et Mac n'est pas confirmé.)

sudachipy link -t full

Code source

Depuis que je l'ai fait de manière lâche, il peut y avoir une partie absurde dans la façon de le faire. Je pense que oui. Les modes sont divisés pour que les haïkus et les chansons courtes puissent être détectés. Dans un premier temps, l'approche était d'extraire une phrase de 31 sons et de voir si ce serait 57757. Mais quand je l'ai essayé, cela n'a pas été détecté du tout, j'ai donc rendu possible la recherche ne serait-ce qu'une partie d'une longue phrase et l'ai commutée avec le drapeau setting.precision. Le premier quand vous en voulez un propre avec moins de bruit, le second quand vous voulez un numéro quand même.

La politique de base est de compter les lectures tout en définissant un drapeau et d'extraire celles dont les coupures sonores s'inscrivent dans 57757. Rejeter lorsqu'il devient 579 ou 57578. Si un mot auxiliaire ou un verbe auxiliaire vient au début d'une phrase, il est également rejeté. Supprimez la partie principale du texte et recherchez à nouveau De plus, [ya, u, yo] etc. ne sont pas comptés comme le nombre de sons. J'utilise importlib parce que je l'ai finalement transformé en un exe avec pyinstaller.

search_tanka.py


import re
import importlib
from sudachipy import tokenizer
from sudachipy import dictionary

setting = importlib.import_module('setting')
tokenizer_obj = dictionary.Dictionary().create()
#Réglez l'unité de division sur la plus longue
split_mode = tokenizer.Tokenizer.SplitMode.C
#Chemin du fichier texte à lire
searchfile_path = "./search_text/" + setting.search_file_name
#Le chemin du fichier texte à exporter
savefile_path = "./result_text/" + setting.save_file_name
#Changement de mode entre haïku et chansons courtes
if setting.mode == 1:
    break_points = [5, 12, 17]
else:
    break_points = [5, 12, 17, 24, 31]
#Expression régulière katakana
re_katakana = re.compile(r'[\u30A1-\u30F4]+')

#Fichier texte ouvert
with open(searchfile_path, encoding="utf-8_sig") as f:
    #Lire toutes les lignes et la liste
    areas = f.readlines()
    for line in areas:
        # "。"Ou"."Ou séparez-vous avec un saut de ligne
        sentences = re.split('[.。\n]', line)
        for sentence in sentences:
            #À travers lors de la recherche par phrase
            if setting.precision == 1:
                pass
            #Les chansons courtes, les haïkus et les phrases contenant plus de chaque caractère ne sont pas détectés.
            else:
                if len(sentence) > break_points[-1]:
                    continue

            #Analyse morphologique
            m = tokenizer_obj.tokenize(sentence, split_mode)
            #Cast Morpheme List dans la liste
            m = list(m)

            retry = True
            while retry:
                break_point_header_flag = True
                retry = False
                counter = 0
                break_point_index = 0
                reading = ""
                surface = ""
                #Déterminer si la phrase est coupée à chaque saut de phrase
                for mm in m:
                    if break_point_header_flag == True:
                        text_type = mm.part_of_speech()[0]
                        #Si le début de chaque phrase n'est pas une partie appropriée, il ne sera pas détecté.
                        if text_type in setting.skip_text_type:
                            #Rechercher à nouveau si la recherche longue est activée
                            if setting.precision == 1:
                                retry = True
                                del m[0]
                                break
                            else:
                                counter = 0
                                break
                        else:
                            break_point_header_flag = False
                    #Analyser les lectures
                    reading_text = mm.reading_form()
                    surface_text = mm.surface()
                    if len(reading_text) > 7:
                        #Rechercher à nouveau si la recherche longue est activée
                        if setting.precision == 1:
                            retry = True
                            del m[0]
                            break
                        else:
                            counter = 0
                            break
                    #Si le résultat de l'analyse est un caractère qui doit être ignoré, ignorez-le
                    if reading_text in setting.skip_text:
                        sentence = sentence.replace(mm.surface(), "")
                        continue
                    #Étant donné que le nom de la personne de Katakana n'entre pas, complétez-le avec surface
                    if reading_text == "":
                        text_surface = mm.surface()
                        if re_katakana.fullmatch(text_surface):
                            reading_text = text_surface
                        #Ignorer si un kanji qui ne peut pas être lu dans le dictionnaire apparaît
                        else:
                            #Rechercher à nouveau si la recherche longue est activée
                            if setting.precision == 1:
                                retry = True
                                del m[0]
                                break
                            else:
                                counter = 0
                                break
                    #Compter le nombre d'éléments phonétiques en lecture
                    counter += len(reading_text)
                    reading = reading + reading_text
                    surface = surface + surface_text
                    #Moins le compte s'il y a un élément sonore compatible qui ne compte pas
                    for letter in setting.skip_letters:
                        if letter in reading_text:
                            counter -= reading_text.count(letter)
                    #Le décompte a-t-il progressé du nombre de caractères dans chaque phrase?
                    if counter == break_points[break_point_index]:
                        break_point_header_flag = True
                        #Si vous n'êtes pas arrivé à la fin, passez à la phrase suivante
                        if counter != break_points[-1]:
                            break_point_index += 1
                            reading = reading + " "
                    #Jouez lorsque le nombre de caractères spécifié dans chaque phrase est dépassé.
                    elif counter > break_points[break_point_index]:
                        #Rechercher à nouveau si la recherche longue est activée
                        if setting.precision == 1:
                            retry = True
                            del m[0]
                            break
                        else:
                            counter = 0
                            break

                #Choisissez celui qui peut être détecté exactement avec le nombre de caractères spécifié et ajoutez-le au fichier
                if counter == break_points[-1]:
                    with open(savefile_path, "a") as f:
                        try:
                            print(surface + " ")
                            print("(" + reading + ")" + "\n")
                            f.write(surface  + "\n")
                            f.write("(" + reading + ")" + "\n")
                            f.write("\n")
                        except Exception as e:
                            print(e)

                if len(m) < len(break_points):
                    break

setting.py


# mode (Mode de détection) 1:Haiku 2:Tanka
mode = 2
# precision (précision) 1:Faible 2:Haute
#Faible nombre de détections:Beaucoup,bruit:Beaucoup、実行時間:Haute
#Nombre élevé de détections:Petit,bruit:Petit、実行時間:Petit
precision = 1
#Caractères qui ne comptent pas comme phonèmes
skip_letters = ['Turbocompresseur','Yu','Yo']
#Fichiers à détecter
search_file_name = "jawiki-latest-pages-articles.xml-001.txt"
#Fichier pour enregistrer le résultat de la détection
save_file_name = "result.txt"
#Mots de partie qui ne devraient pas venir au début de la phrase
skip_text_type = ["Particule", "Verbe auxiliaire", "Suffixe", "Symbole auxiliaire"]
#Caractères non inclus dans la cible d'analyse
skip_text = ["、", "Kigo", "=", "・"]

Résultat d'exécution

Numérisé par rapport au texte de wikipedia. Quelques extraits ci-dessous.

Platon a changé de style à partir de la période moyenne sous l'influence d'Isocrate (Platon Haisokuratesunoeikyowoukechuukiyoribuntaiwokae)

Un monument au lieu de naissance de Shofu est érigé, ce qui serait le début. (Hajimarit Iwareshofu Hasshono Chinoishibumigata Terra Retail)

Un accent particulier sur la lignée, qui est une tradition individuelle d'un commun accord (Soushoni Okerukobetsuno Densho de Arketsumyakuwo Tokuniomonji)

Nuakshot a été construite comme une ville pour devenir la future capitale (Shorino Stoninalbeki Toshitoshite Nuakushotga Kensetsu Saleta)

Pêche au poulpe à la japonaise à l'aide d'un bocal avec la coopération du Japon (Nippon no Kyoryokuniyori Takotsubowo Tsukauni Nippon Shikinota Koryo)

Perspectives d'avenir

Si vous recommencez, je voudrais soutenir ce qui suit.

・ Concernant la lecture des nombres Avec Sudachi, il semble que la lecture des nombres ne fonctionne pas actuellement.

Exemple) C'était généralement entre 50 et 150 voitures. ↓ (Omuneha Gorei Ryokara Fraise Rei Ryo no Aida de Suiishitita)

Il y a un plan, mais la mise en œuvre est indécise. Il semble que nous puissions y faire face en essayant d'écrire un dictionnaire de plug-ins ou en supprimant uniquement les nombres avec des expressions régulières et en les analysant avec un autre moteur. (Cependant, c'est une autre histoire de savoir s'il sera possible d'extraire de bonnes chansons courtes en répondant ...) ・ Concernant la vitesse d'exécution Je m'y attendais, mais il est tard ... C'est un problème avec mon implémentation avant que Sudachi soit lent ou que Python soit lent. Pardon. Comme il est honnêtement tourné avec une instruction for, cela devrait être plus rapide si vous utilisez correctement itertools.

Impressions

Après tout, j'ai créé la source originale presque sans la regarder (Oi). Il y avait parfois du bruit ou quelque chose qui était coupé dans des endroits étranges, mais cela fonctionnait généralement correctement. Je pense que le travail de ramassage final reste le pouvoir humain. Comment tweetez-vous avec un robot ou récupérez-vous la source de la citation?

Beaucoup d'entre eux sont détectés, mais pour le moment, mon préféré est le suivant.

** Acte ennuyeux de copier et d'écrire plusieurs fois des leçons de contenu ** ** (Naiyouno Reswonandomo Kopipeshite Kakikomutoi Meiwakukoui) **

Eh bien.

Recommended Posts

Une histoire sur la création d'une courte chanson par hasard avec Sudachi Py
L'histoire de la création d'une partition de type Hanon avec Python
Une histoire sur un amateur faisant une rupture de bloc avec python (kivy) ②
Une histoire sur l'implémentation d'un écran de connexion avec django
Histoire de l'analyse de données par apprentissage automatique
J'ai essayé de créer un chargeur de démarrage x86 qui peut démarrer vmlinux avec Rust
Histoire de l'utilisation du jeton logiciel de Resona avec 1Password
Une histoire de prédiction du taux de change avec Deep Learning
Une histoire d'essayer un monorepo (Golang +) Python avec Bazel
L'histoire de la gestion de theano avec TSUBAME 2.0
Une histoire de compétition avec un ami dans Othello AI Preparation
Une histoire sur l'installation de matplotlib à l'aide de pip avec une erreur
L'histoire de la construction d'un serveur de cache PyPI (avec Docker) et de me rendre un peu heureux à nouveau
Une histoire sur une tragédie qui se passe en échangeant des commandes dans le chat
L'histoire de la création d'un bot de boîte à questions avec discord.py
Une histoire à propos d'un débutant en python coincé avec aucun module nommé'ttp.server '
Une histoire sur le développement d'un type logiciel avec Firestore + Python + OpenAPI + Typescript
L'histoire de la création d'un module qui ignore le courrier avec python
Une histoire rafraîchissante sur Slice en Python
Une histoire de mauvaise humeur sur Slice en Python
Une histoire épuisée par super (A, self)
L'histoire de l'utilisation de la réduction de Python
L'histoire de la création d'un robot LINE pour le petit-déjeuner d'une université de 100 yens avec Python
Une histoire sur l'automatisation du mahjong en ligne (Jakutama) avec OpenCV et l'apprentissage automatique
Une histoire sur un remodelage magique qui met Lubuntu dans un Chromebook
Une histoire sur Python pop and append
Une histoire que moi, un débutant en programmation, j'ai créé une application de cartographie d'efficacité commerciale avec GeoDjango
[Note] Une histoire sur l'impossibilité de percer le proxy avec pip
Une histoire sur la création d'un environnement IDE avec WinPython sur un ancien système d'exploitation Windows.
Zakuzaku automatique, Bitcoin. Une histoire sur un débutant en Python faisant un tableau de contrôle de pièces en 1 minute
L'histoire de la création d'une application Web qui enregistre des lectures approfondies avec Django
[Python] Une histoire sur la création d'un bot LINE avec une fonction humaine pratique sans utiliser Salesforce [API de messagerie]