Edited at

Rでgensimを使う(Hierarchical Dirichlet Process編)

More than 1 year has passed since last update.


概要

 前回の{tensorflow}を使ってみた記事を書いている最中に、importというPythonモジュールを読み込む関数を見つけて、試してみたら様々なモジュールが呼び出せたので忘れないように書いていく。今回はgensimによるHDP(Hierarchical Dirichlet Process)をやってみる。Rでの実行に対応するPythonスクリプトも一応残しておく。


はじめに

 importを使うと何ができるようになるか簡単に説明すると、下記のようにPythonモジュールをRから呼び出して実行できる。


import

numpy <- tensorflow::import(module = "numpy")

# モジュール名にしなくてもOK(Pythonのimport XXX as YYYYで別名を与えるのと同じようなもの?)
pd <- tensorflow::import(module = "pandas")

# Numpyによる5行10列の乱数行列生成
> numpy$random$randn(5, 10)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0.2047579 1.4396232 1.39649920 -0.1621329 -0.6799612 -1.4375955 0.2590723 -1.4437292 1.1271664 -0.4434576
[2,] -0.3361488 0.5803642 0.95495572 0.6387092 0.6780120 -1.4093077 -1.3109703 -0.3436415 -0.3865685 1.7751260
[3,] -1.5810281 -1.2563752 0.89171330 0.6231667 -0.2083092 -0.3420242 0.3497256 -0.1856578 0.7441822 0.3541081
[4,] 0.8735340 1.3249083 -0.85038554 1.7963186 -0.4585773 0.8976184 -1.3661424 1.1888050 -1.0010572 -1.0871089
[5,] -0.5713605 0.6925751 -0.04234618 1.6234901 0.2355078 -0.2883208 1.6499782 1.6002583 -0.4482790 -0.0950429

# Pandasによるデータフレーム化
> pd$DataFrame(data = numpy$array(c(1, 2)))
0
0 1.0
1 2.0


 以前に書いた記事でRStudioの1系Preview版では{tensorflow}を呼び出すとTensorFlowのオブジェクトがサジェストされる旨に触れたが、importで呼び出したモジュールも同じように対応している。

 下記の画像では上記で呼び出したPandasを例にしている。Pandasを読み込んだpdオブジェクトに$をつけてタブを押すと、関数やオブジェクトがサジェストされる。

 これによりPythonに馴染みがないRStudioユーザーでも便利なモジュールが簡単に使えてしまう。なお、Pythonでは.でメソッドを呼び出すが、R上で呼び出す際には$を使うため、GitHubなどのPythonスクリプトをRで書き直す際には注意が必要になる。


辞書型の扱い方

 話題がそれてしまうが、RにはPythonの辞書型がなくtensorflow::dictで作成した辞書オブジェクトの扱いに戸惑ったので、メモとして残しておく。


{tensorflow}のdict

# 作成はtensorflow::dict()

> (word_dict <- tensorflow::dict(a = "at"))
{'a': 'at'}
> class(x = word_dict)
[1] "tensorflow.builtin.dict" "tensorflow.builtin.object" "externalptr"

# 値の参照はget()メソッドを利用
> word_dict$get("a")
[1] "at"

# 存在しないキーを指定すると何も返さないので、判定ではis.null()を使う
> word_dict$get("b")
> is.null(x = word_dict$get("b"))
[1] TRUE


 なお、RとPython間のオブジェクトの対応は{tensorflow}のAPIリファレンスが参考になる。

Python
R
Examples

Scalar
Single-element vector

1, 1L, TRUE, "foo"

List
Multi-element vector

c(1.0, 2.0, 3.0), c(1L, 2L, 3L)

Tuple
List of multiple types
list(1L, TRUE, "foo")

Dict
Named list or dict

list(a = 1L, b = 2.0), dict(x = x_data)

NumPy ndarray
Matrix/Array
matrix(c(1,2,3,4), nrow = 2, ncol = 2)

None, True, False
NULL, TRUE, FALSE

NULL, TRUE, FALSE


定義・設定

 本題のgensimを使ったHDPの実行用の関数定義。もちろん、あらかじめgensimはインストールしておく必要がある。


