Более быстрый подход, чем gsub в r

Я пытаюсь выяснить, есть ли более быстрый подход, чем gsub векторная функция в R. У меня есть следующий кадр данных с некоторыми "предложениями" (отправленными словами), а затем у меня есть слова для удаления из этих предложений (хранимых в переменной wordForRemoving).

sent <- data.frame(words = 
                     c("just right size and i love this notebook", "benefits great laptop",
                       "wouldnt bad notebook", "very good quality", "bad orgtop but great",
                       "great improvement for that bad product but overall is not good", 
                       "notebook is not good but i love batterytop"), 
                   user = c(1,2,3,4,5,6,7),
                   stringsAsFactors=F)

wordsForRemoving <- c("great","improvement","love","great improvement","very good","good",
                      "right", "very","benefits", "extra","benefit","top","extraordinarily",
                      "extraordinary", "super","benefits super","good","benefits great",
                      "wouldnt bad")

Тогда я собираюсь создать симуляцию больших данных для вычисления потребления времени...

df.expanded <- as.data.frame(replicate(1000000,sent$words))
library(zoo)
sent <- coredata(sent)[rep(seq(nrow(sent)),1000000),]
rownames(sent) <- NULL

Использование следующего подхода gsub для удаления слов (wordsForRemoving) из отправленных $words занимает 72.87 сек. Я знаю, это не хорошая симуляция, но в реальности я использую словарный словарь с более чем 3.000 словами для 300 000 предложений, а общая обработка занимает более 1,5 часов.

pattern <- paste0("\\b(?:", paste(wordsForRemoving, collapse = "|"), ")\\b ?")
res <- gsub(pattern, "", sent$words)

#  user  system elapsed 
# 72.87    0.05   73.79

Пожалуйста, может кто-нибудь помочь мне написать более быстрый подход для моей задачи. Любая помощь или совет очень оценены. Большое спасибо вперёд.

Ответ 1

Как уже упоминалось Джейсоном, stringi - хороший вариант для вас.

Ниже приведена производительность stringi

system.time(res <- gsub(pattern, "", sent$words))
   user  system elapsed 
 66.229   0.000  66.199 

library(stringi)
system.time(stri_replace_all_regex(sent$words, pattern, ""))
   user  system elapsed 
 21.246   0.320  21.552 

Обновление (спасибо Арун)

system.time(res <- gsub(pattern, "", sent$words, perl = TRUE))
   user  system elapsed 
 12.290   0.000  12.281 

Ответ 2

Это не настоящий ответ, так как я не нашел ни одного способа, который всегда был бы быстрее. Видимо, это зависит от длины вашего текста/вектора. С короткими текстами gsub выполняет быстрее всего. С более длинными текстами или векторами иногда gsub с perl=TRUE и иногда stri_replace_all_regex работают быстрее всего.

Вот некоторый тестовый код, чтобы попробовать:

library(stringi)
text = "(a1,\"something (f fdd71)\");(b2,\"something else (a fa171)\");(b4,\"something else (a fa171)\")"
# text = paste(rep(text, 5), collapse = ",")
# text = rep(text, 100)
nchar(text)

a = gsub(pattern = "[()]", replacement = "", x = text)
b = gsub(pattern = "[()]", replacement = "", x = text, perl=T)
c = stri_replace_all_regex(str = text, pattern = "[()]", replacement = "")
d = stri_replace(str = text, regex = "[()]", replacement = "", mode="all")

identical(a,b); identical(a,c); identical(a,d)

library(microbenchmark)
mc <- microbenchmark(
  gsub = gsub(pattern = "[()]", replacement = "", x = text),
  gsub_perl = gsub(pattern = "[()]", replacement = "", x = text, perl=T),
  stringi_all = stri_replace_all_regex(str = text, pattern = "[()]", replacement = ""),
  stringi = stri_replace(str = text, regex = "[()]", replacement = "", mode="all")
)
mc
Unit: microseconds
        expr    min      lq     mean  median     uq     max neval  cld
        gsub 10.868 11.7740 13.47869 13.5840 14.490  31.394   100 a   
   gsub_perl 79.690 80.2945 82.58225 82.4070 83.312 137.043   100    d
 stringi_all 14.188 14.7920 15.58558 15.5460 16.301  17.509   100  b  
     stringi 36.828 38.0350 39.90904 38.7895 39.543 129.194   100   c