100 traitements de langage avec Python (chapitre 3)

introduction

Knock 100 language processing publié sur la page Web du laboratoire Inui-Okazaki de l'Université de Tohoku pour la formation au traitement du langage naturel et Python. Je vais contester nlp100 /). Je prévois de prendre note du code implémenté et des techniques à supprimer. Le code sera également publié sur GitHub.

excuse

Grâce à sauter pendant un moment, j'ai fini par écrire un article en lisant le code que j'avais écrit auparavant. Un style de «je suis une autre personne il y a trois jours» sur le terrain. Pendant ce temps, mon niveau de compétence a considérablement changé et je regardais mon code tout en me parlant. Il y a un écart entre les mises à jour, mais j'espère que vous pourrez l'utiliser comme une pierre d'une autre montagne.

Chapitre 3: Expressions régulières

Il existe un fichier jawiki-country.json.gz qui exporte les articles Wikipedia dans le format suivant.

Une information d'article par ligne est stockée au format JSON Dans chaque ligne, le nom de l'article est stocké dans la clé "title" et le corps de l'article est stocké dans l'objet dictionnaire avec la clé "text", et cet objet est écrit au format JSON. Le fichier entier est gzippé Créez un programme qui effectue le traitement suivant.

20. Lecture des données JSON

Lisez le fichier JSON de l'article Wikipedia et affichez le texte de l'article sur "UK". Dans les problèmes 21-29, exécutez sur le texte de l'article extrait ici.

Répondre

20.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 20.py

import json

with open("jawiki-country.json") as f:
    article_json = f.readline()
    while article_json:
        article_dict = json.loads(article_json)
        if article_dict["title"] == u"Angleterre":
            print(article_dict["text"])
        article_json = f.readline()

commentaire

Le jawiki-country.json.gz utilisé cette fois est de 9,9 Mo, ce qui est assez lourd, donc j'ai lu ligne par ligne avec readline () et seul l'article "UK" est print (les autres articles sont terminés). Je sens que l'opération s'arrêtera pendant un certain temps si je fais readlines (), et s'il y a un plus large éventail d'utilisations, je n'opérerai que pour les articles en "UK", donc je l'ai implémenté comme ça.

Dans ces données texte, chaque ligne du fichier est décrite au format JSON. Cependant, la simple lecture de (json.load ()) ne fonctionne pas bien et l'avantage de JSON ne peut pas être utilisé, j'ai donc utilisé json.loads () pour le convertir au format JSON (cette fois, c'est un vrai dictionnaire). Je vais.

modularisation

À partir de là, le travail d'extraction des seuls articles de "UK" se poursuivra pendant un certain temps, je l'ai donc modulaire comme suit.

extract_from_json.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# extract_from_json.py

import json


def extract_from_json(title):
    with open("jawiki-country.json") as f:
        json_data = f.readline()
        while json_data:
            article_dict = json.loads(json_data)
            if article_dict["title"] == title:
                return article_dict["text"]
            else:
                json_data = f.readline()
    return ""

Contrairement à «20.py», cette fonction renvoie la chaîne de caractères de l'article lorsque le titre est passé en argument (chaîne de caractères vide si elle n'existe pas).

21. Extraire les lignes contenant les noms des catégories

Extrayez la ligne qui déclare le nom de la catégorie dans l'article.

Répondre

21.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 21.py

from mymodule import extract_from_json

lines = extract_from_json(u"Angleterre").split("\n")

for line in lines:
    if "Category" in line:
        print(line)

#Avec python3, cela peut toujours être affiché (bien que ce soit une liste)
# print([line for line in lines if "Category" in line])

commentaire

Bien qu'il s'agisse d'un chapitre sur les expressions régulières, il n'utilise pas d'expressions régulières. Eh bien, celui-ci est plus facile à comprendre ... Par conséquent, seule la ligne contenant la chaîne de caractères «Category» est «print».

Si vous l'écrivez dans la notation d'inclusion, elle s'adaptera parfaitement, mais en Python2, si vous «imprimez» simplement une liste contenant des chaînes de caractères Unicode, elle sera échappée. Par conséquent, il n'est pas affiché sous une forme qui peut être lue en japonais. Ce code peut être exécuté en Python3, donc si vous l'exécutez en Python3, il sera bien traité.

22. Extraction du nom de la catégorie

Extraire les noms des catégories d'articles (par nom, pas ligne par ligne).