定数定義部

library(pacman)

# 読み込むパッケージ
SET_LOAD_PACKAGE <- c("tensorflow", "dplyr", "tidyr", "tidytext", "tibble", "stringi", "ggplot2")



関数定義部

# hdpmodel.pyの__getitem__

# https://github.com/RaRe-Technologies/gensim/blob/master/gensim/models/hdpmodel.py
assignTopic <- function (hdp, corpus, eps = 0.01) {
gamma <- hdp$inference(chunk = corpus)
topic_dist <- gamma / matrix(data = rep(x = rowSums(x = gamma), hdp$m_T), ncol = hdp$m_T, byrow = FALSE)
tpc_idx <- dplyr::as_data_frame(which(x = topic_dist >= eps, arr.ind = TRUE)) %>%
dplyr::arrange(row, col)
return(
dplyr::data_frame(
doc_id = tpc_idx$row,
topic_number = tpc_idx$col - 1,
prob = topic_dist[as.matrix(tpc_idx)]
)
)
}


準備

 gensimのHDP実行に必要なRでのデータ整形を行う。途中経過を表示するので、Python実行と比較してほしい。


準備

# 今回使用するパッケージを読み込み

pacman::p_load(char = SET_LOAD_PACKAGE, install = FALSE, character.only = TRUE)
# Pythonモジュールのgensimの読み込み
gensim <- tensorflow::import(module = "gensim")

# HDPにかけるテキスト
documents <- c(
"Human machine interface for lab abc computer applications",
"A survey of user opinion of computer system response time",
"The EPS user interface management system",
"System and human system engineering testing of EPS",
"Relation of user perceived response time to error measurement",
"The generation of random binary unordered trees",
"The intersection graph of paths in trees",
"Graph minors IV Widths of trees and well quasi ordering",
"Graph minors A survey"
)

> texts <- dplyr::data_frame(documents) %>%
tibble::rownames_to_column(var = "sid") %>%
tidytext::unnest_tokens(output = word, input = documents, token = "words") %>%
dplyr::anti_join(
y = dplyr::data_frame(word = c("for", "a", "of", "the", "and", "to", "in")),
by = "word"
) %>%
print
# A tibble: 52 × 2
sid word
<chr> <chr>
1 8 ordering
2 8 quasi
3 8 well
4 8 widths
5 8 iv
6 8 minors
7 9 minors
8 7 paths
9 7 graph
10 8 graph
# ... with 42 more rows

# gensim.corpora.Dictionaryで単語とIDを紐付けるオブジェクトを作成
dictionary <- gensim$corpora$Dictionary(list(stringi::stri_unique(str = texts$word)))
# 下記ではID = 0の単語が"minors"
> head(x = dictionary$token2id, n = 5)
$minors
[1] 0

$generation
[1] 1

$random
[1] 17

$iv
[1] 3

$engineering
[1] 4

> class(dictionary)
[1] "gensim.corpora.dictionary.Dictionary" "gensim.utils.SaveLoad" "_abcoll.Mapping"
[4] "tensorflow.builtin.object" "externalptr"

# doc2bowメソッドを適用できるように単語毎にlistに格納
# 文毎にlistがあり、単語毎にlistがある形
sentence <- texts %>%
dplyr::group_by(sid) %>%
dplyr::summarize(sentence = list(as.list(x = word))) %>%
print
# A tibble: 9 × 2
sid sentence
<chr> <list>
1 1 <list [7]>
2 2 <list [7]>
3 3 <list [5]>
4 4 <list [6]>
5 5 <list [7]>
6 6 <list [5]>
7 7 <list [4]>
8 8 <list [8]>
9 9 <list [3]>

> sentence$sentence[[1]]
[[1]]
[1] "applications"

[[2]]
[1] "computer"

[[3]]
[1] "abc"

[[4]]
[1] "lab"

[[5]]
[1] "interface"

[[6]]
[1] "machine"

[[7]]
[1] "human"

# 各文毎にdoc2bowメソッドを適用してcorpusを作成
corpus <- lapply(X = sentence$sentence, FUN = dictionary$doc2bow)



