findAssocs для нескольких терминов в R

В РИ использовали [tm package][1] для построения матрицы термодокументов из совокупности документов.

Моя цель - извлечь словосочетания из всех биграмм в матрице терминов документа и вернуть для каждой из трех первых или нескольких. Поэтому я ищу переменную, которая содержит все row.names из матрицы, поэтому функция findAssocs() может сделать свою работу

Это мой код до сих пор:

library(tm)
library(RWeka)
txtData <- read.csv("file.csv", header = T, sep = ",")
txtCorpus <- Corpus(VectorSource(txtData$text))

...further preprocessing

#Tokenizer for n-grams and passed on to the term-document matrix constructor
BigramTokenizer <- function(x) NGramTokenizer(x, Weka_control(min = 2, max = 2))
txtTdmBi <- TermDocumentMatrix(txtCorpus, control = list(tokenize = BigramTokenizer))

#term argument holds two words since the BigramTokenizer extracted all pairs from txtCorpus
findAssocs(txtTdmBi, "cat shop", 0.5)
cat cabi  cat scratch  ...
    0.96         0.91

Я попытался определить переменную со всеми row.names из txtTdmBi и скормить его findAssocs() функция. Однако со следующим результатом:

allRows <- c(row.names(txtTdmBi))
findAssocs(txtTdmBi, allRows, 0.5)
Error in which(x[term, ] > corlimit) : subscript out of bounds
In addition: Warning message:
In term == Terms(x) :
  longer object length is not a multiple of shorter object length

Поскольку извлечение ассоциаций для термина, потраченного на несколько матриц терминов-документов, уже объяснено здесь, я думаю, было бы возможно найти ассоциации для нескольких терминов в одной матрице терминов-документов. Кроме как?

Я надеюсь, что кто-то может объяснить мне, как решить эту проблему. Заранее спасибо за любую поддержку.

1 ответ

Решение

Если я правильно понимаю, lapply Решение, вероятно, способ ответить на ваш вопрос. Это тот же подход, что и ответ, на который вы ссылаетесь, но вот отдельный пример, который может быть ближе к вашему варианту использования:

Загрузите библиотеки и воспроизводимые данные (пожалуйста, включите их в ваши будущие вопросы здесь)

library(tm)
library(RWeka)
data(crude)

Ваш биграмный токенизатор...

#Tokenizer for n-grams and passed on to the term-document matrix constructor
BigramTokenizer <- function(x) NGramTokenizer(x, Weka_control(min = 2, max = 2))
txtTdmBi <- TermDocumentMatrix(crude, control = list(tokenize = BigramTokenizer))

Проверьте, что это сработало, проверив случайную выборку...

inspect(txtTdmBi[1000:1005, 10:15])
A term-document matrix (6 terms, 6 documents)

Non-/sparse entries: 1/35
Sparsity           : 97%
Maximal term length: 18 
Weighting          : term frequency (tf)

                    Docs
Terms                248 273 349 352 353 368
  for their            0   0   0   0   0   0
  for west             0   0   0   0   0   0
  forced it            0   0   0   0   0   0
  forced to            0   0   0   0   0   0
  forces trying        1   0   0   0   0   0
  foreign investment   0   0   0   0   0   0

Вот ответ на ваш вопрос:

Теперь используйте lapply функция для вычисления связанных слов для каждого элемента в векторе терминов в матрице терминов-документов. Вектор терминов наиболее просто доступен с txtTdmBi$dimnames$Terms, Например txtTdmBi$dimnames$Terms[[1005]] это "иностранные инвестиции".

Здесь я использовал llply от plyr пакет, чтобы мы могли иметь индикатор выполнения (удобно для больших рабочих мест), но он в основном такой же, как база lapply функция.

library(plyr)
dat <- llply(txtTdmBi$dimnames$Terms, function(i) findAssocs(txtTdmBi, i, 0.5), .progress = "text" )

Выходные данные представляют собой список, в котором каждый элемент списка представляет собой вектор именованных чисел, где имя является термином, а число является значением корреляции. Например, чтобы увидеть термины, связанные с "иностранными инвестициями", мы можем получить доступ к списку следующим образом:

dat[[1005]]

и вот термины, связанные с этим термином (я только что вставил в верхние несколько)

168 million              1986 was            1987 early               300 mln                31 pct 
                 1.00                  1.00                  1.00                  1.00                  1.00 
                a bit          a crossroads             a leading           a political          a population 
                 1.00                  1.00                  1.00                  1.00                  1.00 
            a reduced              a series            a slightly            about zero    activity continues 
                 1.00                  1.00                  1.00                  1.00                  1.00 
         advisers are   agricultural sector       agriculture the              all such          also reviews 
                 1.00                  1.00                  1.00                  1.00                  1.00 
         and advisers           and attract           and imports       and liberalised             and steel 
                 1.00                  1.00                  1.00                  1.00                  1.00 
            and trade           and virtual       announced since            appears to           are equally 
                 1.00                  1.00                  1.00                  1.00                  1.00 
     are recommending             areas for              areas of                 as it              as steps 
                 1.00                  1.00                  1.00                  1.00                  1.00 
            asia with          asian member    assesses indonesia           attract new            balance of 
                 1.00                  1.00                  1.00                  1.00                  1.00 

Это то, что вы хотите сделать?

Кстати, если у вас матрица терминологических документов очень большая, вы можете попробовать эту версию findAssocs:

# u is a term document matrix
# term is your term
# corlimit is a value -1 to 1

findAssocsBig <- function(u, term, corlimit){
  suppressWarnings(x.cor <-  gamlr::corr(t(u[ !u$dimnames$Terms == term, ]),        
                                         as.matrix(t(u[  u$dimnames$Terms == term, ]))  ))  
  x <- sort(round(x.cor[(x.cor[, term] > corlimit), ], 2), decreasing = TRUE)
  return(x)
}

Это можно использовать так:

dat1 <- llply(txtTdmBi$dimnames$Terms, function(i) findAssocsBig(txtTdmBi, i, 0.5), .progress = "text" )

Преимущество этого состоит в том, что он использует другой метод преобразования TDM в матрицу tm:findAssocs, Этот другой метод использует память более эффективно и поэтому предотвращает такого рода сообщения: Error: cannot allocate vector of size 1.9 Gb от происходящего.

Быстрый бенчмаркинг показывает, что оба findAssocs Функции имеют примерно одинаковую скорость, поэтому основное отличие заключается в использовании памяти:

library(microbenchmark)
microbenchmark(
dat1 <- llply(txtTdmBi$dimnames$Terms, function(i) findAssocsBig(txtTdmBi, i, 0.5)),
dat <- llply(txtTdmBi$dimnames$Terms, function(i) findAssocs(txtTdmBi, i, 0.5)),
times = 10)

Unit: seconds
                                                                                     expr      min       lq   median
 dat1 <- llply(txtTdmBi$dimnames$Terms, function(i) findAssocsBig(txtTdmBi,      i, 0.5)) 10.82369 11.03968 11.25492
     dat <- llply(txtTdmBi$dimnames$Terms, function(i) findAssocs(txtTdmBi,      i, 0.5)) 10.70980 10.85640 11.14156
       uq      max neval
 11.39326 11.89754    10
 11.18877 11.97978    10
Другие вопросы по тегам