Répondre

22.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 22.py

import re
from mymodule import extract_from_json

lines = extract_from_json(u"Angleterre").split("\n")

for line in lines:
    category_line = re.search("^\[\[Category:(.*?)(|\|.*)\]\]$", line)
    if category_line is not None:
        print(category_line.group(1))

commentaire

Tout d'abord, extrayez la ligne de catégorie de la même manière qu'en 21., et extrayez-en uniquement le nom en utilisant re.search (). re.search () retourne une instanceMatchObject s'il y a une partie de la chaîne de caractères spécifiée par le deuxième argument qui correspond au modèle d'expression régulière du premier argument. En plus de ce à quoi ressemble MatchObject, vous pouvez utiliser .group () pour obtenir la chaîne correspondante. Dans ce cas, dans category_line.group (0), toute la chaîne de caractères correspondante (par exemple " [[Category: United Kingdom | *]] "), mais dans category_line.group (1), la première partie correspondante Vous obtiendrez une chaîne (par exemple ʻUK`).

Et bien que ce soit une expression régulière essentielle, les détails sont jetés dans le Document officiel, et des exemples d'adaptation spécifiques sont suivis sur cette page. J'aimerai essayer. Cliquez ici pour la ligne de catégorie à traiter cette fois (résultat d'exécution de 21.py)

22.Résultat d'exécution de py


$ python 22.py
[[Category:Angleterre|*]]
[[Category:Royaume du Royaume-Uni|*]]
[[Category:Pays membres du G8]]
[[Category:Pays membres de l'Union européenne]]
[[Category:Nation marine]]
[[Category:Pays souverain]]
[[Category:Pays insulaire|Kureito Furiten]]
[[Category:État / région créé en 1801]]

En gros, c'est [[Category: nom de la catégorie]], mais il y en a qui spécifient la lecture en séparant par |. Donc, en tant que politique,

Ce sera sous la forme de. Exprimer cela dans une expression régulière (je ne suis pas sûr que ce soit optimal) est " ^ \ [\ [Category: (. *?) (\ |. *) * \] \] $ ".

Intention Expression régulière réelle Commentaire
Premier[[Category:Commence par ^\[\[Category: ^Spécifiez le début avec
Une sorte de chaîne de caractères (nom de catégorie) vient (.*?) Correspondance la plus courte avec n'importe quelle chaîne
Dans certains cas|Le pseudonyme de lecture séparé par (\|.*)* (\|.*)*?Peut être plus approprié
finalement]]Serrez avec \]\]$ Indique la fin$Peut ne pas être nécessaire

23. Structure de la section

Affichez les noms de sections et leurs niveaux contenus dans l'article (par exemple, 1 si "== nom de section ==").

Répondre

23.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 23.py

import re
from mymodule import extract_from_json

lines = extract_from_json(u"Angleterre").split("\n")

for line in lines:
    section_line = re.search("^(=+)\s*(.*?)\s*(=+)$", line)
    if section_line is not None:
        print(section_line.group(2), len(section_line.group(1)) - 1)

commentaire

La structure de base est la même que 22., mais cette fois, le nom de la section (par exemple == section ==) est la cible, nous allons donc la récupérer. Puisqu'il y avait une légère fluctuation dans la notation (== section ==, == section ==), un caractère d'espacement \ s est inséré entre eux afin qu'il puisse être absorbé. Puisque le niveau de section correspond à la longueur de == (== 1 ==, === 2 ===, ...), il est calculé en acquérant la longueur et -1. Il est.

24. Extraction des références de fichiers

Extrayez tous les fichiers multimédias référencés dans l'article.

Répondre

24.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 24.py

import re
from mymodule import extract_from_json

lines = extract_from_json(u"Angleterre").split("\n")

for line in lines:
    file_line = re.search(u"(File|Fichier):(.*?)\|", line)
    if file_line is not None:
        print(file_line.group(2))

commentaire

Au départ, seuls ceux commençant par File: étaient extraits ... stupide.

C'est ʻUnicodeparce que le japonais est inclus dans le modèle d'expression régulière, mais il semble que cela soit autorisé dans le modèle d'expression régulière Python. Je vois souvent des exemples de chaînes brutes commer" hogehoge ", mais au moins cela ne me semble pas indispensable, car cela empêche le processus d'échappement de se dupliquer et de devenir difficile à lire? De plus, si vous voulez réutiliser le modèle d'expression régulière à plusieurs reprises, il semble plus efficace de compiler en utilisant re.compile ()`. Cependant, le dernier modèle d'expression régulière utilisé est mis en cache, vous n'avez donc pas à vous en préoccuper cette fois.

25. Extraction de modèles

Extraire les noms de champs et les valeurs du modèle "informations de base" inclus dans l'article et les stocker sous forme d'objet dictionnaire.

Répondre

25.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 25.py

import re
from mymodule import extract_from_json

temp_dict = {}
lines = re.split(r"\n[\|}]", extract_from_json(u"Angleterre"))

for line in lines:
    temp_line = re.search("^(.*?)\s=\s(.*)", line, re.S)
    if temp_line is not None:
        temp_dict[temp_line.group(1)] = temp_line.group(2)

for k, v in sorted(temp_dict.items(), key=lambda x: x[1]):
    print(k, v)

commentaire

Le modèle ~~ est inclus sous la forme «| nom du modèle = contenu du modèle», c'est donc une expression régulière qui lui correspond. Comme mentionné ci-dessus, si vous écrivez ^ \ | (. *?) \ S = \ s (. *), La première parenthèse est le nom du modèle et la deuxième parenthèse est le contenu du modèle, alors mettez-le dans le dictionnaire. Il est stocké. ~~

Fondamentalement, le modèle est stocké ** dans chaque ligne ** sous la forme de «| nom du modèle = contenu du modèle», mais le nom officiel du pays était un peu gênant.

Nom officiel du pays


|Nom officiel du pays= {{lang|en|United Kingdom of Great Britain and Northern Ireland}}<ref>Nom officiel du pays autre que l'anglais:<br/>
*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}([[Gaélique écossais]])<br/>
*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}([[Pays de Galles]])<br/>
*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}([[irlandais]])<br/>
*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}([[Cornouailles]])<br/>
*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}([[Écossais]])<br/>
**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(Ulster écossais)</ref>

