42

私はRのtopicmodelsパッケージを使用してトピックモデリングを行っています。コーパスオブジェクトを作成し、いくつかの基本的な前処理を行ってから、DocumentTermMatrixを作成しています。

corpus <- Corpus(VectorSource(vec), readerControl=list(language="en")) 
corpus <- tm_map(corpus, tolower)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords("english"))
corpus <- tm_map(corpus, stripWhitespace)
corpus <- tm_map(corpus, removeNumbers)
...snip removing several custom lists of stopwords...
corpus <- tm_map(corpus, stemDocument)
dtm <- DocumentTermMatrix(corpus, control=list(minDocFreq=2, minWordLength=2))

そして、LDAを実行します。

LDA(dtm, 30)

このLDA()の最後の呼び出しは、エラーを返します

  "Each row of the input matrix needs to contain at least one non-zero entry". 

これは、前処理後に用語が含まれていないドキュメントが少なくとも1つあることを意味すると思います。DocumentTermMatrixから用語を含まないドキュメントを削除する簡単な方法はありますか?

topicmodelsパッケージのドキュメントを調べたところ、関数removeSparseTermsが見つかりました。この関数は、どのドキュメントにも表示されない用語を削除しますが、ドキュメントを削除するための類似物はありません。

4

6 に答える 6

62
"Each row of the input matrix needs to contain at least one non-zero entry"

このエラーは、疎行列にエントリ (単語) のない行が含まれていることを意味します。1つのアイデアは、行ごとに単語の合計を計算することです

rowTotals <- apply(dtm , 1, sum) #Find the sum of words in each Document
dtm.new   <- dtm[rowTotals> 0, ]           #remove all docs without words
于 2012-12-19T21:14:13.343 に答える
28

agstudy の答えはうまく機能しますが、低速のコンピューターで使用すると、やや問題があることがわかりました。

tic()
row_total = apply(dtm, 1, sum)
dtm.new = dtm[row_total>0,]
toc()
4.859 sec elapsed

(これは 4000x15000 dtm で行われました)

sum()ボトルネックは疎行列に適用されているようです。

パッケージによって作成された document-term-matrixtmには、名前 i および j が含まれます。これらは、エントリがスパース マトリックス内のどこにあるかのインデックスです。dtm$iに特定の行インデックスが含まれていない場合p、行pは空です。

tic()
ui = unique(dtm$i)
dtm.new = dtm[ui,]
toc()
0.121 sec elapsed

uiにはゼロ以外のすべてのインデックスが含まれており、dtm$iは既に順序付けdtm.newされているため、 と同じ順序になりdtmます。パフォーマンスの向上は、ドキュメント ターム マトリックスが小さい場合は問題にならない可能性がありますが、マトリックスが大きい場合は顕著になる可能性があります。

于 2016-06-14T22:46:54.830 に答える
12

これは、agstudy によって与えられた答えを詳しく説明するためのものです。

dtm マトリックスから空の行を削除する代わりに、長さがゼロのコーパス内のドキュメントを特定し、そのドキュメントをコーパスから直接削除してから、空でないドキュメントのみを使用して 2 回目の dtm を実行できます。

これは、dtm とコーパスの間で 1 対 1 の対応を維持するのに役立ちます。

empty.rows <- dtm[rowTotals == 0, ]$dimnames[1][[1]] corpus <- corpus[-as.numeric(empty.rows)]

于 2015-01-31T10:22:50.143 に答える
0

ダリオ・ラカンの答えへのちょっとした補遺:

empty.rows <- dtm[rowTotals == 0, ]$dimnames[1][[1]]

idは、注文番号ではなくレコードの を収集します。これを試して:

library(tm)
data("crude")
dtm <- DocumentTermMatrix(crude)
dtm[1, ]$dimnames[1][[1]] # return "127", not "1"

連続番号を使用して独自のコーパスを構築すると、データ クリーニング後に一部のドキュメントが削除され、番号も壊れます。したがって、id直接使用することをお勧めします。

corpus <- tm_filter(
  corpus,
  FUN = function(doc) !is.element(meta(doc)$id, empty.rows))
  # !( meta(doc)$id %in% emptyRows )
)
于 2015-07-29T05:03:15.047 に答える