Есть ли более быстрая альтернатива подсчету специальных символов для 100 000 коротких строк в R? - PullRequest
2 голосов
/ 04 апреля 2019

Я пытаюсь подсчитать количество не буквенно-цифровых символов для каждой строки в векторе из 100 000 строк.Я считаю, что моя текущая реализация работает медленнее, чем хотелось бы.

Моя текущая реализация использует purrr::map() для сопоставления пользовательской функции, которая использует пакет stringr для каждой строки в векторе.

library(dplyr)
library(stringr)
library(purrr)

# custom function that accepts string input and counts the number 
# of non-alphanum characters
count_non_alnum <- function(x) {
  stringr::str_detect(x, "[^[:alnum:] ]") %>% sum()
}

# character vector of length 100K
vec <- rep("Hello. World.", 100000)  

# tokenize individual characters for each string
vec_tokens <- purrr::map(vec, function(x) {
  stringr::str_split(x, "") %>% unlist()
})

# count non-alphanum characters
purrr::map(vec_tokens, count_non_alnum)

# Time difference of 1.048214 mins



sessionInfo()
# R version 3.4.3 (2017-11-30)
# Platform: x86_64-w64-mingw32/x64 (64-bit)
# Running under: Windows 7 x64 (build 7601) Service Pack 1

Мое моделирование постоянно требует около 1 минуты.У меня нет особых оснований для ожидания, но я надеюсь, что есть более быстрая альтернатива.Я открыт для альтернативных пакетов R или интерфейсов (например, reticulate, Rcpp).

1 Ответ

2 голосов
/ 05 апреля 2019

Основные функции R намного быстрее.Вот решение sum/grepl и 4 различных способа вызова двух функций.

library(microbenchmark)
library(ggplot2)
library(dplyr)
library(stringr)
library(purrr)

# custom function that accepts string input and counts the number 
# of non-alphanum characters
count_non_alnum <- function(x) {
  stringr::str_detect(x, "[^[:alnum:] ]") %>% sum()
}

count_non_alnum2 <- function(x) {
  sum(grepl("[^[:alnum:] ]", x))
}

# character vector of length 100K
vec <- rep("Hello. World.", 100)  

# tokenize individual characters for each string
vec_tokens <- purrr::map(vec, function(x) {
  stringr::str_split(x, "") %>% unlist()
})


# count non-alphanum characters
mb <- microbenchmark(
  Danny_purrr = purrr::map(vec_tokens, count_non_alnum),
  Rui_purrr = purrr::map(vec_tokens, count_non_alnum2),
  Danny_base = sapply(vec_tokens, count_non_alnum),
  Rui_base = sapply(vec_tokens, count_non_alnum2),
  unit = "relative"
)
mb
#Unit: relative
#        expr       min        lq      mean    median        uq       max neval cld
# Danny_purrr 58.508234 56.440147 52.854162 53.890724 53.464640 25.855456   100   c
#   Rui_purrr  1.026362  1.021998  1.011265  1.025648  1.025087  1.558001   100 a  
#  Danny_base 58.643098 56.398330 52.491478 53.857666 52.821759 27.981780   100  b 
#    Rui_base  1.000000  1.000000  1.000000  1.000000  1.000000  1.000000   100 a  


autoplot(mb)

enter image description here

...