Comme mentionné ci-dessus, il s'étend sur plusieurs lignes, y compris les sauts de ligne (caractère = \ n), il est donc nécessaire de bien gérer cette zone.

Après tout

Il a été fait par divers essais et erreurs.

J'ai utilisé for loop to print pour vérifier le contenu, mais Python3 est également recommandé. Python3 est utile pour une raison quelconque ...

26. Suppression du balisage en surbrillance

Au moment du traitement> 25, supprimez le balisage d'accentuation MediaWiki (tout accent faible, accentuation et accentuation forte) de la valeur du modèle et convertissez-le en texte (Référence: [Markup Quick Reference](https: // ja. wikipedia.org/wiki/Help: tableau de référence rapide)).

Répondre

26.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 26.py

import re
from mymodule import extract_from_json

temp_dict = {}
lines = re.split(r"\n[\|}]", extract_from_json(u"Angleterre"))

for line in lines:
    temp_line = re.search("^(.*?)\s=\s(.*)", line, re.S)
    if temp_line is not None:
        temp_dict[temp_line.group(1)] = re.sub(r"'{2,5}", r"", temp_line.group(2))

# 25.Voir Python3 ainsi que py
for k, v in sorted(temp_dict.items(), key=lambda x: x[1]):
    print(k, v)

commentaire

re.sub est une fonction qui remplace la partie qui correspond à l'expression régulière. Cette fois, j'écris pour effacer 2 ou plus et 5 ou moins s. Si vous écrivez `{n, m}`, vous pouvez exprimer le caractère précédent comme n ou plus et m ou moins dans une expression régulière. ~~ Eh bien, j'ai l'impression que j'aurais dû supprimer tout purement cette fois ... ~~

27. Suppression des liens internes

