LoginSignup
3
2

More than 5 years have passed since last update.

できるだけ楽してwikipedia等を使って生物の学名と一般名の対応を取る

Last updated at Posted at 2019-02-03

wikipediaからの情報抽出をステップバイステップでやっていくチュートリアルの資料です。

生物の学名と和名の対応が取りたかったのでwikiepdiaからゴリっと抜いてみる。ベースとなる学名は、学名DBを持ってきて、そいつとマッチングする形にしないと表記ゆれの問題が大きい。

一応多言語で同じアプローチは取れるはず。

でかいデータから情報を抜いていくには、もとのデータを残しながら、フィルタをして取り出していくパイプラインを構築しておくと手戻りや、他の情報も一緒に取り出すなどがやりやすいので、この手順を覚えておくと良いです。

学名DB

学名も表記ゆれやsynonymも多いのでそこに関してはリファレンスを用いたい。学説が変われば同じようにラベルの張替えだけすれば良いので、まずはべーすとなるものが必要

植物はこれを使う

動物はなんかあるんかいね。虫とかはありそう。

生物分類表

生物の系統についてまとめられているwikipediaのテンプレート。系統の階層の情報や、和名と学名の情報が含まれている。かなり複雑でかつCGMなので適当に記載されているので結構機械で扱うには面倒っぽい。

テンプレートなので、どの記事にこの表が記載されているかはテンプレートへのリンク情報を見れば良い

テンプレートへのリンク

Wiki template inclusion link records.となっているwikipediaのダンプデータを利用する。11月19日現在ではこれが最新

こいつはmysqlのダンプのデータ。mysqlでいろいろやるの面倒なので sqlite3のsqlに変換して、sqliteで処理する。テキストをそのままパースしても良いんだけど、dbのサイズも1Gぐらいで大したこと無いのでコマンドラインだけで楽をします。

mysqlのdumpをsqlite3形式にするにはmysql2sqliteを使うと楽

適当に作業

wget https://raw.githubusercontent.com/dumblob/mysql2sqlite/master/mysql2sqlite
chmod +x mysql2sqlite
wget https://dumps.wikimedia.org/jawiki/20181101/jawiki-20181101-templatelinks.sql.gz
gunzip jawiki-20181101-templatelinks.sql.gz
./mysql2sqlite jawiki-20181101-templatelinks.sql |sqlite3 templatelinks.db
sqlite3 templatelinks.db 'SELECT tl_from FROM templatelinks WHERE tl_title="生物分類表"' > ja_taxsobox.txt

これで、生物分類表を含む記事について1行1記事idになったテキストファイルja_taxsobox.txtが作成される

本文データを処理する

wikipediaの本文データはくっそでかいので、処理時間はかなり掛かるはず。メモリで死ぬので、streaming apiで読むべき。解答しておくのもなんか嫌なので、オンラインで解凍しながらパースしていきたい。

wget https://dumps.wikimedia.org/jawiki/20181101/jawiki-20181101-pages-articles.xml.bz2

生物分類表テンプレートを含む記事のみ取り出し

雑なスクリプトを書く。JSON Linesで出力したかったので、xmltodictというライブラリを入れた

filter_article.py
import bz2
import json
import sys
from xml.etree import ElementTree
import xmltodict

WIKIPEDIA_NAMESPACE = 'http://www.mediawiki.org/xml/export-0.10/'


def translate_path(path):
    return '/'.join('{%s}%s' % (WIKIPEDIA_NAMESPACE, tag) for tag in path.split('/'))


if __name__ == "__main__":
    ids = []
    for line in sys.stdin:
        line = line.strip()
        ids.append(line)
    ids = set(ids)
    page_tag = translate_path('page')
    text_tag = translate_path('revision/text')
    title_tag = translate_path('title')
    page_id_tag = translate_path('id')
    ElementTree.register_namespace('', WIKIPEDIA_NAMESPACE)
    with bz2.open(sys.argv[1], mode="rt") as bz2f:
        context = ElementTree.iterparse(bz2f, events=('start', 'end'))
        event, root = next(context)
        for event, element in context:
            if event == 'end' and element.tag == page_tag:
                if element.findtext(page_id_tag) in ids:
                    print(json.dumps(
                        xmltodict.parse(ElementTree.tostring(element, encoding="unicode")),
                        ensure_ascii=False))
                root.clear()

これで必要な記事だけが入ったjsonl形式のファイルが作成できる

cat ja_taxsobox.txt | python filter_articles.py jawiki-20181101-pages-articles.xml.bz2 > ja_taxsobox.jsonl

テンプレートのマイニング

本文データからのtemplate部分の切り出しはmwparserfromhellを使うと楽が出来ると思う。

JSON Linesで作っているので、一行づつ読み込んで、mwparserfromhellでtemplateだけを取り出す。

extract_template.py
import json
import sys

import mwparserfromhell


if __name__ == "__main__":
    for line in sys.stdin:
        line = line.strip()
        j = json.loads(line)
        id = j["page"]["id"]
        title = j["page"]["title"]
        text = j["page"]["revision"]["text"]["#text"]
        parsed = mwparserfromhell.parse(text)
        templates = parsed.filter_templates()
        for template in templates:
            if template.name.matches("生物分類表"):
                print(json.dumps({"id": id, "title": title, "template": str(template)}, ensure_ascii=False))
cat ja_taxsobox.jsonl| python extract_template.py > ja_taxsobox_templates.jsonl

templateから学名と和名のペア候補を作成

なんか考える

リファレンスの学名データからのマッチング

simstringを使って類似文字列のマッチングを行う。リファレンスデータから類似文字列DBを構築してスコアリング出来るようにしておく

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2