Какой подход?
data.table
— это определенно правильный путь. Операции регулярных выражений медленные, хотя операции в stringi
намного быстрее (помимо того, что они намного лучше). Что-нибудь с
Я прошел много итераций решения проблемы при создании quanteda::dfm()
для моего пакета quanteda (см. репозиторий GitHub здесь ). На сегодняшний день самое быстрое решение включает в себя использование пакетов data.table
и Matrix
для индексации документов и токенизированных функций, подсчета функций в документах и включения результата прямо в разреженную матрицу.
В приведенном ниже коде я взял за пример тексты, найденные с пакетом quanteda, который вы можете (и должны!) установить из CRAN или версию для разработки из
devtools::install_github("kbenoit/quanteda")
Мне было бы очень интересно посмотреть, как это работает с вашими 4-метровыми документами. Судя по моему опыту работы с корпусами такого размера, это будет работать довольно хорошо (если у вас достаточно памяти).
Обратите внимание, что во всех моих профилированиях я не мог повысить скорость операций data.table с помощью какого-либо распараллеливания из-за того, как они написаны на C++.
Ядро функции Quanteda dfm()
Вот костяк исходного кода, основанного на data.table
, на случай, если кто-то захочет попробовать его улучшить. Он принимает на вход список векторов символов, представляющих токенизированные тексты. В пакете Quanteda полнофункциональный dfm()
работает непосредственно с символьными векторами документов или объектами корпуса напрямую и реализует строчные буквы, удаление чисел и удаление пробелов по умолчанию (но все это можно изменить при желании).
require(data.table)
require(Matrix)
dfm_quanteda <- function(x) {
docIndex <- 1:length(x)
if (is.null(names(x)))
names(docIndex) <- factor(paste("text", 1:length(x), sep="")) else
names(docIndex) <- names(x)
alltokens <- data.table(docIndex = rep(docIndex, sapply(x, length)),
features = unlist(x, use.names = FALSE))
alltokens <- alltokens[features != ""] # if there are any "blank" features
alltokens[, "n":=1L]
alltokens <- alltokens[, by=list(docIndex,features), sum(n)]
uniqueFeatures <- unique(alltokens$features)
uniqueFeatures <- sort(uniqueFeatures)
featureTable <- data.table(featureIndex = 1:length(uniqueFeatures),
features = uniqueFeatures)
setkey(alltokens, features)
setkey(featureTable, features)
alltokens <- alltokens[featureTable, allow.cartesian = TRUE]
alltokens[is.na(docIndex), c("docIndex", "V1") := list(1, 0)]
sparseMatrix(i = alltokens$docIndex,
j = alltokens$featureIndex,
x = alltokens$V1,
dimnames=list(docs=names(docIndex), features=uniqueFeatures))
}
require(quanteda)
str(inaugTexts)
## Named chr [1:57] "Fellow-Citizens of the Senate and of the House of Representatives:\n\nAmong the vicissitudes incident to life no event could ha"| __truncated__ ...
## - attr(*, "names")= chr [1:57] "1789-Washington" "1793-Washington" "1797-Adams" "1801-Jefferson" ...
tokenizedTexts <- tokenize(toLower(inaugTexts), removePunct = TRUE, removeNumbers = TRUE)
system.time(dfm_quanteda(tokenizedTexts))
## user system elapsed
## 0.060 0.005 0.064
Конечно, это всего лишь фрагмент, но полный исходный код легко найти в репозитории GitHub (dfm-main.R
).
Quanteda на вашем примере
Как это для простоты?
require(quanteda)
mytext <- c("Let the big dogs hunt",
"No holds barred",
"My child is an honor student")
dfm(mytext, ignoredFeatures = stopwords("english"), stem = TRUE)
# Creating a dfm from a character vector ...
# ... lowercasing
# ... tokenizing
# ... indexing 3 documents
# ... shaping tokens into data.table, found 14 total tokens
# ... stemming the tokens (english)
# ... ignoring 174 feature types, discarding 5 total features (35.7%)
# ... summing tokens by document
# ... indexing 9 feature types
# ... building sparse matrix
# ... created a 3 x 9 sparse dfm
# ... complete. Elapsed time: 0.023 seconds.
# Document-feature matrix of: 3 documents, 9 features.
# 3 x 9 sparse Matrix of class "dfmSparse"
# features
# docs bar big child dog hold honor hunt let student
# text1 0 1 0 1 0 0 1 1 0
# text2 1 0 0 0 1 0 0 0 0
# text3 0 0 1 0 0 1 0 0 1
person
Ken Benoit
schedule
09.07.2015
qdap
не будет быстрее для этой задачи, поскольку он использует пакетtm
в качестве серверной части. Но регулярное выражение с data.table/dplyr или параллельной обработкой может быть. - person Tyler Rinker   schedule 15.08.2014