En plus du traitement 26, supprimez le balisage de lien interne de MediaWiki de la valeur du modèle et convertissez-le en texte (Référence: [Markup Quick Reference](https://ja.wikipedia.org/wiki/Help :) Graphique simplifié)).

Répondre

27.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 27.py

import re
from mymodule import extract_from_json


def remove_markup(str):
    str = re.sub(r"'{2,5}", r"", str)
    str = re.sub(r"\[{2}([^|\]]+?\|)*(.+?)\]{2}", r"\2", str)
    return str

temp_dict = {}
lines = extract_from_json(u"Angleterre").split("\n")

for line in lines:
    category_line = re.search("^\|(.*?)\s=\s(.*)", line)
    if category_line is not None:
        temp_dict[category_line.group(1)] = remove_markup(category_line.group(2))

for k, v in sorted(temp_dict.items(), key=lambda x: x[0]):
    print(k, v)
    

commentaire

J'ai créé une fonction remove_markup () qui supprime les balises.

numéro de ligne Cible à supprimer
La première ligne Emphasis (similaire à 26)
2e ligne Lien interne

Comment écrire des liens internes

Il existe trois types, mais tous sont conformes à la règle selon laquelle "le nom de l'article commence par [[ et se termine par un symbole (]], |, #) ". J'ai écrit une expression régulière.

28. Suppression du balisage MediaWiki

En plus du traitement de> 27, supprimez autant que possible le balisage MediaWiki de la valeur du modèle et formatez les informations de base du pays.

Répondre

28.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 28.py

import re
from mymodule import extract_from_json


def remove_markup(str):
    str = re.sub(r"'{2,5}", r"", str)
    str = re.sub(r"\[{2}([^|\]]+?\|)*(.+?)\]{2}", r"\2", str)
    str = re.sub(r"\{{2}.+?\|.+?\|(.+?)\}{2}", r"\1 ", str)
    str = re.sub(r"<.*?>", r"", str)
    str = re.sub(r"\[.*?\]", r"", str)
    return str

temp_dict = {}
lines = extract_from_json(u"Angleterre").split("\n")

for line in lines:
    temp_line = re.search("^\|(.*?)\s=\s(.*)", line)
    if temp_line is not None:
        temp_dict[temp_line.group(1)] = remove_markup(temp_line.group(2))

for k, v in sorted(temp_dict.items(), key=lambda x: x[0]):
    print(k, v)

commentaire

En plus de 27

numéro de ligne Cible à supprimer
La première ligne Emphasis (similaire à 26)
2e ligne Lien interne (identique à 27)
3e ligne Notation avec la langue spécifiée (mais pas dans le tableau de balisage)
4ème ligne commentaire
5ème ligne Lien externe

Réécriture de remove_markup () pour supprimer.

29. Obtenez l'URL de l'image du drapeau

Utilisez le contenu du modèle pour obtenir l'URL de l'image du drapeau. (Astuce: appelez imageinfo dans l'API MediaWiki pour convertir les références de fichiers en URL)

Répondre

29.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 29.py

import re
import requests
from mymodule import extract_from_json


def json_search(json_data):
    ret_dict = {}
    for k, v in json_data.items():
        if isinstance(v, list):
            for e in v:
                ret_dict.update(json_search(e))
        elif isinstance(v, dict):
            ret_dict.update(json_search(v))
        else:
            ret_dict[k] = v
    return ret_dict


def remove_markup(str):
    str = re.sub(r"'{2,5}", r"", str)
    str = re.sub(r"\[{2}([^|\]]+?\|)*(.+?)\]{2}", r"\2", str)
    str = re.sub(r"\{{2}.+?\|.+?\|(.+?)\}{2}", r"\1 ", str)
    str = re.sub(r"<.*?>", r"", str)
    str = re.sub(r"\[.*?\]", r"", str)
    return str

temp_dict = {}
lines = extract_from_json(u"Angleterre").split("\n")

for line in lines:
    temp_line = re.search("^\|(.*?)\s=\s(.*)", line)
    if temp_line is not None:
        temp_dict[temp_line.group(1)] = remove_markup(temp_line.group(2))

url = "https://en.wikipedia.org/w/api.php"
payload = {"action": "query",
           "titles": "File:{}".format(temp_dict[u"Image du drapeau"]),
           "prop": "imageinfo",
           "format": "json",
           "iiprop": "url"}

json_data = requests.get(url, params=payload).json()

print(json_search(json_data)["url"])

commentaire

Comment puis-je accéder à l'API en Python? Quand je l'ai recherché, c'était assez compliqué ...

... Eh bien, d'après la conclusion, il semble que les «requêtes» soient recommandées. Documentation officielle pour Python 3

Pour une interface client HTTP de niveau supérieur, le package Requests est recommandé.

Ou, Documents officiels pour les demandes

Requêtes: HTTP pour les humains (Omis) Le module urllib2 standard de Python a la plupart des fonctionnalités HTTP requises, mais l'API ne fonctionne pas correctement.

«Requests» est recommandé pour le texte fort.

Pour plus de détails sur son utilisation, reportez-vous au document officiel, mais cette fois, j'ai reçu le résultat de la frappe de l'API en JSON et je l'ai traité. La structure du JSON renvoyé était compliquée, j'ai donc cherché partout et vérifié la partie où l'URL était écrite.

en conclusion

Passez au chapitre 4.

Recommended Posts

100 traitements de langage avec Python
100 traitements de langage avec Python (chapitre 3)
100 traitements de langage avec Python (chapitre 2, partie 2)
100 traitements de langage avec Python (chapitre 2, partie 1)
100 coups de traitement du langage avec Python 2015
100 Language Processing Knock Chapitre 1 (Python)
100 Language Processing Knock Chapitre 2 (Python)
100 Language Processing Knock Chapitre 1 en Python
100 Language Processing Knock Chapitre 1 par Python
100 Language Processing Knock 2020 Chapitre 1
100 Traitement du langage Knock Chapitre 1
100 Language Processing Knock 2020 Chapitre 3
100 Language Processing Knock 2020 Chapitre 2
J'ai fait 100 traitements linguistiques Knock 2020 avec GiNZA v3.1 Chapitre 4
100 Language Processing Knock 2020 Chapitre 4: Analyse morphologique
100 Language Processing Knock 2020 Chapitre 9: RNN, CNN
100 coups de traitement linguistique (2020): 28
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 3
[Chapitre 5] Introduction à Python avec 100 coups de traitement du langage
100 Language Processing Knock: Chapitre 1 Mouvement préparatoire
100 Language Processing Knock 2020 Chapitre 6: Apprentissage automatique
100 Traitement du langage Knock Chapitre 4: Analyse morphologique
100 Language Processing Knock 2020 Chapitre 10: Traduction automatique (90-98)
100 Language Processing Knock 2020 Chapitre 5: Analyse des dépendances
[Chapitre 3] Introduction à Python avec 100 coups de traitement du langage
100 Traitement du langage Knock 2020 Chapitre 7: Vecteur de mots
100 Language Processing Knock 2020 Chapitre 8: Neural Net
Le débutant en Python a essayé 100 traitements de langage Knock 2015 (05 ~ 09)
100 coups de traitement linguistique (2020): 38
[Chapitre 2] Introduction à Python avec 100 coups de traitement du langage
Réhabilitation des compétences Python et PNL à partir de "100 Language Processing Knock 2015" (Chapitre 1)
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 1
100 traitement de la langue frapper 00 ~ 02
100 Language Processing Knock 2020 Chapitre 1: Mouvement préparatoire
100 Language Processing Knock 2020 Chapitre 3: Expressions régulières
100 Language Processing Knock 2015 Chapitre 4 Analyse morphologique (30-39)
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 2
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 4
[Chapitre 4] Introduction à Python avec 100 coups de traitement du langage
Le débutant en Python a essayé 100 traitements de langage Knock 2015 (00 ~ 04)
Traitement d'image par Python 100 knock # 10 filtre médian
3. Traitement du langage naturel par Python 2-1. Réseau de co-occurrence
Traitement d'image par Python 100 knock # 12 motion filter
3. Traitement du langage naturel par Python 1-1. Word N-gram
[Programmeur nouveau venu "100 language processing knock 2020"] Résoudre le chapitre 1
Traitement du langage 100 knocks-88: 10 mots à haute similitude
100 traitements linguistiques Knock 2020 [00 ~ 39 réponse]
100 langues de traitement knock 2020 [00-79 réponse]
100 traitements linguistiques Knock 2020 [00 ~ 69 réponse]
Réhabilitation des compétences Python et PNL à partir de «Knock 100 Language Processing 2015» (chapitre 2 deuxième semestre)
Réhabilitation des compétences Python et PNL à partir de "100 Language Processing Knock 2015" (Chapitre 2 premier semestre)
100 coups de traitement du langage amateur: 17
100 traitements linguistiques Knock 2020 [00 ~ 49 réponse]
Python: traitement du langage naturel
100 coups de traitement du langage ~ Chapitre 1
100 coups de langue amateur: 07
Le traitement de 100 langues frappe le chapitre 2 (10 ~ 19)
Traitement d'image avec Python
100 coups de traitement du langage amateur: 09
100 coups en traitement du langage amateur: 47
Traitement 100 langues knock-53: Tokenisation