3

基于创建语料库和 DTM 的更有效方法的问题,我准备了自己的方法,用于从大型语料库构建术语文档矩阵,(我希望)不需要术语 x 文档内存。

sparseTDM <- function(vc){
  id = unlist(lapply(vc, function(x){x$meta$id}))
  content = unlist(lapply(vc, function(x){x$content}))
  out = strsplit(content, "\\s", perl = T)
  names(out) = id
  lev.terms = sort(unique(unlist(out)))
  lev.docs = id

  v1 = lapply(
    out,
    function(x, lev) {
      sort(as.integer(factor(x, levels = lev, ordered = TRUE)))
    },
    lev = lev.terms
  )

  v2 = lapply(
    seq_along(v1),
    function(i, x, n){
      rep(i,length(x[[i]]))
    },
    x = v1,
    n = names(v1)
  )

  stm = data.frame(i = unlist(v1), j = unlist(v2)) %>%
    group_by(i, j) %>%
    tally() %>%
    ungroup()

  tmp = simple_triplet_matrix(
    i = stm$i,
    j = stm$j,
    v = stm$n,
    nrow = length(lev.terms),
    ncol = length(lev.docs),
    dimnames = list(Terms = lev.terms, Docs = lev.docs)
  )

  as.TermDocumentMatrix(tmp, weighting = weightTf)
}

它在计算时变慢v1。它运行了 30 分钟,我停止了它。

我准备了一个小例子:

b = paste0("string", 1:200000)
a = sample(b,80)
microbenchmark(
  lapply(
    list(a=a),
    function(x, lev) {
      sort(as.integer(factor(x, levels = lev, ordered = TRUE)))
    },
    lev = b
  )
)

结果是:

Unit: milliseconds
expr      min       lq      mean   median       uq      max neval
...  25.80961 28.79981  31.59974 30.79836 33.02461 98.02512   100

id和content有126522个元素,Lev.terms有155591个元素,看来我已经停止处理太早了。因为最终我将处理大约 6M 的文档,我需要问......有什么方法可以加快这段代码的速度吗?

4

3 回答 3

1

现在我已经加快了更换速度

sort(as.integer(factor(x, levels = lev, ordered = TRUE)))

ind = which(lev %in% x)
cnt = as.integer(factor(x, levels = lev[ind], ordered = TRUE))
sort(ind[cnt])

现在时间是:

expr      min       lq     mean   median       uq      max neval
...  5.248479 6.202161 6.892609 6.501382 7.313061 10.17205   100
于 2015-04-07T14:11:50.633 回答
1

我在创建过程中经历了多次解决问题的迭代quanteda::dfm()(请参阅此处的 GitHub 存储库),到目前为止,最快的解决方案涉及使用data.tableMatrix包来索引文档和标记化特征,计算文档中的特征,并将结果直接插入像这样的稀疏矩阵:

require(data.table)
require(Matrix)

dfm_quanteda <- function(x) {
    docIndex <- 1:length(x)
    if (is.null(names(x))) 
        names(docIndex) <- factor(paste("text", 1:length(x), sep="")) else
            names(docIndex) <- names(x)

    alltokens <- data.table(docIndex = rep(docIndex, sapply(x, length)),
                            features = unlist(x, use.names = FALSE))
    alltokens <- alltokens[features != ""]  # if there are any "blank" features
    alltokens[, "n":=1L]
    alltokens <- alltokens[, by=list(docIndex,features), sum(n)]

    uniqueFeatures <- unique(alltokens$features)
    uniqueFeatures <- sort(uniqueFeatures)

    featureTable <- data.table(featureIndex = 1:length(uniqueFeatures),
                               features = uniqueFeatures)
    setkey(alltokens, features)
    setkey(featureTable, features)

    alltokens <- alltokens[featureTable, allow.cartesian = TRUE]
    alltokens[is.na(docIndex), c("docIndex", "V1") := list(1, 0)]

    sparseMatrix(i = alltokens$docIndex, 
                 j = alltokens$featureIndex, 
                 x = alltokens$V1, 
                 dimnames=list(docs=names(docIndex), features=uniqueFeatures))
}

require(quanteda)
str(inaugTexts)
## Named chr [1:57] "Fellow-Citizens of the Senate and of the House of Representatives:\n\nAmong the vicissitudes incident to life no event could ha"| __truncated__ ...
## - attr(*, "names")= chr [1:57] "1789-Washington" "1793-Washington" "1797-Adams" "1801-Jefferson" ...
tokenizedTexts <- tokenize(toLower(inaugTexts), removePunct = TRUE, removeNumbers = TRUE)
system.time(dfm_quanteda(tokenizedTexts))
##  user  system elapsed 
## 0.060   0.005   0.064 

当然,这只是一个片段,但完整的源代码很容易在 GitHub 存储库 ( dfm-main.R) 上找到。

我还鼓励您使用dfm()包装中的全部内容。您可以使用以下命令从 CRAN 或开发版本安装它:

devtools::install_github("kbenoit/quanteda")

在你的文本上,看看它在性能方面是如何工作的。

于 2015-07-09T05:27:09.543 回答
0

您是否尝试过使用排序方法(算法)并指定快速排序或 shell 排序?

就像是:

sort(as.integer(factor(x, levels = lev, ordered = TRUE)), method=shell)

或者:

sort(as.integer(factor(x, levels = lev, ordered = TRUE)), method=quick)

此外,如果排序算法一次又一次地重新执行这些步骤,您可以尝试使用一些中间变量来评估嵌套函数:

foo<-factor(x, levels = lev, ordered = TRUE)
bar<-as.integer(foo)
sort(bar, method=quick)

或者

sort(bar)

祝你好运!

于 2015-04-05T23:56:41.257 回答