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

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


Topics and Transformations」のチュートリアルをやってみました。あんまり意味が分かってないので間違いのご指摘等がありましたらよろしくお願いします…!


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


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

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

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

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

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



コーパスをtfidf, LSAのベクトル空間へ変換する


# ロギングの設定。なくてもOK
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')
print corpus

# 出力結果
MmCorpus(9 documents, 12 features, 28 non-zero entries)

tfidf = models.TfidfModel(corpus) # step 1 -- initialize a model

ここまでの手順により、tfidfモデルのデータが作られました。


# doc_bowは初回のチュートリアルで作成した下記のnew_vecと同じ
# >>> new_doc = "Human computer interaction"
# >>> new_vec = dictionary.doc2bow(new_doc.lower().split())
# >>> print new_vec
# [(0, 1), (1, 1)]
# このことから、この場合のdoc_bowってのはある文章を表すベクトルと等価らしい
doc_bow = [(0, 1), (1, 1)]

print tfidf[doc_bow] # step 2 -- use the model to transform vectors
[(0, 0.70710678), (1, 0.70710678)]

corpus_tfidf = tfidf[corpus]
for doc in corpus_tfidf:
    print doc
[(0, 0.57735026918962573), (1, 0.57735026918962573), (2, 0.57735026918962573)]
[(0, 0.44424552527467476), (3, 0.44424552527467476), (4, 0.44424552527467476), (5, 0.32448702061385548), (6, 0.44424552527467476), (7, 0.32448702061385548)]
[(2, 0.5710059809418182), (5, 0.41707573620227772), (7, 0.41707573620227772), (8, 0.5710059809418182)]
[(1, 0.49182558987264147), (5, 0.71848116070837686), (8, 0.49182558987264147)]
[(3, 0.62825804686700459), (6, 0.62825804686700459), (7, 0.45889394536615247)]
[(9, 1.0)]
[(9, 0.70710678118654746), (10, 0.70710678118654746)]
[(9, 0.50804290089167492), (10, 0.50804290089167492), (11, 0.69554641952003704)]
[(4, 0.62825804686700459), (10, 0.45889394536615247), (11, 0.62825804686700459)]

tfidfオブジェクトを作るために使ったcorpusをtfidfモデルのベクトル空間に変換、ということをやっているらしい。別の言い方をすると、「tfidfモデルの訓練データをtfidfベクトル空間に変換」となる。


あるデータを適用した結果の入力に再度同じデータを与えるってのが不思議ですが、これはこれでOKらしいです。私は研究者ではないので深追いせずに次に行きます…(^^)


lsi = models.LsiModel(corpus_tfidf, id2word=dictionary, num_topics=2) # initialize an LSI transformation
corpus_lsi = lsi[corpus_tfidf] # create a double wrapper over the original corpus: bow->tfidf->fold-in-lsi

さっき作ったtfidfコーパスから今度はlsiモデルを作っています。num_tipicsは文字通りトピック数なんですが、別の言い方をすると次元数みたいなものっぽいです。


lsi.print_topics(2)
topic #0(1.594): -0.703*"trees" + -0.538*"graph" + -0.402*"minors" + -0.187*"survey" + -0.061*"system" + -0.060*"response" + -0.060*"time" + -0.058*"user" + -0.049*"computer" + -0.035*"interface"
topic #1(1.476): -0.460*"system" + -0.373*"user" + -0.332*"eps" + -0.328*"interface" + -0.320*"response" + -0.320*"time" + -0.293*"computer" + -0.280*"human" + -0.171*"survey" + 0.161*"trees"

lsiオブジェクトって何なの?という疑問に答えるためにtopicを出力したものが上記になります。


上記の出力から、「tree, graph, minorsは関連のある単語である」、「この3つの単語は1つ目のトピックに大きく貢献している」ということが分かります。


for doc in corpus_lsi: # both bow->tfidf and tfidf->lsi transformations are actually executed here, on the fly
    print doc
[(0, -0.066), (1, 0.520)] # "Human machine interface for lab abc computer applications"
[(0, -0.197), (1, 0.761)] # "A survey of user opinion of computer system response time"
[(0, -0.090), (1, 0.724)] # "The EPS user interface management system"
[(0, -0.076), (1, 0.632)] # "System and human system engineering testing of EPS"
[(0, -0.102), (1, 0.574)] # "Relation of user perceived response time to error measurement"
[(0, -0.703), (1, -0.161)] # "The generation of random binary unordered trees"
[(0, -0.877), (1, -0.168)] # "The intersection graph of paths in trees"
[(0, -0.910), (1, -0.141)] # "Graph minors IV Widths of trees and well quasi ordering"
[(0, -0.617), (1, 0.054)] # "Graph minors A survey"

上記の出力から、最初の5つのdocument(文章のこと)は2つめのトピックと関連していることが分かります。


lsi.save('/tmp/model.lsi') # same for tfidf, lda, ...
lsi = models.LsiModel.load('/tmp/model.lsi')

作ったlsiモデルのデータを保存する方法です。



tfidf, LDA, LSAのベクトル空間へ変換する方法おさらい


model = tfidfmodel.TfidfModel(bow_corpus, normalize=True)

bow_corpusって何?

ここまでの流れから、bow_corpusには下記の関係があるようです。


bow_corpus = corpus = corpora.MmCorpus('/tmp/deerwester.mm') = [dictionary.doc2bow(text) for text in texts]

つまり、「bow_corpusは、dictionaryから作ったコーパスのこと」のようです。dictionaryは元の文章集合(この場合のtexts)から作った単語とその出現回数の対応表です。


model = lsimodel.LsiModel(tfidf_corpus, id2word=dictionary, num_topics=300)

# これは補足情報
lsi_vec = model[tfidf_vec]

tfidf_corpusって何?

ここまでの流れから、tfidf_corpusには下記の関係があるようです。


tfidf_corpus = tfidf[corpus] = models.TfidfModel(corpus)[corpus]
corpus = bow_corpus

つまり、「tfidf_corpusは、bow_corpusから作ったtfidfモデルを用いてbow_corpusのベクトル空間を変換しもの」のようです。


また、lsi_vec = model[tfidf_vec] のような書き方もされることから、コーパスとはつまりベクトルである、ということが言えるようです。


model = ldamodel.LdaModel(bow_corpus, id2word=dictionary, num_topics=100)

LDAモデルはLSAモデルと名前が似ていますが、少なくともこのコード上では、間にtfidfをはさむかはさまないかの違いがあるようです。(実際はもっと色々違うんだと思います)



RPモデル、HDPモデル


チュートリアルページではRPモデルとHDPモデルのオブジェクト作成方法も書いてあるのですが本記事では省略します。


また、LSIモデルでインクリメンタルにコーパスを作成するような方法ものっています。online trainingというそうです。



まとめ


ベクトル空間であれこれやってるのは分かったんですが、逆に言うとそれしか分からなかったです…。間違いのご指摘等がありましたらよろしくお願いします…!


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