Как «эффективно» заменить вектор строк другим (попарно) в большом текстовом корпусе - PullRequest
2 голосов
/ 30 марта 2019

У меня большой корпус текста в векторе строк (ок. 700.000 строк).Я пытаюсь заменить конкретные слова / фразы в корпусе.То есть у меня есть вектор из приложения 40 000 фраз и соответствующий вектор замен.

Я ищу эффективный способ решения проблемы

Я могу сделать это в цикле for, цикл по каждому шаблону + замена.Но он плохо масштабируется (3 дня или около того!)

Я также пробовал qdap :: mgsub (), но, похоже, он плохо масштабируется

txt <- c("this is a random sentence containing bca sk", 
"another senctence with bc a but also with zqx tt",
"this sentence contains non of the patterns", 
"this sentence contains only bc a")

patterns <- c("abc sk", "bc a", "zqx tt")

replacements <- c("@a-specfic-tag-@abc sk", 
"@a-specfic-tag-@bc a", 
"@a-specfic-tag-@zqx tt")

#either
txt2 <- qdap::mgsub(patterns, replacements, txt)
#or
for(i in 1:length(patterns)){
    txt  <- gsub(patterns[i], replacements[i], txt)
}

Оба решения плохо масштабируютсядля моих данных с приложением 40 000 шаблонов / замен и 700 000 текстовых строк

Я считаю, что должен быть более эффективный способ сделать это?

Ответы [ 3 ]

1 голос
/ 04 апреля 2019

Если вы можете сначала токенизировать тексты, тогда векторизация будет намного быстрее.Это также быстрее, если а) вы можете использовать многопоточное решение и б) вы используете фиксированное вместо сопоставления регулярных выражений.

Вот как это сделать в пакете quanteda .Последняя строка вставляет токены обратно в один «документ» как символьный вектор, если это то, что вам нужно.

library("quanteda")
## Package version: 1.4.3
## Parallel computing: 2 of 12 threads used.
## See https://quanteda.io for tutorials and examples.
## 
## Attaching package: 'quanteda'
## The following object is masked from 'package:utils':
## 
##     View
quanteda_options(threads = 4)

txt <- c(
  "this is a random sentence containing bca sk",
  "another sentence with bc a but also with zqx tt",
  "this sentence contains none of the patterns",
  "this sentence contains only bc a"
)
patterns <- c("abc sk", "bc a", "zqx tt")
replacements <- c(
  "@a-specfic-tag-@abc sk",
  "@a-specfic-tag-@bc a",
  "@a-specfic-tag-@zqx tt"
)

Это токенизирует тексты и затем использует быструю замену типов хеширования, используяфиксированное сопоставление с образцом (но вы могли бы использовать valuetype = "regex" для сопоставления с регулярным выражением).Оборачивая patterns внутри функции phrases(), вы указываете tokens_replace() искать последовательности токенов, а не отдельные совпадения, поэтому это решает проблему, состоящую из нескольких слов.

toks <- tokens(txt) %>%
  tokens_replace(phrase(patterns), replacements, valuetype = "fixed")
toks
## tokens from 4 documents.
## text1 :
## [1] "this"       "is"         "a"          "random"     "sentence"  
## [6] "containing" "bca"        "sk"        
## 
## text2 :
## [1] "another"                "sentence"              
## [3] "with"                   "@a-specfic-tag-@bc a"  
## [5] "but"                    "also"                  
## [7] "with"                   "@a-specfic-tag-@zqx tt"
## 
## text3 :
## [1] "this"     "sentence" "contains" "none"     "of"       "the"     
## [7] "patterns"
## 
## text4 :
## [1] "this"                 "sentence"             "contains"            
## [4] "only"                 "@a-specfic-tag-@bc a"

Наконец, если вы действительнохотите вернуть это обратно в формат символов, затем преобразовать в список типов символов и затем вставить их вместе.

sapply(as.list(toks), paste, collapse = " ")
##                                                                             text1 
##                                     "this is a random sentence containing bca sk" 
##                                                                             text2 
## "another sentence with @a-specfic-tag-@bc a but also with @a-specfic-tag-@zqx tt" 
##                                                                             text3 
##                                     "this sentence contains none of the patterns" 
##                                                                             text4 
##                                "this sentence contains only @a-specfic-tag-@bc a"

Вам придется проверить это на большом корпусе, но строки 700k не звучаткак слишком большая задача.Пожалуйста, попробуйте это и сообщите, как это было!

0 голосов
/ 31 марта 2019

Создать карту между старыми и новыми значениями

map <- setNames(replacements, patterns)

Создать шаблон, содержащий все шаблоны в одном регулярном выражении

pattern = paste0("(", paste0(patterns, collapse="|"), ")")

Найти все совпадения и извлечь их

ridx <- gregexpr(pattern, txt)
m <- regmatches(txt, ridx)

Unlist, отобразить и сопоставить совпадения с их значениями замены и обновить исходный вектор

regmatches(txt, ridx) <- relist(map[unlist(m)], m)
0 голосов
/ 31 марта 2019

Создайте вектор всех слов в каждой фразе

txt1 = strsplit(txt, " ")
words = unlist(txt1)

Используйте match(), чтобы найти индекс заменяемых слов, и замените их

idx <- match(words, patterns)
words[!is.na(idx)] = replacements[idx[!is.na(idx)]]

Переформируйтефразы и вставки вместе

phrases = relist(words, txt1)
updt = sapply(phrases, paste, collapse = " ")

Я думаю, это не сработает, если шаблоны могут иметь более одного слова ...

...