按文档提取 tf-idf topfeatures 的正确方法是什么?

What's the correct way to extract tf-idf topfeatures by document?

假设我们有一个来自 10K 相当小文档的语料库的 tf-idf 加权 dfm。

quanteda 提取顶级特征(即文档的最大 tf-idf 值)的方法是什么? 我确实希望整个语料库成为计算 tf-idf 时的参考。类似于

topfeatures(some_dfm_tf_idf, n =3, decreasing = TRUE, groups ="id")

returns 一个适当的列表。然而,这时基本上已经整理好的东西需要相当长的时间。鉴于 quanteda 在我迄今为止所做的一切中都表现得如此出色,我怀疑我在这里可能做错了什么。

也许这与关于 github (https://github.com/quanteda/quanteda/issues/1646) 的讨论和 @Astelix 显示的示例解决方法有关。

topfeatures() 正是要走的路。我不确定你为什么要说它 "takes quite some time",或者你的 "id" docvar 是什么,但以下是获取 dfm 中得分最高的功能列表的正确且最有效的方法(不考虑权重)。

结果是一个命名列表,其中名称是文档名,每个元素是一个命名数值向量,其中元素名称是特征标签。

library("quanteda")
## Package version: 1.5.2

some_dfm_tf_idf <- dfm(data_corpus_irishbudget2010)[1:5, ] %>%
  dfm_tfidf()

topfeatures(some_dfm_tf_idf, n = 1, groups = docnames(some_dfm_tf_idf))
## $`Lenihan, Brian (FF)`
## details 
## 5.57116 
## 
## $`Bruton, Richard (FG)`
## confront 
##  5.59176 
## 
## $`Burton, Joan (LAB)`
## lenihan 
## 4.19382 
## 
## $`Morgan, Arthur (SF)`
##    sinn 
## 5.59176 
## 
## $`Cowen, Brian (FF)`
## dividend 
##  4.19382

topfeatures() 有点慢,因为它对每个特征进行排序,然后 return 是最高值。获取每个文档中最有价值的特征的更有效方法是使用 max.col。这是方法和比较(将 return 放在与 topfeatures() 答案格式相同的列表中)。

library("quanteda")
## Package version: 1.5.2

data(data_corpus_sotu, package = "quanteda.corpora")
dfmat <- dfm(data_corpus_sotu) %>%
  dfm_tfidf()

# alternative using max.col
get_top_feature <- function(x) {
  topfeature_index <- max.col(x, "first")
  result <- mapply(function(a, b) {
    l <- as.numeric(x[a, b])
    names(l) <- featnames(x)[b]
    l
  },
  seq_len(ndoc(x)), topfeature_index,
  SIMPLIFY = FALSE
  )
  names(result) <- docnames(x)
  result
}

microbenchmark::microbenchmark(
  topfeatures = topfeatures(dfmat, n = 1, groups = docnames(dfmat)),
  maxcol = get_top_feature(dfmat),
  times = 20, unit = "relative"
)
## Unit: relative
##         expr      min       lq     mean   median       uq      max neval
##  topfeatures 2.085184 2.113136 2.069444 2.104166 2.032536 1.987218    20
##       maxcol 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    20

除了 Ken 的 get_top_feature(),您可能不仅对“顶级”术语感兴趣,而且对 tfidf-dtm 中权重第二高的术语感兴趣。我花了一些时间才弄明白,所以我认为它可能对一般情况有所帮助。

get_scnd_feature <- function(x) {
topfeature_index <- max.col(x, 'first')
scndfeature_index <- max.col(replace(x, cbind(seq_len(nrow(x)), topfeature_index), -Inf), 'first')
  result <- mapply(function(a, b) {
    l <- as.numeric(x[a, b])
    names(l) <- featnames(x)[b]
    l
  },
  seq_len(ndoc(x)), scndfeature_index,
  SIMPLIFY = FALSE
  )
  names(result) <- docnames(x)
  result
}
scndterm_tfidf <- get_scnd_feature(dtmtfidf)

您可以通过比较权重来查看结果:

maxn <- function(n) function(x) order(x, decreasing = TRUE)[n]
scndtermcount <- apply(dtmtfidf, 1, function(x)x[maxn(2)(x)])