Turing Bot(1)Wikipediaページからのトークン抽出

Turing Bot (1) Extracting tokens from Wikipedia pages


2021/06/17
藤田昭人


本稿から数回は Turing Bot のための道具立てを紹介します。

これまで紹介してきた fastWMD は PythonC++ で実装されてますが、 このコードを参考に JavaScript に書き直して行きたいと思います。 初回の本稿では wikipedia-tokens.txtwikipedia-papers.txt の生成を試みます。


Alan Turing 関連のページデータを抽出する

まず Wikipedia のバックアップ・ダンプ・ファイルから Alan Turing 関連のページを抽出します。 抽出には 以前紹介した wikiPageSelector を使いますが、 任意の単独のページのみを抽出できるように修正しました。 第1引数に URL を指定すると該当するページのみを抽出します。 例えば Alan Turing のページを抽出する場合は次のコマンドラインになります。

$ ./wikiPageSelector http://en.wikipedia.org/wiki/Alan_Turing ~/Wikipedia/enwiki-20210520-pages-articles-multistream.xml > Alan_Turing-20210520.xml
・・・
$ 

なお、この要領で1ページのみ抽出した xmlwiki-xml-to-txt.py の入力にするとコケます。ちょっと調べてみたところ それが Python の挙動のようです。ご注意を。

ちなみにこのコマンド、今の仕様では実行時間は バックアップ・ダンプ・ファイルのサイズに依存します。 実行終了まで最低でも2時間程度待たされるので、 まだまだ改善の余地がありそうです。


ページ本文を抽出する

次に、バックアップ・ダンプ・ファイルから切り取った ページ選択した xml ファイルから、ページ本文を抽出します。 実はいろいろ思案をしたのですが*1Wikipedia バックアップからのデータ抽出では定評のある wikiextractor を利用することにしました。

github.com

これまた、当初はソースからインストールしようと 試みたのですがズッコケました。調べてみると いろいろトラブルが報告されているようで、 結局、次のように pip コマンドを使って 安易にインストールするのがお手軽のようです。

$ pip install wikiextractor
・・・
$ 

通常 wikiextractor を使う場合、 元の bzip2 で圧縮されたバックアップから 直接データを抽出することが多いと思いますが、 次のとおり非圧縮の xml ファイルでも問題なく動きます。 素敵なことに --json オプションを指定すると JSON フォーマットで出力してくれます。

$ wikiextractor --json -o extracted Alan_Turing-dump-20210420.xml
INFO: Preprocessing 'Alan_Turing-dump-20210420.xml' to collect template definitions: this may take some time.
INFO: Loaded 0 templates in 0.0s
INFO: Starting page extraction from Alan_Turing-dump-20210420.xml.
INFO: Using 7 extract processes.
INFO: Finished 7-process extraction of 1 articles in 0.1s (16.3 art/s)
$ 

この例では -o オプションで出力先を指定しますが、 指定した名前の ディレクト が生成され、 その下にデータファイルが格納されます。 覗いてみると…

$ ls -l extracted/AA/
total 88
-rw-r--r--  1 fujita  staff  44042  6 13 15:06 wiki_00
$ head extracted/AA/wiki_00
{"id": "1208", "revid": "20355744", "url": "https://en.wikipedia.org/wiki?curid=1208", "title": "Alan Turing", "text": "Alan Mathison Turing (; 23 June 1912\u00a0\u2013 7 June 1954) was an English mathematician, computer scientist, logician, cryptanalyst, philosopher, and theoretical biologist. Turing was highl<中略>listed buildings and landscape, and by extension the conservation area.\""}
$ 

この extracted/AA/wiki_00 が JSON ファイルです。

ちなみに、wiki-xml-to-txt.py と wikiextractor はいずれも ページ本文に頻繁に登場している MediaWikiマークアップ記法を 削除してくれますが、削除の仕様が微妙に異なります。 したがって、生成されるデータが異なり 厳密には一致しないことに注意してください。 本稿では当面 wikiextractor が生成するデータを採用します。


tokens と papers を生成する

次に、このJSONファイルから wikipedia-tokens.txtwikipedia-papers.txtを生成する 次の make_tokens なるJavaScriptのコードを書いてみました。

github.com

このプログラムは wiki-xml-to-txt.py の関数 preprocess_contentJavaScriptで次のように再現しています。

const entities = require("entities");
const stopwords = require('nltk-stopwords')
var english = stopwords.load('english');

function RemovePunctuation(rawString)
{
  var punctuation = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ –';
  var rawLetters = rawString.split('');
  var cleanLetters = rawLetters.filter(function(letter) {
    return punctuation.indexOf(letter) === -1;
  });
  var cleanString = cleanLetters.join('');
  return(cleanString);
}