Hierarchical Dirichlet Process

 上記までで加工したcorpusを用いて、gensimのHDPを呼び出す。後述するが、ここではTopic数を150までで実行している。


HDP実行と結果表示

hdp <- gensim$models$hdpmodel$HdpModel(corpus = corpus, id2word = dictionary, alpha = 1, T = 150L)

# show_topicsメソッドで作成したトピック上位100を取得
topic_most_words <- dplyr::bind_rows(
lapply(
X = hdp$show_topics(topics = -1L, topn = 100L, formatted = FALSE),
FUN = function (topic_result) {
return(
dplyr::data_frame(
topic_number = topic_result[[1]],
word = sapply(X = topic_result[[2]], FUN = "[[", 1),
weight = sapply(X = topic_result[[2]], FUN = "[[", 2)
)
)
}
)
)
# 各トピックでTOP1の重みの単語を出力
> topic_most_words %>%
dplyr::group_by(topic_number) %>%
dplyr::top_n(n = 1, wt = weight) %>%
dplyr::glimpse()
Observations: 150
Variables: 3
$ topic_number <int> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3...
$ word <chr> "iv", "abc", "machine", "opinion", "iv", "binary", "user", "time", "random", "unordered", "graph", "computer", "ordering"...
$ weight <dbl> 0.12797694, 0.12662267, 0.14265295, 0.22422048, 0.07968149, 0.15725564, 0.12947385, 0.12292357, 0.12069854, 0.08766465,...

# トピック番号0の重みが上位10単語を表示
> topic_most_words %>%
dplyr::filter(topic_number == 0) %>%
dplyr::top_n(n = 10, wt = weight)
# A tibble: 10 × 3
topic_number word weight
<int> <chr> <dbl>
1 0 iv 0.12797694
2 0 error 0.09925327
3 0 unordered 0.08631031
4 0 widths 0.08567026
5 0 user 0.05359417
6 0 perceived 0.04646710
7 0 quasi 0.03670312
8 0 minors 0.03300030
9 0 survey 0.03216778
10 0 relation 0.03062379

# トピックの重みはトピック毎の合計が1.0になるように設定
> topic_most_words %>%
dplyr::group_by(topic_number) %>%
dplyr::summarize(sum_weight = sum(weight))
# A tibble: 150 × 2
topic_number sum_weight
<int> <dbl>
1 0 1
2 1 1
3 2 1
4 3 1
5 4 1
6 5 1
7 6 1
8 7 1
9 8 1
10 9 1
# ... with 140 more rows

# Rで加工しない形は次の通り
> hdp$show_topics(topics = 1L, topn = 10L)
[1] "topic 0: 0.128*iv + 0.099*error + 0.086*unordered + 0.086*widths + 0.054*user + 0.046*perceived + 0.037*quasi + 0.033*minors + 0.032*survey + 0.031*relation"



トピック数について

 HDP-LDAは明示的なトピック数を持たず、無限可変長のトピックを持つ。理論的には無限トピックだが、プログラム実行の都合上、あるトピック数までに定めることになる(前述の実行だと150までを設定)。無限可変長のトピックをパラメータによって打ち切り、結果として適したトピック数となるという認識ですが、間違っていたらすみません(勉強不足で申し訳ありません)。


トピック数

# パラメータを変動させてトピックの割り当てを比較すると、ある程度の数で確率がほとんど0になるトピックが出てくる(適したトピック数は満遍なく確率が振られている状態と考えられる?)

> assignTopic(hdp = hdp, corpus = corpus, eps = 0.5) %>%
tidyr::spread(key = topic_number, value = prob, fill = 0)
# A tibble: 7 × 4
doc_id `0` `1` `2`
* <int> <dbl> <dbl> <dbl>
1 2 0.0000000 0.000000 0.5794248
2 3 0.0000000 0.636553 0.0000000
3 4 0.0000000 0.549115 0.0000000
4 5 0.0000000 0.000000 0.6637392
5 7 0.8510308 0.000000 0.0000000
6 8 0.9171867 0.000000 0.0000000
7 9 0.8142352 0.000000 0.0000000

