ロシア語自然言語処理の世界

このエントリーは、KLab Advent Calendar 2015 の12/24の記事です。

2015年新卒の本堂です。

この記事ではロシア語テクストを統計的に分析することについて紹介します。

少しでもコンピュータを使って言語を分析することについて興味をもっていただけたら著者として幸せです。

  • ロシア語を少しでも勉強したことのある方
  • ロシア語を数量的に分析することに興味のある方

を読者として想定しています。

はじめに

僕の専門は言語学、特に言語獲得で、さまざまな言語獲得を実験する過程でロシアにも2年ほど住んでいました。

言語獲得というのは、乳幼児の言語習得や外国語習得などです。

乳幼児と大人の言語獲得スピードの差は今だに人類の謎です。

最近はコンピュータを使った数量的な分析を行う計量言語学も(特に英語で)盛んなので、

乳幼児が言語獲得していく過程と、僕が外国語としてロシア語を習得していく過程を数量的に表現したいと思いました。

例えば、乳幼児が生活に密着した語彙から覚えるのに対して、大人は抽象的な語彙から覚えるとか、

乳幼児は覚えた語彙の使用頻度が高いのに対し、大人は滅多に使わない語彙から覚えるなど。

というようなことを数量化できるかもしれない。

プログラミングは知らなかったので、最初は身近にあったMicrosoftのエクセルで始めました。

excel_stats_sample

このように(どうやったかはもう覚えていませんが)一行に一文、一列に一語ずつ入力して、

エクセルの関数を組み合わせて、なんとか目的の語を入力して出現回数を表示させることができました。

しかし、"я"と"мне"が別々にカウントされています。

(яは"私"の意。"мне"は"я"の与格で"私に"の意。)

格ごとに数えたい場合はこれでもいいですが、僕は語を数えたかったのでどちらも"я"としてまとめてほしいわけです。

"я"などはまだ曲用が少ない方なので、格それぞれの出現回数を合計するといいでしょう。

しかし、ご存知のように"идти"のような動詞は形動詞も含めると数十パターンの変化をするので、

これを手作業で行うのは大変です。

エクセルはロシア語の語形変化など知りませんから、教える必要があります。

どうせ自分で教えるなら自分でプログラムを書こう、と勉強を始めました。

ロシア語の自然言語処理について日本語で書かれた情報が全くないので、最初はとても苦労しました。

今後勉強される方のために情報を残しておこうと思います。

自然言語処理とは

コンピュータでロシア語など人の話す言語を処理する分野を総称して「自然言語処理」といいます。

"мне"を"я"に自動で変換することも自然言語処理の一部です。

プログラムもなんらかの言語によって書きます。

この分野ではPython(パイソン)というプログラミング言語がよく使われます。

自然言語処理やPythonについての説明は、すでに優れた書籍や解説記事がいくつもあるのでそれらを参照してください。

入門 自然言語処理という書籍は特におすすめです。自然言語処理だけでなくPythonの入門書としてもわかりやすく、プログラミングの経験がない僕でも楽しく読み進められました。

英語版であればこちらからPDFで読むことができます。

実際にロシア語テクストを分析してみよう・用語編

それでは実際にPythonを使ってチェーホフの戯曲「かもめ」の使用語彙を分析してみましょう。

その前に、これから使う用語を重要なものだけ整理しておきます。

「トークン」は、テキスト中に現れる語そのものです。句読点の間には適宜スペースをいれてあげます。

例えば、"Отчего вы всегда ходите в черном?"という文は、"Отчего"、"вы"、"всегда"、"ходите"、"в"、"черном"、"?"という7つのトークンからなります。

「レマ」は、そのトークンが見出し語として辞書に載っている語形のことだと思って大丈夫です。トークンは必ず1つのレマをもちます。

例えば、トークン"мне"のレマは"я"、トークン"я"のレマも同じく"я"です。トークン"шедщий"のレマは"идти"です。

「レマ化」とは、トークンをレマに変換することです。つまり、トークン"шедщий"をレマ"идти"に変換することです。

「タグ」は、トークンに対しての付加情報です。品詞、態、性別などの形態情報だけでなく意味情報・統語情報なども含みます。

色々な表記方法がありますが、例えば、"Отчего/疑問詞 вы/代名詞 всегда/副詞 ходите/動詞 в/前置詞 черном/形容詞 ?/句読点"というように記します。

「形態素解析」は、トークンに対して品詞、態、性別など形態論的に解析することです。

実際にロシア語テクストを分析してみよう・事前準備編

プログラミング言語にはPythonを使います。

Pythonについては、Macをお使いの場合最初からインストールされていますし、Windowsであればこちらから簡単にインストールできます。

Windowsの場合はPython3.5と書いてあるものをインストールしましょう。

今回の分析にはPython上にさらに2つのソフトウェアをインストールします。

  • nltk 自然言語処理に必要な機能を網羅的に提供してくれます
  • pymorphy2 ロシア語の形態素解析・レマ化をしてくれます

