gensim0.8.6のチュートリアルをやってみた【Similarity Queries】

gensimの使い方がよく分からないからgensim0.8.6のチュートリアルをやってみた。そのメモ。


Similarity Queries」のチュートリアルをやってみました。


gensim関係のやってみたシリーズのリンク一覧


Python GensimでLDAを使うための前準備・パッケージのインストール

gensimを使ったwikipediaのコーパス作成

gensim0.8.6のチュートリアルをやってみた【コーパスとベクトル空間】

gensim0.8.6のチュートリアルをやってみた【Topics and Transformations】

gensim0.8.6のチュートリアルをやってみた【Similarity Queries】



LSAやLDAを使って最終的に実現するのは文章間の類似度判定


「LSAやLDAを使って最終的に実現したいこと」についての分かりやすい解説がチュートリアル内にあったので、その文章を翻訳します。


前回のチュートリアル「Corpora and Vector Spaces」と「Topics and Transformations」では、ベクトル空間におけるコーパスの作成と、そのコーパスを他のベクトル空間モデルに変換する方法を学びました。

そのような手順を踏んだ目的は、「文章間の類似度決定」や「ある文章とその他複数の文章の類似度決定」を行うためです。その一例として、ユーザーが入力したテキストと既にインデックスされた文章の類似度比較が挙げられます。
- Similarity Queries


つまり、このチュートリアルを終えることで、文章間の類似度比較ができるようになるよ、ということらしいです。



LSIモデルを使った文章間の類似度判定


# 毎度お決まりの手順
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
from gensim import corpora, models, similarities
dictionary = corpora.Dictionary.load('/tmp/deerwester.dict')
corpus = corpora.MmCorpus('/tmp/deerwester.mm') # comes from the first tutorial, "From strings to vectors"

print corpus
MmCorpus(9 documents, 12 features, 28 non-zero entries)

# lsiモデルを使う
lsi = models.LsiModel(corpus, id2word=dictionary, num_topics=2)

途中で読み込んでいるファイルは、前回までのチュートリアルで作成されたものです。


doc = "Human computer interaction"

vec_bow = dictionary.doc2bow(doc.lower().split())
print vec_bow
[(0, 1), (1, 1)]

vec_lsi = lsi[vec_bow] # convert the query to LSI space
print vec_lsi
[(0, -0.461821), (1, 0.070028)]

「Human computer interaction」が人間に入力された検索語(query)だとして、dictionary を使ってベクトル(vec_bow)に変換してます。


vec_bowは単語とその頻度が入った単純なコーパスなので、ID=0(computer)とID=1(human)が1回ずつ、というベクトルになっています。


さらにvec_bowをLSIベクトル空間に変換したものがvec_lsi、LSIベクトル空間ではトピック単位に次元が縮約されているので、数字がなんか半端になっている、みたいな感じです。


index = similarities.MatrixSimilarity(lsi[corpus]) # transform corpus to LSI space and index it

# ファイルに保存する場合
index.save('/tmp/deerwester.index')

# ファイルから読み込む場合
index = similarities.MatrixSimilarity.load('/tmp/deerwester.index')

indexの計算結果をファイルに保存しておくこともできます。コーパスが大きいとindexの計算だけで10時間とかかかったりします。


sims = index[vec_lsi] # perform a similarity query against the corpus

print list(enumerate(sims)) # print (document_number, document_similarity) 2-tuples
[(0, 0.99809301), (1, 0.93748635), (2, 0.99844527), (3, 0.9865886), (4, 0.90755945),
(5, -0.12416792), (6, -0.1063926), (7, -0.098794639), (8, 0.05004178)]

「Human computer interaction」と元文章との類似度を計算しています。類似度の尺度にはデフォルトではコサイン類似度を使うようです。


この結果はソートされていなくて読みづらいので、次にソートして出力してみます。


sims = sorted(enumerate(sims), key=lambda item: -item[1])

print sims # print sorted (document number, similarity score) 2-tuples
[(2, 0.99844527), # The EPS user interface management system
(0, 0.99809301), # Human machine interface for lab abc computer applications
(3, 0.9865886), # System and human system engineering testing of EPS
(1, 0.93748635), # A survey of user opinion of computer system response time
(4, 0.90755945), # Relation of user perceived response time to error measurement
(8, 0.050041795), # Graph minors A survey
(7, -0.098794639), # Graph minors IV Widths of trees and well quasi ordering
(6, -0.1063926), # The intersection graph of paths in trees
(5, -0.12416792)] # The generation of random binary unordered trees

類似度が大きい順に並べたのが上記の出力結果です。この結果から、「Human computer interaction」と一番近い文章は、ID=2、類似度=0.998の「The EPS user interface management system」であることが分かります。


# 上位のn件のみ出力する方法。この場合は上位の3件。
sims = sorted(enumerate(sims), key=lambda item: -item[1])[:3]

print sims # print sorted (document number, similarity score) 2-tuples
[(2, 0.99844527), # The EPS user interface management system
(0, 0.99809301), # Human machine interface for lab abc computer applications
(3, 0.9865886)] # The generation of random binary unordered trees

全部の結果を出力すると多すぎるので、上位のn件(このサンプルでは3件)だけ出力する方法も書きました。



LSIモデルを使うと出現しない単語に対しても類似度が求まる


上記の結果には一つ特筆すべき点があります。


それは、「Human computer interaction」というqueryのどの単語も、「The EPS user interface management system」には入っていない点です。


LSA(=LSI)では、文章の次元をトピックという単位で縮約するので、queryに入っていない単語も検索でヒットさせることができます。これがLSAの大きな特徴です。


上記の仕組みは、トピックという単位に次元を縮約することで、単語の単純なマッチではなく、単語間の関連も見ることで実現しています。


一見万能そうなLSAですが、弱点もあります。それは、関連があるとみなされた単語であっても、訓練データ中での出現回数が0回だとその次元は長さ0のベクトルになってしまい検索結果に反映されなくなる点です。


このあたりを特徴ベクトルのゆらぎとして許容したモデルがLDAモデルらしいのですが私は全然詳しくはないです。


LSA、LDAについては「LSIやLDAを手軽に試せるGensimを使った自然言語処理入門」にもっと分かりやすい解説が書いてあります。



まとめ


本記事では、各モデルを使った類似度判定を行いました。


理論の話から実践の話に近づいてきたので、何に使えるのか?が直感的に分かりやすくなってきました。


次はいよいよ、テストデータではなく実際のデータを使った類似度判定を行なっていきます。


著者プロフィール
Webサイトをいくつか作っています。
著者プロフィール