> assignTopic(hdp = hdp, corpus = corpus, eps = 0.05) %>%
tidyr::spread(key = topic_number, value = prob, fill = 0)
# A tibble: 9 × 5
doc_id `0` `1` `2` `3`
* <int> <dbl> <dbl> <dbl> <dbl>
1 1 0.0000000 0.4434944 0.4689728 0.0000000
2 2 0.0000000 0.0000000 0.5794248 0.3236852
3 3 0.2711764 0.6365530 0.0000000 0.0000000
4 4 0.3718040 0.5491150 0.0000000 0.0000000
5 5 0.2609743 0.0000000 0.6637392 0.0000000
6 6 0.4543387 0.4534745 0.0000000 0.0000000
7 7 0.8510308 0.0000000 0.0000000 0.0000000
8 8 0.9171867 0.0000000 0.0000000 0.0000000
9 9 0.8142352 0.0000000 0.0000000 0.0000000

> assignTopic(hdp = hdp, corpus = corpus, eps = 0.005) %>%
tidyr::spread(key = topic_number, value = prob, fill = 0)
# A tibble: 9 × 10
doc_id `0` `1` `2` `3` `4` `5` `6` `7` `8`
* <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0.03606753 0.44349436 0.46897279 0.01310405 0.010056735 0.007288994 0.005646310 0.000000000 0.000000000
2 2 0.03447054 0.02405832 0.57942479 0.32368520 0.010056624 0.007288991 0.005646310 0.000000000 0.000000000
3 3 0.27117635 0.63655299 0.02365162 0.01747056 0.013409101 0.009718661 0.007528413 0.005514206 0.000000000
4 4 0.37180402 0.54911504 0.02026298 0.01497529 0.011494638 0.008330283 0.006452925 0.000000000 0.000000000
5 5 0.26097434 0.02382923 0.66373916 0.01309609 0.010056665 0.007288992 0.005646310 0.000000000 0.000000000
6 6 0.45433870 0.45347446 0.02357873 0.01746019 0.013408535 0.009718667 0.007528413 0.005514206 0.000000000
7 7 0.85103077 0.03833858 0.02829496 0.02095766 0.016090783 0.011662393 0.009034095 0.006617047 0.000000000
8 8 0.91718670 0.02139333 0.01567863 0.01164270 0.008939062 0.006479106 0.005018942 0.000000000 0.000000000
9 9 0.81423517 0.04750129 0.03534385 0.02619753 0.020113102 0.014577990 0.011292619 0.008271309 0.005930772

# 以下はeps = 0.01の結果で検証する
topic_assign <- assignTopic(hdp = hdp, corpus = corpus)
topic_assign %>%
tidyr::spread(key = topic_number, value = prob, fill = 0)
# A tibble: 9 × 8
doc_id `0` `1` `2` `3` `4` `5` `6`
* <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0.03606753 0.44349436 0.46897279 0.01310405 0.01005674 0.00000000 0.00000000
2 2 0.03447054 0.02405832 0.57942479 0.32368520 0.01005662 0.00000000 0.00000000
3 3 0.27117635 0.63655299 0.02365162 0.01747056 0.01340910 0.00000000 0.00000000
4 4 0.37180402 0.54911504 0.02026298 0.01497529 0.01149464 0.00000000 0.00000000
5 5 0.26097434 0.02382923 0.66373916 0.01309609 0.01005666 0.00000000 0.00000000
6 6 0.45433870 0.45347446 0.02357873 0.01746019 0.01340854 0.00000000 0.00000000
7 7 0.85103077 0.03833858 0.02829496 0.02095766 0.01609078 0.01166239 0.00000000
8 8 0.91718670 0.02139333 0.01567863 0.01164270 0.00000000 0.00000000 0.00000000
9 9 0.81423517 0.04750129 0.03534385 0.02619753 0.02011310 0.01457799 0.01129262

# 確率が最大となるトピック番号をトピックとして割り当てると、0から2までに集中
> topic_assign %>%
dplyr::group_by(doc_id) %>%
dplyr::filter(prob == max(prob))
Source: local data frame [9 x 3]
Groups: doc_id [9]

