Премахване на празни документи от DocumentTermMatrix в R topicmodels?

Правя моделиране на теми, използвайки пакета topicmodels в R. Създавам обект Corpus, извършвам основна предварителна обработка и след това създавам DocumentTermMatrix:

corpus <- Corpus(VectorSource(vec), readerControl=list(language="en")) 
corpus <- tm_map(corpus, tolower)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords("english"))
corpus <- tm_map(corpus, stripWhitespace)
corpus <- tm_map(corpus, removeNumbers)
...snip removing several custom lists of stopwords...
corpus <- tm_map(corpus, stemDocument)
dtm <- DocumentTermMatrix(corpus, control=list(minDocFreq=2, minWordLength=2))

И след това изпълнява LDA:

LDA(dtm, 30)

Това последно извикване на LDA() връща грешката

  "Each row of the input matrix needs to contain at least one non-zero entry". 

Предполагам, че това означава, че има поне един документ, в който няма условия след предварителната обработка. Има ли лесен начин за премахване на документи, които не съдържат термини, от DocumentTermMatrix?

Погледнах в документацията за пакета topicmodels и намерих функцията removeSparseTerms, която премахва термини, които не фигурират в нито един документ, но няма аналог за премахване на документи.


person Bill M    schedule 19.12.2012    source източник
comment
Когато правите проверка (корпус), виждате ли някакъв празен документ? а LDA в кой пакет е?   -  person agstudy    schedule 19.12.2012
comment
Използвам функцията LDA от пакета topicmodels. Имам около 51 000 документа, така че не мога да проверя ръчно с inspect. Освен това е възможно някои термини да бъдат премахнати от параметрите minDocFreq=2, minWordLength=2, така че това, което наистина искам да проверя, е DocumentTermMatrix. Има ли друг начин за намиране на празни документи?   -  person Bill M    schedule 19.12.2012


Отговори (6)


"Each row of the input matrix needs to contain at least one non-zero entry"

Грешката означава, че разредената матрица съдържа ред без записи (думи). една идея е да се изчисли сумата от думи по ред

rowTotals <- apply(dtm , 1, sum) #Find the sum of words in each Document
dtm.new   <- dtm[rowTotals> 0, ]           #remove all docs without words
person agstudy    schedule 19.12.2012
comment
Това работи добре. Не осъзнавах, че DocumentTermMatrix може да бъде индексиран по този начин. Благодаря! - person Bill M; 20.12.2012
comment
@BillM това е матрица, специално да (разредена), но все пак матрица. - person agstudy; 20.12.2012
comment
Това решение има един потенциален проблем: получената матрица без документи с нулеви думи вече няма да съответства на оригиналния корпус, т.е. ще има по-малък брой редове. Следователно няма да е възможно да се използва резултатът от LDA за категоризиране на корпуса (например чрез присвояване на най-добрия клъстер на всеки документ). Някаква идея как да се реши това? - person Dario Lacan; 08.12.2014
comment
Получавам тази грешка: rror in vector(typeof(x$v), nr * nc) : vector size cannot be NA In addition: Warning message: In nr * nc : NAs produced by integer overflow - person Morry; 27.12.2014
comment
В един ред, без използване на приложение: dtm[rowSums(dtm)>0,] - person christopherlovell; 04.08.2015

Отговорът на agstudy работи чудесно, но използването му на бавен компютър се оказа леко проблематично.

tic()
row_total = apply(dtm, 1, sum)
dtm.new = dtm[row_total>0,]
toc()
4.859 sec elapsed

(това беше направено с 4000x15000 dtm)

Тесното място изглежда прилага sum() към разредена матрица.

Матрица-термин-документ, създадена от пакета tm, съдържа имената i и j, които са индекси за това къде са записите в разредената матрица. Ако dtm$i не съдържа определен индекс на ред p, тогава ред p е празен.

tic()
ui = unique(dtm$i)
dtm.new = dtm[ui,]
toc()
0.121 sec elapsed

ui съдържа всички ненулеви индекси и тъй като dtm$i вече е подреден, dtm.new ще бъде в същия ред като dtm. Увеличаването на производителността може да няма значение за по-малки матрици на термини на документи, но може да стане значително при по-големи матрици.

person SylphFeather    schedule 14.06.2016
comment
Това решение е по-добро от предишното по отношение на необходимата памет! - person 0xF; 19.09.2018

Това е само за уточняване на отговора, даден от agstudy.

Вместо да премахваме празните редове от dtm матрицата, можем да идентифицираме документите в нашия корпус с нулева дължина и да премахнем документите директно от корпуса, преди да изпълним втори dtm само с непразни документи.

Това е полезно за поддържане на съответствие 1:1 между dtm и корпуса.

empty.rows <- dtm[rowTotals == 0, ]$dimnames[1][[1]] corpus <- corpus[-as.numeric(empty.rows)]

person Dario Lacan    schedule 31.01.2015
comment
За мен вторият ред на кода хвърли тази грешка Error in [.VCorpus(corpus, 1, 1) : unused argument (1). Модифицирах го на корпус ‹- корпус[-as.numeric(empty.rows)] - person user131476; 14.04.2015
comment
Корпусът е списък, така че не можете да използвате 2D селекция. Вие просто искате corpus[-as.numeric(empty.rows)] (т.е. едно измерение). - person neverfox; 28.04.2015

Просто премахнете редките термини от DTM и всичко ще работи добре.

dtm <- DocumentTermMatrix(crude, sparse=TRUE)
person Arijay Chaudhry    schedule 16.11.2015
comment
dtm‹-removeSparseTerms(dtm, sparse=0.98) - person Arijay Chaudhry; 26.08.2016

Само малко допълнение към отговора на Дарио Лакан:

empty.rows <- dtm[rowTotals == 0, ]$dimnames[1][[1]]

ще събира id на записа, а не номерата на поръчките. Опитайте тази:

library(tm)
data("crude")
dtm <- DocumentTermMatrix(crude)
dtm[1, ]$dimnames[1][[1]] # return "127", not "1"

Ако изградите свой собствен корпус с последователна номерация, след почистване на данните някои документи могат да бъдат премахнати и номерацията също ще бъде нарушена. Така че е по-добре да използвате id директно:

corpus <- tm_filter(
  corpus,
  FUN = function(doc) !is.element(meta(doc)$id, empty.rows))
  # !( meta(doc)$id %in% emptyRows )
)
person Bernitske    schedule 29.07.2015

Имах колона в рамка с данни lt$title, която съдържаше низове. Нямах "празни" редове в тази колона, но все пак получих грешката:

Грешка в LDA(dtm, k = 20, control = list(seed = 813)): Всеки ред на входната матрица трябва да съдържа поне един ненулев запис

Някои от решенията по-горе не работеха за мен, тъй като трябваше да присъединя вектора от предвидени теми към първоначалната си рамка от данни. Така че премахването на ненулеви записи от матрицата на документа не беше опция.

Проблемът беше, че някои (много кратки) низове в lt$title съдържаха специални знаци, които не можеха да бъдат обработени от Corpus() и/или DocumentTermMatrix().

Моето решение беше да премахна "късите" низове (максимум една или две думи), които така или иначе не носят много информация.

# Clean up text data
lt$test=nchar(lt$title)
lt = lt[!lt$test<10,]
lt$test<-NULL

# Topic modeling
corpus <- Corpus(VectorSource(lt$title))
dtm = DocumentTermMatrix(corpus)
tm = LDA(dtm, k = 20, control = list(seed = 813))

# Add "topics" to original DF
lt$topic = topics(tm)
person Peter    schedule 22.04.2020