将文档词矩阵转换为数据量巨大的矩阵会导致溢出问题。

14

让我们进行一些文本挖掘

这里我有一个文档术语矩阵(来自tm软件包)

dtm <- TermDocumentMatrix(
     myCorpus,
     control = list(
         weight = weightTfIdf,
         tolower=TRUE,
         removeNumbers = TRUE,
         minWordLength = 2,
         removePunctuation = TRUE,
         stopwords=stopwords("german")
      ))

当我执行一个

typeof(dtm)

我看到这是一个“列表”,结构看起来像这样:


Docs
Terms        1 2 ...
  lorem      0 0 ...
  ipsum      0 0 ...
  ...        .......

所以我尝试了一个 <\p>
wordMatrix = as.data.frame( t(as.matrix(  dtm )) ) 

这对于1000个文档是可行的。

但当我尝试使用40000个文档时,就不再行得通了。

我会收到如下错误:

Fehler in vector(typeof(x$v), nr * nc) : Vektorgröße kann nicht NA sein
Zusätzlich: Warnmeldung:
In nr * nc : NAs durch Ganzzahlüberlauf erzeugt

向量中出现错误...:向量不能是NA 附加信息: 在nr * nc中,由于整数溢出而创建了N个NA

所以我查看了as.matrix,发现该函数会将其转换为一个向量,然后再转换为矩阵。转换为向量可以正常工作,但是从向量到矩阵的转换却不行。

您有什么建议吗?

谢谢,船长


2
一个简单的方法来使你的 DTM 在内存限制下是使用 tm::removeSparseTerms 函数来删除稀疏项。 - Ben
1
避免在文档中包含非常罕见或仅出现一次的术语的简单方法是使用 DocumentTermMatrix(..., control(... bounds=list(global = c(N,Inf)))),并将 N 设置为例如 2、3、4... 直到大小足够小。 - smci
3个回答

17

整数溢出告诉你问题出在哪里:有40000个文档,数据太多了。顺便说一下,问题始于转换为矩阵,如果查看底层函数的代码,就能看到这一点:

class(dtm)
[1] "TermDocumentMatrix"    "simple_triplet_matrix"

getAnywhere(as.matrix.simple_triplet_matrix)

A single object matching ‘as.matrix.simple_triplet_matrix’ was found
...
function (x, ...) 
{
    nr <- x$nrow
    nc <- x$ncol
    y <- matrix(vector(typeof(x$v), nr * nc), nr, nc)
   ...
}

这是错误信息所引用的那一行。可以通过以下方式轻松模拟出问题的原因:

as.integer(40000 * 60000) # 40000 documents is 40000 rows in the resulting frame
[1] NA
Warning message:
NAs introduced by coercion 
函数vector()接受一个长度参数,本例中为nr * nc,如果该参数大于约2e9(.Machine$integer.max),则会被替换为NA。这个NA不能作为vector()的参数。
简而言之:您已经遇到了R语言的限制。目前来看,使用64位也无法解决问题。您需要采用不同的方法。一种可能的方法是继续使用您拥有的列表(dtm是一个列表),使用列表操作选择所需的数据,然后进行下一步操作。
注:我通过以下方式创建了一个dtm对象
require(tm)
data("crude")
dtm <- TermDocumentMatrix(crude,
                          control = list(weighting = weightTfIdf,
                                         stopwords = TRUE))

谢谢你的澄清。我会尝试解析dtm,并希望能够成功进行转换。 - Captain Cook

4

这里是我最近发现的一个非常简单的解决方案

DTM=t(TDM)#taking the transpose of Term-Document Matrix though not necessary but I prefer DTM over TDM
M=as.big.matrix(x=as.matrix(DTM))#convert the DTM into a bigmemory object using the bigmemory package 
M=as.matrix(M)#convert the bigmemory object again to a regular matrix
M=t(M)#take the transpose again to get TDM

请注意,将TDM转置为DTM是完全可选的,这是我个人喜好,用这种方式处理矩阵。
附注:4年前我还是大学新生,无法回答这个问题。

0
根据Joris Meys的回答,我找到了解决方案。"vector()"关于"length"参数的文档如下:

... 对于一个长向量,即长度大于.Machine$integer.max,它必须是"double"类型...

因此我们可以对as.matrix()进行微小的修复:
as.big.matrix <- function(x) {
  nr <- x$nrow
  nc <- x$ncol
  # nr and nc are integers. 1 is double. Double * integer -> double
  y <- matrix(vector(typeof(x$v), 1 * nr * nc), nr, nc)
  y[cbind(x$i, x$j)] <- x$v
  dimnames(y) <- x$dimnames
  y
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接