nltkのインストール方法に関しては上述の『入門 自然言語処理』に丁寧な説明がありますが、

どちらもPythonの"pip"というものを使うと簡単にインストールすることができます。

pipはPythonで作られたソフトウェアのインストールを簡単にしてくれるものです。

Macの場合はターミナルを開いて以下のコマンドを実行します。

sudo pip install nltk pymorphy2

Windowsの場合はコマンドプロンプトから以下のコマンドを実行するだけです。

C:¥Python35¥Scripts¥pip.exe install nltk pymophy2

事前準備はこれで終わりです。

実際にロシア語テクストを分析してみよう・実践編

それではいよいよ「かもめ」の使用語彙を分析してみましょう。

まずPythonを起動します。

Python 3.5.0 (default, Sep 23 2015, 04:42:00)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.72)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

インターネットからテキストを取得する

ダウンロードに必要なプログラムをロードします。

>>> import urllib.request

テキストをダウンロードします。
テキストはこちらのものを使用します。

>>> downloaddata = urllib.request.urlopen("http://www.lib.ru/LITRA/CHEHOW/chajka.txt")
>>> text = downloaddata.read().decode("koi8-r")

ダウンロードしたテキストを整形する

今回の分析では句読点が不要なので削除します。
replaceを使ってスペースに置き換えています。

>>> text = text.replace(".", " ")
>>> text = text.replace(",", " ")
>>> text = text.replace("?", " ")
>>> text = text.replace("!", " ")
>>> text = text.replace("(", " ")
>>> text = text.replace(")", " ")
>>> text = text.replace("\"", " ")
>>> text = text.replace("'", " ")

ダウンロードしたデータを一行ずつに分解します。
splitを使ってテキストを改行で区切ります。
lenでテキストの行数が分かります。大体3900行ぐらいであれば正しく分解できています。

>>> text = text.split("¥n")
>>> len(text)
3913

39行目までは不要な行なのでカットします。
len(text)で39行減っていることが確認できます。

>>> text = text[39:]
>>> len(text)
3874

1行目はtext[0]で確認できます。見たい行番号 - 1 であることに注意してください。
以下のように本文の一部が表示されたらOKです。

>>> print(text[0])
                            ДЕЙСТВИЕ ПЕРВОЕ

1行をトークンに分割してみる

テキストの1行目をline1に保存します。
line1.split()で1行目をトークンに分割できます。
結果がトークンのリストになっていることが確認できます。

>>> line1 = text[0]
>>> l1_tokens = line1.split()
>>> print(l1_tokens)
['ДЕЙСТВИЕ', 'ПЕРВОЕ']

トークンを集計してみる

テキストからトークンを取り出せるようになったので、実際に集計してみましょう。

まずはテキストをトークンに分割してみましょう。
まず、token_listという空のリストを作って、
テキストをfor文を使って1行ずつトークンに分割し、extendtoken_listに加えていきます。
きちんと分割されているようですね。

>>> token_list = []
>>> for line in text:
...      tokens = line.split()
...      token_list.extend(tokens)
>>> token_list
...
'не',
'любит',
'любит',
'-',
'не',
'любит',
'любит',
'-',
'не',
'любит',
'Смеется',
'Видишь',
'моя',
'мать',
'меня',
'не',
'любит',
'Еще',
'бы',
...]

集計のためにnltkのFreqDistというプログラムをロードします。

>>> from nltk import FreqDist

分割したトークンをFreqDistの中に入れて集計してもらいます。

>>> freqdist = FreqDist(token_list)

集計結果を見てみましょう。
most_commonで見ることができます。上位20位まで表示してみましょう。

>>> freqdist.most_common(20)
[('и', 854),
 ('в', 624),
 ('не', 611),
 ('я', 520),
 ('на', 338),
 ('Я', 274),
 ('что', 263),
 ('с', 254),
 ('Маша', 218),
 ('как', 207),
 ('все', 204),
 ('а', 193),
 ('меня', 180),
 ('мне', 171),
 ('у', 169),
 ('Ирина', 162),
 ('вы', 150),
 ('бы', 147),
 ('-', 146),
 ('то', 134)]

集計できました!
確かによく使われそうな語が上位にきていますね。しかし、"я", "Я", "меня", "мне"が別々にカウントされているようですね。ここまではエクセルでも出来たのでした。
次にいよいよレマ化をしていきます。

トークンをレマ化する

まずは例として先ほどのトークンリストにあった"меня"をレマ化してみましょう。

この"меня"(訳:私を)は代名詞"я"(訳:私)が曲用したものですね。これを"я"に変換しましょう。

pymorphy2を使用するのでロードします。このanalyzerが、ロシア語のトークンをレマ化してくれるものです。

>>> import pymorphy2
>>> analyzer = pymorphy2.MorphAnalyzer()

