gensim チュートリアル 1 – コーパスとベクトル空間


gensim のチュートリアル1を日本語にしてみました。 このチュートリアルのコードサンプルを GitHub: gensim-learning で公開しています。

コーパスとベクトル空間

準備

ログイベントを表示するには次のコードを実行してください。

文字列からベクトルへ

まずはドキュメントを作ります。

この文書をトークン化し、一般的な単語と一度だけしか出現しない単語を取り除きます。 (一般的な単語は簡単な単語のリストを用いて取り除きます。)

確認のために表示する場合は次のようにします。

ここでは次のようなアウトプットとなります。

ドキュメントを処理する方法は様々ですが、ここでは Deerwester et al. のもとのLSA記事にあるやり方を真似るために、 スペースで区切りすべてを小文字にするというシンプルだが非効率的な方法をとっています。 ここで扱うコーパスは、 Deerwester et al. (1990) の論文 Indexing by Latent Semantic Analysis の表2にあるものと同じものです。

ドキュメントを処理する方法は実に様々で、アプリケーションや言語に依存するため、いかなるインターフェースによっても制限されないようにしました。 その代わりに、ドキュメントはその特徴によって表され、表面的な文字列形式では表されないものとします。 その特徴をどのように取得するかはあなた次第で、下に例として一般的なアプローチ方法 (Bag-of-words) を示しますが、 異なるアプリケーションドメインでは別の特徴を採用することもあります。 いつものように、 ガーベジイン・ガーベジアウトです(意味のある入力でないと、意味のある出力が得られないということ)。

ドキュメントをベクトルに変換するため、ここでは Bag-of-words というドキュメントの表現方法を使います。 この表現方法では、ひとつのベクトルのそれぞれの要素が次のような質問・回答のペアになります。

“system” という単語が何度出現したか : 1回

この利点は質問をそのIDのみで表せることです。 そして、質問と回答のペアはディクショナリと呼ばれます。

次のようにして確認できます。

ここでは クラス gensim.corpora.dictionary.Dictionary を用いて、 出現したすべての単語にIDを付与しています。 すべてのテキストを判別して出現頻度と関連する統計情報を算出します。 最終的に、コーパス内に12の異なる単語があることがわかり、それぞれのドキュメントは12個の数(12次元ベクトル)で表されることがわかります。 単語とIDの対応を見るには次のようにします。

次のようにして、トークン化されたドキュメントをベクトルにします。

関数 doc2bow() は単純にそれぞれの単語の出現回数を計算し、 単語は id に変換してその結果を疎ベクトルとして返します。 疎ベクトルとはほとんどの成分が 0 のベクトルです。 疎ベクトル [(0, 1), (1, 1)] は “Human computer interaction” というドキュメントの中に、 id が 0 の単語 “computer” が 0回出現し、 id が 1 の単語 “human” が 1回出現することを意味しています。 他のディクショナリ内の単語は 0回出現します(1回も出現しません)。 ディクショナリにない単語は、ベクトルでは表現されません。 上の例では “interaction” がそれにあたります。

id=0 のベクトル成分は 「ドキュメントの中に 単語 “graph” は何回出現するか」 を表していて、 はじめの6つのドキュメントでは0回、 残る3つのドキュメントでは1回という結果になっています。

この結果をコーパスにして、後で使用するためにファイルに保存しておきます。 コーパスとはテキストや発話を大量に集めてデータベース化した言語資料のことです。

コーパスストリーミング – 1度にひとつのドキュメント

上のコーパスは Python のリストとして完全にメモリ内で扱われます。 とてもシンプルな例だったのでそれ自体問題にはなりませんでした。 ではコーパス内に100万のドキュメントがあったらどうでしょうか。 ドキュメントすべてを RAM の中に保存するのは無理でしょう。 ドキュメントはハードディスク内のファイルに、1行に1ドキュメントが記述されていると考えます。 Gensim で使用するためには、コーパスの各行それぞれに1つのドキュメントベクトルを記述する必要があります。

ここで使用している mycorpus.txt は次のような内容です。

1つのファイル内に、1行ずつ各ドキュメントが書かれているという仮定は重要ではありません。 どのようなフォーマットであれ、 __iter__ 関数をそのフォーマットに合うように変更できます。 ディレクトリを操作する、XMLを解析する、ネットワークにアクセスする… 各ドキュメントのトークンリストを取得するために入力を解析することで、ディクショナリを利用してトークンをidに変換し、__iter__の内部で疎ベクトルを生成することができます。

コーパスはオブジェクトで、アウトプットする方法を定義していませんから、オブジェクトのメモリ上のアドレスが表示されます。 あまり使いやすくないので、構成要素のベクトルを見るために、コーパスの中のそれぞれのドキュメントベクトルを1つ1行で順次表示してみましょう。1回のイテレートで、1つのベクトルデータを読み込み表示します。

出力結果は普通の Python の リストの場合と同じですが、 RAMの中には1度に1つのベクトルしか読み込まれないので、コーパスはずっとメモリにやさしい設計です。 これでコーパスはどれだけでも大きくすることができます。

同様に、すべてのテキストを読み込まずにディクショナリを生成するのが次の方法です。

以上がすべてです。 少なくとも Bag-of-words の表現については。 もちろん、それぞれのコーパスで何をするかが次の課題です。 まだ、各単語の出現頻度を計算することがどのように役に立つかはわかっていません。 しかしいずれにせよ、意味のあるドキュメントとドキュメントの類似点を計算できるようになる前には、まず最初に単純な変換をする必要があります。 変換については次のチュートリアルで扱いますが、その前に、コーパスの永続性に注目してみましょう。

コーパスの形式

ベクトル空間コーパス(ベクトルの配列)をハードディスクに保存するフォーマットはいくつかあります。 Gensim は先に述べたストリーミングコーパスの方式を利用してそれらの実装をしています。 その方法では、ドキュメントは一度にメモリ内に読み込まれず、1度にひとつのドキュメントを読み込みます。

最も注目するべきファイルフォーマットは Market Matrix フォーマット です。 Market Matrix フォーマット でコーパスを保存するには次のようにします。

他のフォーマットには、 Joachim’s SVMlight フォーマット、 Blei’s LDA-C フォーマット、 GibbsLDA++ フォーマット があります。

逆に、 Matrix Market フォーマット からコーパスを読み込む方法は次の通りです。

コーパスオブジェクトはストリームで、基本的にそれらを直接表示することはできません。

代わりに、コーパスの内容を表示します。

または

2つめの方法は明らかにメモリにやさしい方法です。 しかしテストや開発の目的においては、リストを(コーパス)を呼び出すこと以上に単純な方法はありません。

Matrix Market フォーマットのストリームを Blei’s LDA-C フォーマットで保存してみます。

このように、 gensim はメモリ効率を考えた 入出力フォーマット変換ツールとしても利用できます。 1つのフォーマットのドキュメントストリームを読み込み、直ちに別のフォーマットで保存できます。 新しいフォーマットを追加するのもとても簡単で、 SVMlight のコーパスのコードを参考にしてください。

NumPy と SciPy の互換性

Gensim は NumPy の行列と相互に変換するための効果的なツールも含んでいます。

また、 scipy.sparse の行列との相互変換も可能です。

ディクショナリを小さなサイズに整える、コーパスと NumPy, SciPy との変換を効率化するといったことを含む、完全なリファレンスについてはAPIドキュメントご覧ください。 次のチュートリアルはトピックと変換についてです。