Stemming с анализом текста R
Я делаю много анализа с TM пакета. Одна из моих самых больших проблем связана со стеммингом и подобными ему преобразованиями.
предположим, у меня есть несколько связанных с бухгалтерией терминов (я знаю о проблемах правописания).
После stemming мы имеем:
accounts -> account
account -> account
accounting -> account
acounting -> acount
acount -> acount
acounts -> acount
accounnt -> accounnt
результат: 3 условия (учетная запись, acount, account), где я хотел бы 1 (учетная запись), поскольку все они относятся к одному и тому же термину.
1) исправить правописание возможно, но я никогда не пытался это сделать в R. возможно ли это вообще?
2) другой вариант-сделать ссылочный список, т. е. account = (account, account, acount, acounts, accountnt), а затем заменить все вхождения на основной термин. Как бы я это сделал в R?
еще раз, любая помощь/предложения будут с благодарностью.
3 ответов
мы могли бы создать список синонимов и заменить эти значения. Например
synonyms <- list(
list(word="account", syns=c("acount", "accounnt"))
)
это говорит о том, что мы хотим заменить "acount" и "account" на "account" (я предполагаю, что мы делаем это после stemming). Теперь давайте создадим тестовые данные.
raw<-c("accounts", "account", "accounting", "acounting",
"acount", "acounts", "accounnt")
а теперь определим функцию преобразования, которая заменит слова в нашем списке первичным синонимом.
library(tm)
replaceSynonyms <- content_transformer(function(x, syn=NULL) {
Reduce(function(a,b) {
gsub(paste0("\b(", paste(b$syns, collapse="|"),")\b"), b$word, a)}, syn, x)
})
здесь мы используем
г-н Флик ответил на вопрос #2. Я приближаюсь, отвечая на вопрос № 1.
вот подход, который использует двоичный поиск известной базы данных word (DICTIONARY С qdapDictionaries). Двоичный поиск медленный, но если мы сделаем некоторые предположения о замене (например, диапазон различий в количестве символов). Итак, вот основная идея:
- повернуть
Corpusв уникальный мешок слов, используяqdap' sbag_o_words - посмотреть эти слова в словаре (
qdapDictionaries'DICTIONARYнабор данных), чтобы найти слова не распознать с помощьюmatch- эти
missesиз шага # 2 будет то, что мы ищем
- эти
- определить количество символов для слов в словаре, чтобы устранить грубую разницу позже с помощью
nchar - выполнить каждый элемент
missesчерез петлю (sapply) и сделайте следующее:
a. stem каждый элемент изmissesиспользуяtm::stemDocument
си. определите количество символов и удалите те из словаря, которые не находятся в этом диапазоне, используяnchar
С. используйтеagrepСmax.distanceчтобы исключить больше слов из словаря
d. используйте двоичный поиск (что обратные инженерыagrep), чтобы определить слово из словаря, который ближе всего к пропущенному элементу [Примечание это не экспортируется функция изqdapпод названиемqdap:::Ldist] - результат-это именованный вектор, который мы можем использовать для
gsubbing - использовать
tm_mapс пользовательскимtmароматизированные заменить словами - сделайте stemming с
tm_mapиstemDocument
вот код. Я сделал подделку Corpus используя слова, которые вы предоставляете, и некоторые случайные слова, чтобы продемонстрировать, как это сделать от начала до конца. Вы можете играть с range и max.distance, предоставленный для sapply. Чем слабее вы с этими медленный поиск будет, но tightiening эти слишком многое сделает его более вероятным для ошибки. Это действительно не ответ на исправление орфографии в общем смысле, но работает здесь, потому что вы все равно были. Есть Aspell пакета, но я никогда не использовал его раньше.
terms <- c("accounts", "account", "accounting", "acounting", "acount", "acounts", "accounnt")
library(tm); library(qdap)
fake_text <- unlist(lapply(terms, function(x) {
paste(sample(c(x, sample(DICTIONARY[[1]], sample(1:5, 1)))), collapse=" ")
}))
fake_text
myCorp <- Corpus(VectorSource(fake_text))
terms2 <- unique(bag_o_words(as.data.frame(myCorp)[[2]]))
misses <- terms2[is.na(match(terms2, DICTIONARY[[1]]))]
chars <- nchar(DICTIONARY[[1]])
replacements <- sapply(misses, function(x, range = 3, max.distance = .2) {
x <- stemDocument(x)
wchar <- nchar(x)
dict <- DICTIONARY[[1]][chars >= (wchar - range) & chars <= (wchar + range)]
dict <- dict[agrep(x, dict, max.distance=max.distance)]
names(which.min(sapply(dict, qdap:::Ldist, x)))
})
replacer <- content_transformer(function(x) {
mgsub(names(replacements), replacements, x, ignore.case = FALSE, fixed = FALSE)
})
myCorp <- tm_map(myCorp, replacer)
inspect(myCorp <- tm_map(myCorp, stemDocument))
этот вопрос вдохновил меня на попытку написать проверку орфографии для . Есть интерактивная версия, которая может быть полезна здесь. Он доступен в qdap >= version 2.1.1. Это означает, что вам понадобится версия dev на данный момент.. вот шаги по установке:
library(devtools)
install_github("qdapDictionaries", "trinker")
install_github("qdap", "trinker")
library(tm); library(qdap)
## воссоздавать Corpus как вы описываете.
terms <- c("accounts", "account", "accounting", "acounting", "acount", "acounts", "accounnt")
fake_text <- unlist(lapply(terms, function(x) {
paste(sample(c(x, sample(DICTIONARY[[1]], sample(1:5, 1)))), collapse=" ")
}))
fake_text
inspect(myCorp <- Corpus(VectorSource(fake_text)))
## интерактивная проверка орфографии (check_spelling_interactive)
m <- check_spelling_interactive(as.data.frame(myCorp)[[2]])
preprocessed(m)
inspect(myCorp <- tm_map(myCorp, correct(m)))
на correct функция просто захватывает функцию закрытия из вывода check_spelling_interactive и позволяет затем применить "исправление" к любой новой текстовой строке(строкам).