Удалить пустые документы из 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

(это было сделано с dtm 4000x15000)

Похоже, что узким местом является применение 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
Для меня вторая строка кода вызвала эту ошибку Ошибка в [.VCorpus (корпус, 1, 1): неиспользуемый аргумент (1). Я изменил его на corpus ‹- corpus [-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