function RemoveNumber(rawString)
{
  var number = '0123456789';
  var rawLetters = rawString.split('');
  var cleanLetters = rawLetters.filter(function(letter) {
    return number.indexOf(letter) === -1;
  });
  var cleanString = cleanLetters.join('');
  return(cleanString);
}

function preprocess_content(text)
{
  text = entities.decodeHTML(text);
  text = RemovePunctuation(text);
  text = RemoveNumber(text);
  text = stopwords.remove(text, english);
  return(text);
}

関数 preprocess_content を見てもらえればわかるように…

  • HTMLのエンティティをデコードする
  • 句読点を削除する
  • 数字を削除する
  • ストップワードを削除する

を行なっています。これは自然言語処理では一般的な前処理です。詳細は 自然言語処理における前処理の種類とその威力 で説明されているので参考にしてください。

なお例外は、wiki-xml-to-txt.py では行なっている 複数改行コードの削除は割愛しています。 というのも Turing Bot では Wikipedia ページを 各文節ごと独立して扱う考えで、 改行コード(\n)は文節間の区切り文字として 扱っているからです。 これは Wikipedia ページを「1つの文章」として扱う トリプレットとは異なる仕様です。

実装コードを動かすには JavaScript のパッケージ entitiesnltk-stopwords が必要です。 以下の手順で実行してみてください。 ちなみに Alan_Turing.json は 先ほど wikiextractor で生成したJSONファイルをコピーしたものです。

$ npm install entities nltk-stopwords

added 2 packages, and audited 3 packages in 2s

1 package is looking for funding
  run `npm fund` for details

found 0 vulnerabilities
$ node make_tokens.js Alan_Turing.json
$ ls
Alan_Turing.json    make_tokens.js      package.json
README-ja.md        node_modules        wikipedia-papers.json
README.md       package-lock.json   wikipedia-tokens.json
$ 

無事 wikipedia-papers.jsonwikipedia-tokens.json が 生成されたようです。


生成されたデータファイルを可視化する

生成された wikipedia-papers.jsonwikipedia-tokens.json の検証を兼ねて、 可視化するプログラム show_paper.js を作りました。 第1引数に wikipedia-tokens.json を 第2引数に wikipedia-papers.json を 指定すると元の文章を再現して表示してくれます。 次は Alan Turing のページの冒頭の1段落を表示した例です。

$ node show_paper.js wikipedia-tokens.json wikipedia-papers.json | head -1
Alan Mathison Turing June June English mathematician computer scientist logician cryptanalyst philosopher theoretical biologist Turing highly influential development theoretical computer science providing formalisation concepts algorithm computation Turing machine considered model generalpurpose computer Turing widely considered father theoretical computer science artificial intelligence
$ 

対応する Alan Turing のページ の冒頭は以下のとおりです。

Alan Mathison Turing OBE FRS (/ˈtjʊərɪŋ/; 23 June 1912 – 7 June 1954) was an English mathematician, computer scientist, logician, cryptanalyst, philosopher, and theoretical biologist.[6][7] Turing was highly influential in the development of theoretical computer science, providing a formalisation of the concepts of algorithm and computation with the Turing machine, which can be considered a model of a general-purpose computer.[8][9][10] Turing is widely considered to be the father of theoretical computer science and artificial intelligence.[11]

前処理で削除された情報が確認できますね。


まとめ

本稿では wikipedia-tokens.jsonwikipedia-papers.json の生成を試みました。

今回のコード実装の最中に思ったのは 「スクリプト言語には予想外のところで裏切られる」 でした。PythonJavaScript も いわゆるスクリプト言語、 つまりインタープリターなので、 時として期待に反した 不可思議な振る舞いをすることがあります*2。 今回も思うとおりに動いてくれないので、 何度か全面書き直しに追い込まれました (具体的な事例は割愛しますが…)。

とはいえ…

スクリプト言語のモダンな機能は抗し難い魅力があります。 特に文字列処理を多用する自然言語処理をC言語で書きたいとは 僕もあまり思わないのですが…

次回予定している wikipedia-embeddings.txt の生成では そうも行きそうにありません。

以上

*1:当初は xml2json を自前で実装しようとしたのですが、 Wikipedia のバックアップ・ダンプ・ファイルに含まれている データを漏れなく json に反映しようとすると、 むっちゃ時間がかかりそうだったので、 止む無く断念しました。

*2:都度コードを解釈する インタープリターは コンパイラーのように 「全ての記述が書かれている」 ことが仮定できません。 「次に何が記述されるか予測できない」 故に不思議な挙動をすることがあります。 まぁ、それがその言語の仕様ってことなんでしょう。