doc_id topic_number prob
<int> <dbl> <dbl>
1 1 2 0.4689728
2 2 2 0.5794248
3 3 1 0.6365530
4 4 1 0.5491150
5 5 2 0.6637392
6 6 0 0.4543387
7 7 0 0.8510308
8 8 0 0.9171867
9 9 0 0.8142352

# トピック番号毎に比率を出す
> dplyr::left_join(
x = topic_assign %>%
dplyr::group_by(topic_number) %>%
dplyr::summarize(topic_sum_prob = sum(prob)),
y = topic_assign %>%
dplyr::mutate(sum_prob = sum(prob)) %>%
dplyr::distinct(topic_number, sum_prob),
by = "topic_number"
) %>%
dplyr::mutate(
ratio = topic_sum_prob / sum_prob,
cumsum_ratio = cumsum(x = ratio)
) %>%
dplyr::select(topic_number, ratio, cumsum_ratio)
# A tibble: 7 × 3
topic_number ratio cumsum_ratio
<dbl> <dbl> <dbl>
1 0 0.460601369 0.4606014
2 1 0.256953677 0.7175550
3 2 0.213456275 0.9310113
4 3 0.052658161 0.9836695
5 4 0.012020739 0.9956902
6 5 0.003013089 0.9987033
7 6 0.001296691 1.0000000


 eps = 0.01のときは、トピック数が3から4くらいでほぼ網羅でき、多くても7までという結果だろうか。


可視化

 トピック番号0から6までの7トピックに限定し、様々な切り口で可視化してみる。


トピック毎に単語の重み累積和を可視化


単語の重み累積和

tpc_words <- dplyr::inner_join(

x = topic_most_words,
y = topic_assign %>%
dplyr::distinct(topic_number),
by = "topic_number"
)

tpc_words %>%
dplyr::mutate(topic_number = as.factor(x = topic_number)) %>%
dplyr::group_by(topic_number) %>%
dplyr::mutate(
counter = dplyr::row_number(x = topic_number),
cumsum_weight = cumsum(x = weight)
) %>%
ggplot2::ggplot(
data = ., mapping = ggplot2::aes(x = counter, y = cumsum_weight)
) + ggplot2::geom_line(mapping = ggplot2::aes(group = topic_number, color = topic_number))


 上位5単語のとき(X軸が5のライン)では、トピック番号3は約0.50でトピック番号4は約0.28となっており、トピック番号3の方が少ない単語に高い確率が付与されていることがわかる(いくつかの単語がトピック番号3を強く表現していると考えられる)。


トピック毎に重み上位10単語を可視化


トピック毎に重み上位10単語

tpc_words %>% 

dplyr::group_by(topic_number) %>%
dplyr::arrange(topic_number, dplyr::desc(x = weight)) %>%
dplyr::top_n(n = 10, wt = weight) %>%
dplyr::mutate(word = reorder(x = word, X = weight)) %>%
dplyr::ungroup() %>%
ggplot2::ggplot(data = ., mapping = ggplot2::aes(x = word, y = weight, fill = factor(topic_number))) +
ggplot2::geom_bar(stat = "identity", show.legend = FALSE) +
ggplot2::facet_wrap(facets = ~ topic_number, scales = "free") +
ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 90))



 

 トピック番号3は"opinion"と"user"の割合が大きく、トピック番号4は単語毎に満遍なく重みが付与されている。これはひとつ前の可視化を単語レベルで確認しているとも。


トピック毎に重み上位30単語を単語毎に積み上げ棒グラフで可視化


単語毎に積み上げ棒グラフ

tpc_words %>% 

dplyr::group_by(topic_number) %>%
dplyr::arrange(topic_number, dplyr::desc(x = weight)) %>%
dplyr::top_n(n = 30, wt = weight) %>%
dplyr::ungroup() %>%
dplyr::mutate(
topic_number = factor(topic_number),
word = reorder(x = word, X = weight)
) %>%
ggplot2::ggplot(ggplot2::aes(x = word, y = weight, fill = topic_number)) +
ggplot2::geom_bar(stat = "identity") + ggplot2::coord_flip()

 単語毎にトピックの割合が可視化できると考えられる。具体的には、"error"はトピック番号0に大きい割合を占め、"opinion"はひとつ前の可視化の結果通りトピック番号3の割合が大きい。対照的に、"iv"や"user"などはひとつのトピックに捉われないとも。


