リムナンテスは愉快な気分

徒然なるままに、言語、数学、音楽、プログラミング、時々人生についての記事を書きます

コーパスの整形

Chainerで機械翻訳 (python) 第6回

参考:
qiita.com


今回は京都大学の「日英中基本文データ」を使おうと思います。
日英中基本文データ - KUROHASHI-KAWAHARA LAB
というのも、英語以外の言語で試したかったのでこれにしました。(ゆくゆくはこのデータに追加する形で多言語対応させたい)
文章の数も5000文くらいなので個人でやる分には問題ないかなぁと。あんまり多いと計算終わらなさそうだし。これでも終わらないかもしれないけど。

f:id:frecafloros:20180403135000p:plain
上記サイトから持ってきた文例ですが、文自体の形はこのままexcelにデータが入ってました。
こいつを使いやすいように整形していきます。データは同じ行に同じ意味の文、同じ列に同じ言語が並んでいるので使い勝手は非常によさげ。importするだけならそのままcsvで吐き出して行ごとに突っ込めるし。
将来的に多言語化することを考えて、各言語ごとに別ファイルとして出力しましょうか。

で問題は、文を単語に分けなければいけないということ。英語は空白とかカンマでsplitすればいいので楽なんですけど、日本語と中国語は形態素解析しないといけませんね…
形態素っていうと言語学的には厳密にはちょっと違う気がしますが、本質はそこではないので以降形態素解析と言ったら分かち書きだと思ってください。)

日本語の形態素解析にはMeCab使おうかと思っていたんですが、どうもうまくインストールできなかったので(Windowsだるい)「Janome」を使うことにしました。
Welcome to janome’s documentation! (Japanese) — Janome v0.3 documentation (ja)

>>> from janome.tokenizer import Tokenizer
>>> t = Tokenizer()
>>> t.tokenize("透明な緑色の概念が猛烈に眠る。", wakati=True)
['透明', '', '緑色', '', '概念', '', '猛烈', '', '眠る', '']
>>> " ".join(t.tokenize("透明な緑色の概念が猛烈に眠る。", wakati=True))
透明 な 緑色 の 概念 が 猛烈 に 眠る 。

問題なく分かち書きできている様子。
日本語は上の例の最終行みたいな感じで、単語ごとにスペースで区切られるように加工していきます。



続いて英語ですが、めんどくさいので大文字は代項X以外全て小文字にして、末尾のカンマとピリオドだけ分離するようにすればいいですかね。英語用tokenizerを用意してもいいのですが、大したことをするわけでもないので今回は正規表現でお茶を濁そうかなと思います。略語の大文字はどうしようか悩みどころではありますが、だるいので全部小文字で。固有名詞とか知らない。よくよく考えたらNLTK入れてたので(完全に忘れてた)これのword_tokenize()で処理することにしました。まあクソ重いので入れてない人はPolyglotでも使えばいいんじゃないでしょうか。


…と、ここまで書いて気づいたんですけど、全部Polyglotでよかったんでは…
日本語はまあもうめんどくさいのでそのままでいっか。方針転換して英語と中国語はPolyglot使うことにします。世の中ストレートに上手くいくことなんてないんです。あと今までの苦労が無駄になるとかで旧い考えに固執すると真に優良な仕事はできないのです。記事の流れがめちゃくちゃとかもうどうでもいいのです。気持ちを切り替えてPolyglotりますよ!本当はつらい。


Polyglotがなぜか入らないのでNLTKでいきます。これのせいで1日分くらい消えた。只管悲しい。
NLTK : 英語の文章を文または単語単位で分割する - Matter Mind Meaning
Dive Into NLTK, Part II: Sentence Tokenize and Word Tokenize – Text Mining Online
ここに詳しい。

>>> from nltk.tokenize import word_tokenize
>>> word_tokenize(("Colorless green ideas sleep furiously.".lower()))
['colorless', 'green', 'ideas', 'sleep', 'furiously', '.']
>>> " ".join(word_tokenize(("Colorless green ideas sleep furiously.".lower())))
colorless green ideas sleep furiously .

代項Xだけは大文字を保持しておきたいところなので、まあ処理し終わってから正規表現で引っかけてまた大文字に戻しますかね。二度手間だけど。



中国語もPolyglotが使えないので止むを得ずPyNLPIRを使ってみる。
PyNLPIR 0.5.2 : Python Package Index

>>> import pynlpir
>>> pynlpir.open()
>>> pynlpir.segment("无色的绿色想法愤怒地睡觉。", pos_tagging=False)
['无色', '', '?', '', '想法', '?', '', '', '', '?', '']
>>> " ".join(pynlpir.segment("无色的绿色想法愤怒地睡觉。", pos_tagging=False))
'无色 的 ? 色 想法 ? 怒 地 睡 ? 。'

理論上はこれでいけるんですけどWind○wsはクソなので簡体字エンコードに失敗してます。
NLPIR(ICTCLAS)で,中国語の文章を形態素解析・分かち書きするJavaプログラムを作る手順 …Windows日本語環境で動くサンプルコード - 主に言語とシステム開発に関して
ここによると、どう足掻いても無理っぽいので、shellへのprintは諦めました。
csvに吐き出して確認したらちゃんと形態素解析&出力されてたのでこれでいきたいと思います。)



先の日英中基本文データを分かち書き→言語ごとに分割していきます。

#coding: utf-8
from janome.tokenizer import Tokenizer
from nltk.tokenize import word_tokenize
import pynlpir
import re
import csv

data_ja = []
data_en = []
data_zh = []
t = Tokenizer()
pynlpir.open()

with open('JEC_basic_sentence_v1-2.csv', 'r', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        data_ja.append([" ".join(t.tokenize(row[1], wakati=True)) + " 。"])
        row_en = " ".join(word_tokenize(row[2].lower()))
        row_en = re.sub(r"( x ){1}", " X ", row_en)
        row_en = re.sub(r"^(x ){1}", "X ", row_en)
        data_en.append([row_en])
        data_zh.append([" ".join(pynlpir.segment(row[3], pos_tagging=False))])

pynlpir.close()

with open('ja.csv', 'w', encoding='utf-8') as fja:
    writer = csv.writer(fja, lineterminator='\n')
    writer.writerows(data_ja)

with open('en.csv', 'w', encoding='utf-8') as fen:
    writer = csv.writer(fen, lineterminator='\n')
    writer.writerows(data_en)

with open('zh.csv', 'w', encoding='utf-8') as fzh:
    writer = csv.writer(fzh, lineterminator='\n')
    writer.writerows(data_zh)

入出力にわざわざコード指定しているのは、なぜか勝手にcp932で処理されてしまうのを防ぐため。憎きShift_JIS

日本語
f:id:frecafloros:20180407061701p:plain

英語
f:id:frecafloros:20180407061715p:plain

中国語
f:id:frecafloros:20180407061728p:plain

よさげ。
「いつも」って「总」より「经常」のほうが個人的には馴染みが深いんだけど…まあいっか。

次回はこれらのデータを使ってモデルの学習をしてみたいと思います。