レマ化します。parseでレマ化することができます。可能性の高い順からリストをくれるので[0]で先頭だけ取り出します。normal_formに実際のレマが入っています。

>>> analyzer.parse("меня")[0].normal_form
'я'

うまくできたようですね。ではすべてのトークンをレマ化してもう一度集計してみましょう。
appendを使ってlemmaを一つずつリストに入れています。

>>> lemma_list = []
>>> for token in token_list:
...     lemma = analyzer.parse(token)[0].normal_form
...     lemma_list.append(lemma)
>>> lemma_list
'не',
'любить',
'любить',
'-',
'не',
'любить',
'любить',
'-',
'не',
'любить',
'смеяться',
'видеть',
'мой',
'мать',
'я',
'не',
'любить',
'ещё',
'бы',
...]

先ほどのトークンリストを比べてみると確かにレマしかなくなっていることが確認できます。

token_list lemma_list
не не
любит любить
любит любить
- -
не не
любит любить
любит любить
- -
не не
любит любить
Смеется смеяться
Видишь видеть
моя мой
мать мать
меня я
не не
любит любить
Еще ещё
бы бы

集計してみましょう。

>>> freqdist_lemma = FreqDist(lemma_list)
>>> freqdist_lemma.most_common(20)
[('я', 1229),
 ('и', 952),
 ('не', 729),
 ('в', 725),
 ('вы', 473),
 ('что', 380),
 ('на', 357),
 ('быть', 334),
 ('он', 332),
 ('а', 313),
 ('с', 304),
 ('весь', 304),
 ('это', 256),
 ('она', 253),
 ('как', 250),
 ('маша', 240),
 ('у', 229),
 ('ты', 220),
 ('мой', 217),
 ('ирина', 195)]

先ほどの"метя", "мне"がすべて集約されて"я"が1位になりましたね!

おわりに

以上簡単でしたが1作品の使用語彙をレマ化して集計するところまで紹介しました。
意外と簡単にできるなと思っていただけたらうれしいです。
NLTKにはまだまだ色々な機能があるので、ほとんどプログラムを書かなくても面白い分析ができます。
ロシア語関連のソフトウェアもたくさんあるので色々触ってみて新しい発見に繋げていただけたら幸いです。
最後まで読んでいただきありがとうございました。
興味はもったが分からない!ということがありましたらお気軽にコメントください。

紹介しきれなかった有用なツールが他にもいくつかあるので最後に簡単に紹介します。

その他ロシア語自然言語処理に有用なツールの紹介

形態素解析・レマ化ツール

Mystem

Mystemはロシアで最大の検索エンジンを作っているYandex製の形態素解析・レマ化ツールです。

商用利用は禁止されており、教育・学術目的のみ利用が許可されています。

Pythonから使うこともできます。

digsolab/pymystem3

TreeTagger

TreeTaggerはロシア語に限らず形態素解析に使われているツールで、日本語でも多くの紹介記事が見つけられます。

商用利用は禁止されています。

インストール方法はやや面倒ですが、こちらに従って丁寧に進めるとインストールできます。

ロシア語にも対応させることができて、

後述のRussian National Corpusで訓練されたパラメータファイルをリーズ大学のSerge Sharoffさんが配布してくれています。

russian.par.gz

Pythonから使うこともできます。

TreeTaggerWrapper

コーパスなど

Национальный корпус русского языка(Russian National Corpus)

コーパスとは、言語データを大量に収集・整理したもので、

収集された生のテキストには、形態情報・意味情報などのメタデータが付与されます。

大量のメタデータを利用して言語を統計的に扱うことを可能にします。

Национальный корпус русского языка(以下、НКРЯ)は現在のところロシア語の唯一にして最大のもっとも権威のあるコーパスです。

1.5億語程度の規模だそうです。

大部分が文語で構成されていて、わずかに口語も含まれています。

プログラム+手動で丁寧にタグ付けされています。

ブラウザからの検索インターフェイスも用意されていて、

形態情報、意味情報など詳細な条件で検索することができます。

商用利用は禁止されており、利用は科学・教育分野に限られています。

また、コーパスの生のデータを取得するには別途許可が必要ですので、

こちらをご覧ください。

OpenCorpora

OpenCorporaは、利用者同士が協力して構築しているロシア語コーパスです。

上サイトからコーパスの生のデータをダウンロードすることができます。

商用利用も可能です。

この記事で使用したpymorphy2はこのコーパスを元に形態素解析・レマ化を行っています。

ロシア語版青空文庫

日本語の青空文庫にあたるものは多数あります。

一番上のБиблиотека Максима Мошкова が一番有名だと思います。

このブログについて

KLabのゲーム開発・運用で培われた技術や挑戦とそのノウハウを発信します。

おすすめ

合わせて読みたい

このブログについて

KLabのゲーム開発・運用で培われた技術や挑戦とそのノウハウを発信します。