まとめ

 {tensorflow}のimportというPythonモジュールを読み込む関数を用いて、gensimのHDPを実行しました。さらに適してそうなトピック数を求め、結果を様々な切り口で可視化してみました。HDPの知識が足らず、正しい認識かどうか心配ですが、とりあえずやってみました(ここがおかしいなどがありましたらが、ご指摘いただけると幸いです)。同じようにgensimのDoc2Vecも実行検証したので、そのうちまとめます。

 {tensorflow}のimportで以前から愛用していた{PythonInR}を使わなくなるかと思ったのですが、Pythonでは呼び出せる関数が読み出せなかったりするので、もう少し調査したいです。


gensimのDTMをRから呼び出し

> gensim$models$ldaseqmodel$LdaSeqModel

eval(substitute(expr), envir, enclos) でエラー:
AttributeError: 'module' object has no attribute 'ldaseqmodel'


gensimのDTMをPythonから呼び出し

import gensim

>>> gensim.models.ldaseqmodel.LdaSeqModel
<class 'gensim.models.ldaseqmodel.LdaSeqModel'>


追記(2016.01.04)

 上記のgensimでDTMが呼び出せない件について、tensorflowのバージョンを上げたところ利用できました(実行を確認できた環境は0.12.1)。ただし、pip install tensorflowではダメで、公式にある通りの手順でTF_BINARY_URLで.whlを指定するとできました。違いがよくわかりません。


gensimのDTMをRから呼び出し(追記版)

dtm <- gensim$models$ldaseqmodel$LdaSeqModel(corpus = corpus, time_slice = c(5L, 10L, 15L), num_topics = 3L)

> print(dtm)
LdaSeqModel

# 指定した文書のトピック分布
> dtm$doc_topics(doc_number = 1)
[1] 0.001422475 0.001422475 0.997155050

# 文書毎のトピック分布、単語毎のトピック分布、文毎の単語数、単語毎の出現頻度
> dtm$dtm_vis(time = 1L, corpus = corpus)
[[1]]
[,1] [,2] [,3]
[1,] 0.001422475 0.001422475 0.997155050
[2,] 0.001422475 0.001422475 0.997155050
[3,] 0.001988072 0.001988072 0.996023857
[4,] 0.001658375 0.001658375 0.996683250
[5,] 0.001422475 0.001422475 0.997155050
[6,] 0.996023857 0.001988072 0.001988072
[7,] 0.995037221 0.002481390 0.002481390
[8,] 0.001245330 0.997509340 0.001245330
[9,] 0.003300330 0.993399340 0.003300330

[[2]]
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 0.05957456 0.01419498 0.01419498 0.014194979 0.01419498 0.01419498 0.01419498 0.01419498
[2,] 0.20229085 0.04711086 0.01035351 0.041352822 0.01035351 0.01035351 0.01035351 0.01035351
[3,] 0.01935312 0.01369708 0.01369708 0.007190831 0.01369708 0.07356165 0.01369708 0.07356165
[,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16]
[1,] 0.01419498 0.01419498 0.128644022 0.01419498 0.014194979 0.128644022 0.01419498 0.01419498
[2,] 0.01035351 0.01035351 0.010353508 0.01035351 0.041352822 0.202290845 0.01035351 0.01035351
[3,] 0.01369708 0.01369708 0.007190831 0.01369708 0.007190831 0.007190831 0.13245925 0.01369708
[,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24]
[1,] 0.014194979 0.01419498 0.01419498 0.01419498 0.12864402 0.01419498 0.01419498 0.01419498
[2,] 0.041352822 0.01035351 0.01035351 0.01035351 0.04135282 0.01035351 0.01035351 0.01035351
[3,] 0.007190831 0.01369708 0.01369708 0.01369708 0.01369708 0.01369708 0.01369708 0.01369708
[,25] [,26] [,27] [,28] [,29] [,30] [,31] [,32]
[1,] 0.01419498 0.128644022 0.01419498 0.01419498 0.014194979 0.014194979 0.01419498 0.01419498
[2,] 0.01035351 0.010353508 0.01035351 0.01035351 0.041352822 0.041352822 0.01035351 0.04135282
[3,] 0.07356165 0.007190831 0.07356165 0.01369708 0.007190831 0.007190831 0.07356165 0.01369708
[,33] [,34] [,35]
[1,] 0.01419498 0.01419498 0.01419498
[2,] 0.01035351 0.01035351 0.01035351
[3,] 0.07356165 0.01369708 0.10274367

