[PYTHON] Enquêter sur les verbes irréguliers anglais avec Wiktionary

Vous pouvez maintenant étudier le texte intégral du Wiktionnaire en 1 minute environ. À titre d'exemple pour extraire des informations significatives, nous étudierons les verbes irréguliers en anglais.

Ceci est une série d'articles.

  1. Explorer des méthodes de traitement efficaces pour Wiktionary
  2. Comparez la vitesse de traitement de Wiktionnaire entre F # et Python
  3. Enquêter sur les verbes irréguliers en anglais avec le Wiktionnaire ← Cet article

Le script de cet article est publié dans le référentiel suivant.

Aperçu

Comme il est difficile de saisir l'intégralité des données de vidage énormes, nous allons les réduire grossièrement et procéder au traitement.

Tout d'abord, lisez le texte intégral et collectez des informations verbales.

Analysez les informations obtenues et supprimez les verbes réguliers en plusieurs étapes.

Information verbale

Prenons un exemple pour voir comment les variantes des verbes anglais sont stockées.

Verb

see (third-person singular simple present sees, present participle seeing, simple past saw or (dialectal) seen or (dialectal) seent or (dialectal) seed, past participle seen or (dialectal) seent or (dialectal) seed)

Comme il est écrit en phrases et qu'il existe également d'autres formes d'informations telles que diallectales, il semble difficile de les analyser par programme.

Si vous vérifiez la source, elle est dans un format facile à gérer.

====Verb====
{{en-verb|sees|seeing|saw|past2=seen|past2_qual=dialectal|past3=seent|past3_qual=dialectal|past4=seed|past4_qual=dialectal|seen|past_ptc2=seent|past_ptc2_qual=dialectal|past_ptc3=seed|past_ptc3_qual=dialectal}}

Il semble que vous puissiez ignorer des informations supplémentaires telles que past2 =. Les informations suivantes demeurent.

{{en-verb|sees|seeing|saw|seen}}

Le formulaire original semble provenir du titre de la page.

Titre

J'ai confirmé le cap entouré d'égal à égal.

Il n'y a aucun cas où le nombre d'égaux ne correspond pas à gauche et à droite, mais il semble qu'il puisse y avoir des espaces.

[Exemple] Les espaces sont indiqués par des traits de soulignement.

Il semble que la hiérarchie des rubriques ne soit pas toujours unifiée.

scénario

Implémenté en Python.

Extrayez le titre, l'identifiant et le texte comme informations sur la page.

def getpages(bz2data):
    xml = bz2.decompress(bz2data).decode("utf-8")
    pages = ET.fromstring(f"<pages>{xml}</pages>")
    for page in pages:
        if int(page.find("ns").text) == 0:
            title = page.find("title").text
            id = int(page.find("id").text)
            with io.StringIO(page.find("revision/text").text) as text:
                yield id, title, text

Divisez le «texte» par motif.

def splittext(pattern, text):
    line = next(text, "")
    while line:
        m = pattern.match(line)
        line = next(text, "")
        if m:
            def g():
                nonlocal line
                while line and not pattern.match(line):
                    yield line
                    line = next(text, "")
            yield m[1].strip(), g()

Récupérez le {{en-verb ...}} à ==== Verb ==== de == English ==. Excluez les mots-clés contenant des espaces ou des traits d'union en tant que mots composés ou mots composés.

def en_verb(args):
    target, pos, length = args
    with open(target, "rb") as f:
        f.seek(pos)
        bz2data = f.read(length)
    pattern1 = re.compile("==([^=].*)==")
    pattern2 = re.compile("===+([^=].*?)===")
    result = []
    for id, title, text in getpages(bz2data):
        if " " in title or "-" in title: continue
        for lang, text2 in splittext(pattern1, text):
            if lang != "English": continue
            for subsub, text3 in splittext(pattern2, text2):
                if subsub != "Verb": continue
                for line in text3:
                    if line.startswith("{{en-verb"):
                        result.append((id, title, line.strip()))
                        break
    return result

Ajoutez à cela un traitement parallèle et une sortie de fichier. J'ai mis tout le script ci-dessous.

Exécutez le script et vérifiez le nombre de lignes de données de sortie.

Résultat d'exécution


$ time python en-verb.py
6,861 / 6,861

real    1m50.159s
user    13m53.906s
sys     0m17.438s
$ wc -l en-verb.tsv
31334 en-verb.tsv

Mise en forme des données

Formatez les données acquises de manière à ce qu'elles soient faciles à traiter.

Supprimer les liens et les commentaires

Si vous regardez les données acquises, vous trouverez des liens et des commentaires.

