Buscando una alternativa más rápida para sapply()
He escrito una función que cuenta el número de palabras (unigramas) en una oración:
library(ngram)
library(stringi)
library(tidyverse)
set.seed(123)
get_unigrams <- function(text) {
sapply(text, function(text){
unigram<- ngram(text, n = 1) %>% get.ngrams() %>% length()
return(unigram)
})
}
Para hacer esto, utilicé la función sapply
que aplica mi función get_unigrams
a cada fila en el conjunto de datos. Esto también funciona hasta ahora:
### ejemplo de conjunto de datos:
df<-sample.int(5, 5, replace = T) %>%
map(., ~ stri_randstrings(.x, 10) %>% paste(collapse = " ")) %>%
unlist() %>%
tibble(text = .)
### aplicando mi función
df %>% mutate(n=get_unigrams((text)))
### A tibble: 5 x 2
text n
<chr> <int>
1 SxSgZ6tF2K xtgdzehXaH 9xtgn1TlDJ 3
2 E8PPM98ESG r2Rn7YC7kt Nf5NHoRoon 3
3 Rkdi0TDNbL 6FfPm6Qzts 2
4 A8eLeJBm5S VbKUxTtubP 2
5 9vI3wi8Yxa PeJJDMz958 gctfjWeomy 3
Sin embargo, dado que la función get_unigrams
se aplica para cada fila, esto consume mucho tiempo. Por lo tanto, me gustaría preguntar si hay una alternativa rápida para la función sapply
que acelere significativamente mi función get_unigrams
.
### conjunto de datos con 50.000 filas:
df<-sample.int(50, 50000, replace = T) %>%
map(., ~ stri_randstrings(.x, 10) %>% paste(collapse = " ")) %>%
unlist() %>%
tibble(text = .)
system.time({
df %>% mutate(n=get_unigrams((text)))
})
User System verstrichen
21.35 0.11 22.06
Para un conjunto de datos con 50.000 filas, mi función necesita 22.06 segundos (“verstrichen”). ¡Esto claramente es demasiado para mí! ¿Alguien puede ayudarme a aumentar la velocidad? ¿Quizás con una función vectorizada?
La construcción dentro de la función get_unigrams
debe permanecer igual:
unigram <- ngram(text, n = 1) %>% get.ngrams() %>% length()
return(unigram)
Solo me refiero a la función sapply
. ¡Muchas gracias de antemano!
davy.ai
Sí, en lugar de usar
sapply
para recorrer cada fila del data frame, puedes utilizar el paquetestringr
y un patrón regex para dividir cada oración en palabras y luego contar el número de elementos resultantes. Aquí tienes una versión actualizada de tu función que utiliza este enfoque:La función
str_split()
divide cada oración en palabras utilizando el patrón regex\\s+
, que coincide con uno o más caracteres de espacio en blanco. La lista resultante de vectores de palabras se pasa luego alengths()
, que devuelve un vector de la misma longitud que la lista de entrada, donde cada elemento es la longitud del vector de palabras correspondiente (es decir, el número de palabras en la oración).Luego puedes aplicar esta función actualizada a tu data frame utilizando
mutate()
de la siguiente manera:Esto debería ser mucho más rápido que usar
sapply
, ya que la división y el conteo están vectorizados en lugar de realizarse en un bucle.