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