$ grep "\[" en-verb.tsv | head -n 2
4109    U-turn  {{en-verb|head=[[U]]-[[turn]]|U-turns|U-turning|U-turned}}
5661    read    {{en-verb|reads|reading|[[:en:#Etymology_2|read]]|[[:en:#Etymology_2|read]]|past_ptc2=readen|past_ptc2_qual=archaic, dialectal}}
$ grep '<!--' en-verb.tsv | head -n 2
5443    sing    {{en-verb|sings|singing|sang|sung|past_ptc2=sungen|past_ptc2_qual=archaic}}<!--Sang or sung for preterite, according to AHD.-->
6959    hide    {{en-verb|hides|hiding|hided}}<!--not hid, hidden!-->

Supprimez les parenthèses et les commentaires sur le lien. Avec un lien[[:en:#Etymology_2|read]]À l'intérieur comme|Ce qui est séparé par est le dernier élément (dans cet exempleread) Est laissé.

en-verb-2.py


import re, sys
pattern1 = re.compile("\[\[(.+?)\]\]")
pattern2 = re.compile("<!--(.*?)-->")
for line in sys.stdin:
    while (m := pattern1.search(line)):
        data = m[1].split("|")
        line = line[:m.start()] + data[-1] + line[m.end():]
    sys.stdout.write(pattern2("", line))

Résultat d'exécution


$ python en-verb-2.py < en-verb.tsv > en-verb-2.tsv
$ diff -U 0 en-verb.tsv en-verb-2.tsv | head -n 8
--- en-verb.tsv 2020-06-12 21:22:01.943343500 +0900
+++ en-verb-2.tsv       2020-06-12 21:22:54.506793900 +0900
@@ -747 +747 @@
-5443   sing    {{en-verb|sings|singing|sang|sung|past_ptc2=sungen|past_ptc2_qual=archaic}}<!--Sang or sung for preterite, according to AHD.-->
+5443   sing    {{en-verb|sings|singing|sang|sung|past_ptc2=sungen|past_ptc2_qual=archaic}}
@@ -763 +763 @@
-5661   read    {{en-verb|reads|reading|[[:en:#Etymology_2|read]]|[[:en:#Etymology_2|read]]|past_ptc2=readen|past_ptc2_qual=archaic, dialectal}}
+5661   read    {{en-verb|reads|reading|read|read|past_ptc2=readen|past_ptc2_qual=archaic, dialectal}}

Suppression d'informations supplémentaires

Des informations supplémentaires telles que past_ptc2 = readen en lecture sont nécessaires si vous regardez des dialectes ou des documents plus anciens, mais cette fois, nous les supprimerons. Supprimez toute autre information après «}}».

en-verb-3.py


import re, sys
pattern1 = re.compile("{{(.*?)}}")
pattern2 = re.compile("[a-z0-9_]+?=")
for line in sys.stdin:
    if (m := pattern1.search(line)):
        data = [d for d in m[1].split("|") if not pattern2.match(d)]
        line = line[:m.start()] + "{{" + "|".join(data) + "}}\n"
    sys.stdout.write(line)

Résultat d'exécution


$ python en-verb-3.py < en-verb-2.tsv > en-verb-3.tsv
$ diff -U 0 en-verb-2.tsv en-verb-3.tsv | head -n 8
--- en-verb-2.tsv       2020-06-12 21:22:54.506793900 +0900
+++ en-verb-3.tsv       2020-06-12 21:25:39.197882200 +0900
@@ -14 +14 @@
-71     crow    {{en-verb|crows|crowing|crowed|past2=crew|past2_qual=UK|crowed|past_ptc2=crown|past_ptc2_qual=archaic}}
+71     crow    {{en-verb|crows|crowing|crowed|crowed}}
@@ -19 +19 @@
-114    may     {{en-verb|may|-|might|-|past_ptc2=mought|past_ptc2_qual=obsolete}}
+114    may     {{en-verb|may|-|might|-}}

Verbe régulier

Cette fois, le but est d'étudier les verbes irréguliers, nous allons donc exclure les verbes réguliers.

Voyons comment écrire un verbe régulier à partir des données générées précédemment.

2157    open    {{en-verb}}
46912   like    {{en-verb|lik}}
58007   wish    {{en-verb|es}}
60426   hone    {{en-verb|hon|es}}
34295   chop    {{en-verb|chop|p|ing}}
39760   compel  {{en-verb|compel|l|ed}}

Cela semble vouloir dire ce qui suit. Le trait d'union est un délimiteur entre la tige et la fin.

mot 3 simples Partie courante Participe passé Interprétation
open open-s open-ing open-ed Aucune information sous forme de mot
like like-s lik-ing lik-ed Les deux derniers mots lik
wish wish-es wish-ing wish-ed 3 simples es
hone hon-es hon-ing hon-ed Mot racine hon et 3 es unitaires
chop chop-s chop-p-ing chop-p-ed Dupliquer p et la séparation actuelle
compel compel-s compel-l-ing compel-l-ed Dupliquer l et le passé

Like et Hone ont le même motif, mais les deux styles semblent donner le même résultat. Les tirets sont dans des positions différentes, mais ils n'ont aucune signification linguistique et sont destinés aux programmes générant des variantes.

Supprimez les mots sans informations supplémentaires, jusqu'à 2 termes ou 3 éléments ou éditions. Supprimez également le début {{en-verb | et la fin }} pour les délimiter par des tabulations.

en-verb-4.py


import re, sys
pattern = re.compile("{{en-verb\\|(.*?)\\|*}}")
for line in sys.stdin:
    id, verb, forms = line.split("\t")
    if (m := pattern.match(forms)):
        forms = m[1].split("|")
        if len(forms) > 2 and forms[2] != "ing" and forms[2] != "ed":
            forms = "\t".join(forms)
            print(f"{id}\t{verb}\t{forms}")

Résultat d'exécution


$ python en-verb-4.py < en-verb-3.tsv > en-verb-4.tsv
$ head -n 5 en-verb-4.tsv
71      crow    crows   crowing crowed  crowed
112     march   marches marching        marched
114     may     may     -       might   -
167     swop    swops   swopping        swopped
180     deal    deals   dealing dealt
$ wc -l en-verb-4.tsv
5296 en-verb-4.tsv

Je l'ai réduit dans une certaine mesure, mais il y en a encore beaucoup.

Enquête sur les formes de mots

En regardant les données, il semble que la notation qui spécifie la racine n'est pas unifiée et que les verbes réguliers sont mélangés.

71  crow    crows   crowing crowed  crowed
167 swop    swops   swopping    swopped

3 Ignorez les informations des parties et variantes simples et présentes et excluez celles qui satisfont aux conditions suivantes en tant que verbes réguliers.

  1. Il n'y a pas de description de la forme passée.
  2. La forme passée et la partie passée ont la même forme et se terminent par ed.
  3. Le formulaire d'origine se termine par e et le formulaire précédent ajoute d au formulaire d'origine.
  4. Le formulaire d'origine se termine par y et le formulaire précédent change de y en i et ajoute ed.
  5. Pour le formulaire précédent, ajouté au formulaire d'origine.
  6. Pour le formulaire précédent, ajoutez en dupliquant le dernier caractère du formulaire d'origine. (Il y a un mot qui suit k à la fin c)

Il y a des conditions pour les caractères en double, mais cette fois ce n'est pas nécessaire, donc je n'entrerai pas.

Les mots avec apostrophie sont jugés en supprimant le symbole.

127005	F	F's|F'ing|F'ed

Si la forme passée et la partie passée sont à la fois «-» et non définies, elles seront supprimées.

en-verb-5.py


import sys
for line in sys.stdin:
    id, *forms = line.strip().split("\t")
    if len(forms) == 4: forms.append(forms[3])
    verb, _, _, past, pp = [f.replace("'", "").replace("-", "") for f in forms]
    if past == pp:
        if not past: continue
        if past.endswith("ed"):
            if verb.endswith("e") and verb + "d" == past: continue
            if verb.endswith("y") and verb[:-1] + "ied" == past: continue
            if verb + "ed" == past: continue
            if verb + verb[-1] + "ed" == past: continue
            if verb[-1] == "c" and verb + "ked" == past: continue
    forms = "\t".join(forms)
    print(f"{id}\t{forms}")

Résultat d'exécution


$ python en-verb-5.py < en-verb-4.tsv > en-verb-5.tsv
$ wc -l en-verb-5.tsv
1461 en-verb-5.tsv

Suppression du même motif

Si vous regardez les données, vous pouvez voir le même mot aligné plusieurs fois.

5438    think   thinks  thinking    thought thought
5438    think   thinks  thinking    thought thought

De plus, certains mots composés ont le même schéma de changement.

5664    draw    draws   drawing drew    drawn
7404    overdraw    overdraws   overdrawing overdrew    overdrawn
7761    withdraw    withdraws   withdrawing withdrew    withdrawn

Combinez les mêmes mots en un seul et réduisez le même modèle aux mots courts.

en-verb-6.py


import sys
verbs = {}
for line in sys.stdin:
    id, verb, *forms = line.strip().split("\t")
    if verb in verbs: continue
    verbs[verb] = (id, forms)
verbs2 = []
for v1, (id, forms) in verbs.items():
    contains = False
    for v2, (_, f2) in verbs.items():
        if v1 != v2 and v1.endswith(v2):
            c = True
            for f1, f2 in zip(forms, f2):
                if not f1.endswith(f2):
                    c = False
                    break
            if c:
                contains = True
                break
    if not contains:
        forms = "\t".join(forms)
        print(f"{id}\t{v1}\t{forms}")

Résultat d'exécution


$ python en-verb-6.py < en-verb-5.tsv > en-verb-6.tsv
$ wc -l en-verb-6.tsv
378 en-verb-6.tsv

Il a été considérablement serré. Après cela, il serait réaliste de les examiner individuellement.

Placez le fichier créé. Il y a encore quelques problèmes, mais il semble que les données d'origine devront être modifiées.

application

En appliquant cette méthode, vous pouvez rechercher des langues autres que l'anglais. Bien sûr, Wiktionary n'est pas la seule source d'informations, mais c'est un bon point de départ car les informations sont collectées dès que vous écrivez le programme.

Lors de l'apprentissage d'une nouvelle langue, cela peut être utile pour créer du matériel d'auto-apprentissage.

Si j'essaye quelque chose, je l'ajouterai.

Recommended Posts

Enquêter sur les verbes irréguliers anglais avec Wiktionary
Rechercher les fuites de mémoire avec objgraph