[[3]]
[1] 7 7 5 5 7 5 4 8 3

[[4]]
[1] 2 1 1 1 1 2 1 2 1 1 1 1 1 3 4 1 1 1 1 1 3 1 1 1 2 1 2 1 1 1 2 2 2 1 3

[[5]]
[1] "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17"
[19] "18" "19" "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30" "31" "32" "33" "34"



参考



Pythonコード

HDPを呼び出しに使ったPythonスクリプト。


Python実行環境

Python 2.7.12 (default, Jul 10 2016, 20:09:20) 

[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.


Python-HDP

import gensim

import pandas

# HDPにかけるテキスト
documents = ["Human machine interface for lab abc computer applications",
"A survey of user opinion of computer system response time",
"The EPS user interface management system",
"System and human system engineering testing of EPS",
"Relation of user perceived response time to error measurement",
"The generation of random binary unordered trees",
"The intersection graph of paths in trees",
"Graph minors IV Widths of trees and well quasi ordering",
"Graph minors A survey"]

# ストップワード定義
stoplist = set('for a of the and to in'.split())

# テキスト前処理
texts = [[word for word in document.lower().split() if word not in stoplist] for document in documents]
>>> pprint(texts)
[['human', 'machine', 'interface', 'lab', 'abc', 'computer', 'applications'],
['survey', 'user', 'opinion', 'computer', 'system', 'response', 'time'],
['eps', 'user', 'interface', 'management', 'system'],
['system', 'human', 'system', 'engineering', 'testing', 'eps'],
['relation', 'user', 'perceived', 'response', 'time', 'error', 'measurement'],
['generation', 'random', 'binary', 'unordered', 'trees'],
['intersection', 'graph', 'paths', 'trees'],
['graph', 'minors', 'iv', 'widths', 'trees', 'well', 'quasi', 'ordering'],
['graph', 'minors', 'survey']]

dictionary = gensim.corpora.Dictionary(texts)
>>> pprint(dictionary.token2id)
{u'abc': 0,
u'applications': 3,
u'binary': 22,
u'computer': 4,
u'engineering': 15,
u'eps': 14,
u'error': 18,
u'generation': 21,
u'graph': 26,
u'human': 5,
u'interface': 6,
u'intersection': 27,
u'iv': 33,
u'lab': 1,
u'machine': 2,
u'management': 13,
u'measurement': 20,
u'minors': 29,
u'opinion': 11,
u'ordering': 30,
u'paths': 28,
u'perceived': 17,
u'quasi': 34,
u'random': 23,
u'relation': 19,
u'response': 12,
u'survey': 8,
u'system': 7,
u'testing': 16,
u'time': 10,
u'trees': 25,
u'unordered': 24,
u'user': 9,
u'well': 32,
u'widths': 31}
corpus = [dictionary.doc2bow(text) for text in texts]
>>> pprint(corpus)
[[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1)],
[(4, 1), (7, 1), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1)],
[(6, 1), (7, 1), (9, 1), (13, 1), (14, 1)],
[(5, 1), (7, 2), (14, 1), (15, 1), (16, 1)],
[(9, 1), (10, 1), (12, 1), (17, 1), (18, 1), (19, 1), (20, 1)],
[(21, 1), (22, 1), (23, 1), (24, 1), (25, 1)],
[(25, 1), (26, 1), (27, 1), (28, 1)],
[(25, 1), (26, 1), (29, 1), (30, 1), (31, 1), (32, 1), (33, 1), (34, 1)],
[(8, 1), (26, 1), (29, 1)]]

