无论文档边界如何,都可以有效地计算大型语料库中的词频

Calculating term frequencies in a big corpus efficiently regardless of document boundaries

我有一个包含近 200 万文档的语料库。我想计算词条在整个语料库中的词频,不考虑文档边界。

一种天真的方法是将所有文档组合成一个非常大的文档并将其矢量化。

一种精心设计的方法是使用 tm 或任何工具构建一个完整的 TDM,其中可以得到每个文档中每个词项的词频,从而获得整个语料库中的词频。这是我的做法:

# Build a TDM from the 'corpus' tibble using a filtered 'texts' column:

htgs = VCorpus(VectorSource(subset(x = corpus,
                                   subset = condition)$texts))
# Some preprocessing
htgs = preprocess(htgs)

# Consider terms whose length is between 2 and Inf in the TDM (the default is 3 to Inf):
dtm_htgs = TermDocumentMatrix(htgs,
                              control = list(wordLengths=c(2, Inf)))
> dtm_htgs
<<TermDocumentMatrix (terms: 495679, documents: 1983567)>>
Non-/sparse entries: 5361931/983207145062
Sparsity           : 100%
Maximal term length: 170
Weighting          : term frequency (tf)

但是,如果尝试解压缩由此尝试产生的稀疏矩阵,预计会发出内存错误:

> m = as.matrix(dtm_htgs)

Error: cannot allocate vector of size 7325.5 Gb

如何忽略每个文档的计数而将整个语料库中的全局术语频率作为一个整体来满足,这样可以节省大量内存?

如果我将 VectorSource 的输入数据结构从 character vector 更改为 tibble,我显然得到了我想要的,因为该函数会自动将所有文本整合到一个文档中:

> class(subset(corpus, condition)$texts)
[1] "character"
> class(subset(corpus, condition, select = texts))
[1] "tbl_df"     "tbl"        "data.frame"
htgs = VCorpus(VectorSource(subset(x = corpus,
                                   subset = condition,
                                   select = texts)))

# Same code as in the question: 
htgs = preprocess(htgs)
dtm_htgs = TermDocumentMatrix(htgs,
                              control = list(wordLengths=c(2, Inf)))
> dtm_htgs
<<TermDocumentMatrix (terms: 495679, documents: 1)>>
Non-/sparse entries: 495679/0
Sparsity           : 0%
Maximal term length: 170
Weighting          : term frequency (tf)

最后可以使用以下方法简单地获得频率计数:

m = as.matrix(dtm_htgs)

# Corpus counts
v = sort(rowSums(m),decreasing=TRUE)
d = data.frame(word = names(v),freq=unname(v))

这实际上消除了稀疏性并节省了大量 RAM,效率极高,使我能够继续处理数据。

在分析了 10 个文档样本后,我发现生成的词频是有效的。可能有更简单的方法来实现这一点,但他的方法非常有效并且可以完成工作。

您也可以试试:

library("quanteda")

topfeats <- tokens(corpus$text, remove_punct = TRUE) %>%
  dfm() %>%
  topfeatures()

根据您的 RAM 和文档的大小,它应该可以处理 200 万个文档。结果是全局术语频率的命名向量,其中名称是术语,值是频率。