この文書は Dmitriy Selivanov によるRパッケージtext2vec
(version 0.3.0) のビネット "Advanced topics" の日本語訳です.
ただし文中の注は全て訳者によるものです1.
License: MIT
関連文書
- text2vec vignette: text2vecパッケージによるテキスト分析
- text2vec vignette: GloVeによる単語埋め込み
- text2vec vignette: 発展的な話題
ファイルの取り扱い
この段落では,text2vec
を使ってファイルに保存された巨大なテキストの集合をベクトル化する方法を示します.
ldaパッケージでトピックモデルを構築したいとしましょう.映画レビューの集まりを,複数のテキストファイルでディスクに保存して持っているとします.
このビネットのために,組み込みのmovie_review
データセットからそのようなファイルを作成します.
library(text2vec)
library(magrittr)
data("movie_review")
# 読み込みを簡単にするために,全ての改行を除いておく
movie_review$review <- gsub(pattern = '\n', replacement = ' ',
x = movie_review$review, fixed = TRUE)
N_FILES <- 10
CHUNK_LEN <- nrow(movie_review) / N_FILES
files <- sapply(1:N_FILES, function(x) tempfile())
chunks <- split(movie_review, rep(1:N_FILES, each = nrow(movie_review) / N_FILES ))
for (i in 1:N_FILES ) {
write.table(chunks[[i]], files[[i]], quote = T, row.names = F, col.names = T, sep = '|')
}
# どんなデータか見ておく
str(movie_review, strict.width = 'cut')
## 'data.frame': 5000 obs. of 3 variables:
## $ id : chr "5814_8" "2381_9" "7759_3" "3630_4" ...
## $ sentiment: int 1 1 0 0 1 1 0 0 0 1 ...
## $ review : chr "With all this stuff going down at the moment with MJ"..
text2vec
はファイルを容易に扱うための関数群を提供します.
ユーザはほんのいくつかの作業を行う必要があるだけです.
-
ifiles
関数でファイルのイテレータを構築する.
-
ifiles
にファイル読込関数を与える.text2vec
は背後にあるファイルについては何も知りません.プレーンテキストでも何らかのバイナリ形式でも構いません.
-
itoken
関数によってファイルからトークンのイテレータを構築する.
どうやるのか見てみましょう.
library(data.table)
reader <- function(x, ...) {
# 読み込み
chunk <- fread(x, header = T, sep = '|')
# review列を選択
res <- chunk$review
# レビューにidを振る
names(res) <- chunk$id
res
}
# ファイルのイテレータを作成
it_files <- ifiles(files, reader_function = reader)
# ファイルのイテレータからトークンのイテレータを作成
it_tokens <- itoken(it_files, preprocess_function = tolower,
tokenizer = word_tokenizer, progessbar = FALSE)
vocab <- create_vocabulary(it_tokens)
これでDTMを(lda
パッケージで必要な)lda_c
形式で構築することができます.
# イテレータは再初期化が必要!
# イテレータは変更可能(mutable)で既に空になっている!
# try(it_files$nextElem())
it_files <- ifiles(files, reader_function = reader)
it_tokens <- itoken(it_files, preprocess_function = tolower,
tokenizer = word_tokenizer, progessbar = FALSE)
dtm <- create_dtm(it_tokens, vectorizer = vocab_vectorizer(vocab), type = 'lda_c')
str(dtm, list.len = 5)
## List of 5000
## $ 5814_8 : int [1:2, 1:228] 7489 1 7835 1 8174 3 8365 1 8816 4 ...
## $ 2381_9 : int [1:2, 1:109] 7835 1 8174 2 8816 2 9560 1 9562 1 ...
## $ 7759_3 : int [1:2, 1:253] 7593 1 7790 1 8174 1 8634 1 8708 1 ...
## $ 3630_4 : int [1:2, 1:218] 7410 1 7841 1 8174 1 8258 1 8572 1 ...
## $ 9495_8 : int [1:2, 1:256] 7489 1 7659 1 7835 1 7878 1 8174 1 ...
## [list output truncated]
DTMに文書IDが付いていることに注目してください.これらのIDはreader
関数で割り当てた名前から引き継がれています.ファイルを扱うときに文書IDを割り当てる便利な方法です.
これでlda::lda.collapsed.gibbs.sampler()
関数を使ってLDA
モデルをフィットさせることができます.
library(lda)
# トピックの事前分布
alpha = 0.1
# 単語の事前分布
eta = 0.001
# トピック30個のモデルをフィットさせる.Gibbsサンプリングは30回
lda_fit <- lda.collapsed.gibbs.sampler(documents = dtm, K = 30,
vocab = vocab$vocab$terms,
alpha = alpha,
eta = eta,
num.iterations = 30,
trace = 2L)
マルチコアを使った並列モード
create_dtm
, create_tcm
, create_vocabulary
はマルチコアのマシンを透過的なやり方で利用することができます.GloVeのフィッティングではRcppParallel
による低レベルスレッドの並列処理を使用するのとは対照的に,これらの関数はforeach
パッケージを通じて標準的なRの高レベル並列処理を使用します.これらの関数は柔軟であり,doParallel
やdoRedis
等,いろいろな並列処理バックエンドを使うことができます.ただし,このような高レベルの並列処理は大きなオーバーヘッドをもたらす可能性があるということをユーザは覚えておくべきです.
マルチコアのマシンを利用するのにユーザが手動で行うべき操作は2つだけです.
- 並列処理のバックエンドを登録する.
-
itoken
イテレータのリストの形式で分割された入力データを用意する.
以下は簡単な例です2.
N_WORKERS <- 4
library(doParallel)
## Loading required package: foreach
## Loading required package: iterators
## Loading required package: parallel
# 並列処理バックエンドを登録
registerDoParallel(N_WORKERS)
# 分割を用意する
# "jobs"はitokenイテレータのリスト!
N_SPLITS <- 4
jobs <- files %>%
split_into(N_SPLITS) %>%
lapply(ifiles, reader_function = reader) %>%
# 既に入力データを分割してあるので,chunks_numberは1にするのがよい
lapply(itoken, chunks_number = 1, preprocess_function = tolower,
tokenizer = word_tokenizer, progessbar = FALSE)
# あるいは,データがメモリ上にある時は以下のようにして分割を実行することが可能
#
# review_chunks <- split_into(movie_review$review, N_SPLITS)
# review_ids <- split_into(movie_review$id, N_SPLITS)
#
# jobs <- Map(function(doc, ids) {
# itoken(iterable = doc, ids = ids, preprocess_function = tolower,
# tokenizer = word_tokenizer, chunks_number = 1, progessbar = FALSE)
# }, review_chunks, review_ids)
# 以降の関数呼び出しは全てマルチコアの恩恵を受ける
# それぞれのjobが別々のプロセスで評価される
# 語彙の作成
vocab <- create_vocabulary(jobs)
# 語彙でベクトル化したDTM
v_vectorizer <- vocab_vectorizer(vocab)
vocab_dtm_parallel <- create_dtm(jobs, vectorizer = v_vectorizer)
# 素性ハッシングでベクトル化したDTM
h_vectorizer <- hash_vectorizer()
hash_dtm_parallel <- create_dtm(jobs, vectorizer = h_vectorizer)
# 共起回数の統計
tcm_vectorizer <- vocab_vectorizer(vocab, grow_dtm = FALSE, skip_grams_window = 5)
tcm_parallel <- create_tcm(jobs, vectorizer = tcm_vectorizer)
-
訳者の環境を示しておく.
devtools::session_info()
## Session info --------------------------------------------------------------
## setting value ## version R version 3.3.1 (2016-06-21) ## system x86_64, linux-gnu ## ui X11 ## language (EN) ## collate ja_JP.UTF-8 ## tz <NA> ## date 2016-09-04
## Packages ------------------------------------------------------------------
↩## package * version date source ## Matrix 1.2-7.1 2016-09-01 CRAN (R 3.3.1) ## Rcpp 0.12.3 2016-01-10 CRAN (R 3.2.3) ## RcppParallel 4.3.20 2016-08-16 CRAN (R 3.3.1) ## chron 2.3-47 2015-06-24 CRAN (R 3.2.1) ## codetools 0.2-14 2015-07-15 CRAN (R 3.3.1) ## data.table * 1.9.6 2015-09-19 CRAN (R 3.3.1) ## devtools 1.12.0 2016-06-24 CRAN (R 3.3.1) ## digest 0.6.9 2016-01-08 CRAN (R 3.2.3) ## doParallel * 1.0.10 2015-10-14 CRAN (R 3.3.1) ## evaluate 0.9 2016-04-29 CRAN (R 3.3.1) ## foreach * 1.4.3 2015-10-13 CRAN (R 3.3.1) ## formatR 1.2.1 2015-09-18 CRAN (R 3.2.3) ## htmltools 0.3.5 2016-03-21 CRAN (R 3.3.1) ## iterators * 1.0.8 2015-10-13 CRAN (R 3.2.2) ## knitr 1.14 2016-08-13 CRAN (R 3.3.1) ## lattice 0.20-33 2015-07-14 CRAN (R 3.2.1) ## lda * 1.4.2 2015-11-22 CRAN (R 3.3.1) ## magrittr * 1.5 2014-11-22 CRAN (R 3.3.1) ## memoise 1.0.0 2016-01-29 CRAN (R 3.3.1) ## rmarkdown 1.0 2016-07-08 CRAN (R 3.3.1) ## stringi 1.0-1 2015-10-22 CRAN (R 3.2.2) ## stringr 1.0.0 2015-04-30 CRAN (R 3.2.2) ## text2vec * 0.3.0 2016-03-31 CRAN (R 3.3.1) ## withr 1.0.2 2016-06-20 CRAN (R 3.3.1) ## yaml 2.1.13 2014-06-12 CRAN (R 3.2.3)
-
doParallel
の仕様により,以下のコードはWindowsでは動作しない.Windowsで動かすには,訳者は未検証だがこのあたりが参考になるかもしれない. ↩