# HDP実行
hdp = gensim.models.hdpmodel.HdpModel(corpus = corpus, id2word = dictionary, alpha = 1.0, T = 150)
pandas.DataFrame([dict(hdp[x]) for x in corpus])
0 1 2 3 4 5 6
0 0.153961 0.024102 0.017490 0.013135 0.763441 NaN NaN
1 0.424649 0.506962 0.017490 0.013132 NaN NaN NaN
2 0.234524 0.033107 0.664496 0.017517 0.013194 NaN NaN
3 0.894362 0.027382 0.020088 0.015006 0.011309 NaN NaN
4 0.907610 0.023981 0.017512 0.013130 NaN NaN NaN
5 0.052698 0.856097 0.023335 0.017514 0.013194 NaN NaN
6 0.054569 0.835891 0.028101 0.021013 0.015832 0.011575 NaN
7 0.029701 0.478424 0.015533 0.011674 NaN 0.437527 NaN
8 0.066220 0.797049 0.034939 0.026260 0.019790 0.014469 0.01079




実行環境


実行環境

Session info ----------------------------------------------------------------------------------------------------------------------

setting value
version R version 3.3.1 (2016-06-21)
system x86_64, darwin13.4.0
ui RStudio (1.0.44)
language (EN)
collate ja_JP.UTF-8
tz Asia/Tokyo
date 2016-10-30

Packages --------------------------------------------------------------------------------------------------------------------------
package * version date source
assertthat 0.1 2013-12-06 CRAN (R 3.3.1)
broom 0.4.1 2016-06-24 CRAN (R 3.3.0)
colorspace 1.2-6 2015-03-11 CRAN (R 3.3.1)
DBI 0.5 2016-08-11 cran (@0.5)
devtools 1.12.0 2016-06-24 CRAN (R 3.3.0)
digest 0.6.9 2016-01-08 CRAN (R 3.3.0)
dplyr * 0.5.0 2016-06-24 CRAN (R 3.3.1)
ggplot2 * 2.1.0 2016-03-01 CRAN (R 3.3.1)
gtable 0.2.0 2016-02-26 CRAN (R 3.3.1)
janeaustenr 0.1.1 2016-06-20 CRAN (R 3.3.0)
lattice 0.20-33 2015-07-14 CRAN (R 3.3.1)
magrittr 1.5 2014-11-22 CRAN (R 3.3.1)
Matrix 1.2-6 2016-05-02 CRAN (R 3.3.1)
memoise 1.0.0 2016-01-29 CRAN (R 3.3.0)
mnormt 1.5-4 2016-03-09 CRAN (R 3.3.0)
munsell 0.4.3 2016-02-13 CRAN (R 3.3.1)
nlme 3.1-128 2016-05-10 CRAN (R 3.3.1)
pacman * 0.4.1 2016-03-30 CRAN (R 3.3.0)
plyr 1.8.4 2016-06-08 CRAN (R 3.3.1)
psych 1.6.6 2016-06-28 CRAN (R 3.3.0)
R6 2.1.3 2016-08-19 cran (@2.1.3)
Rcpp 0.12.7 2016-09-05 cran (@0.12.7)
reshape2 1.4.1 2014-12-06 CRAN (R 3.3.1)
scales 0.4.0 2016-02-26 CRAN (R 3.3.1)
SnowballC 0.5.1 2014-08-09 CRAN (R 3.3.1)
stringi * 1.1.1 2016-05-27 CRAN (R 3.3.1)
stringr 1.1.0 2016-08-19 cran (@1.1.0)
tensorflow * 0.3.0 2016-10-25 Github (rstudio/tensorflow@dfe2f1a)
tibble * 1.2 2016-08-26 cran (@1.2)
tidyr * 0.6.0 2016-08-12 cran (@0.6.0)
tidytext * 0.1.1 2016-06-25 CRAN (R 3.3.0)
tokenizers 0.1.4 2016-08-29 CRAN (R 3.3.0)
withr 1.0.2 2016-06-20 CRAN (R 3.3.0)