Pregunta

Al crear funciones que el uso strsplit, entradas vector no se comportan como se desee, y las necesidades sapply a utilizar. Esto se debe a la salida de la lista que strsplit produce. ¿Hay una manera de vectorizar el proceso - es decir, la función produce el elemento correcto en la lista para cada uno de los elementos de la entrada

?

Por ejemplo, para contar las longitudes de las palabras en un vector de caracteres:

words <- c("a","quick","brown","fox")

> length(strsplit(words,""))
[1] 4 # The number of words (length of the list)

> length(strsplit(words,"")[[1]])
[1] 1 # The length of the first word only

> sapply(words,function (x) length(strsplit(x,"")[[1]]))
a quick brown   fox 
1     5     5     3 
# Success, but potentially very slow

Idealmente, algo así como length(strsplit(words,"")[[.]]) donde . se interpreta como el ser la parte relevante de vector de entrada.

¿Fue útil?

Solución

En general, usted debe tratar de utilizar una función vectorizado para empezar. Usando strsplit con frecuencia requerirá algún tipo de iteración después (que será más lento), lo que debería evitar si es posible. En su ejemplo, se debe utilizar en lugar nchar:

> nchar(words)
[1] 1 5 5 3

De forma más general, se aprovechan del hecho de que strsplit devuelve una lista y el uso lapply:

> as.numeric(lapply(strsplit(words,""), length))
[1] 1 5 5 3

O más use una función de la familia l*ply de plyr. Por ejemplo:

> laply(strsplit(words,""), length)
[1] 1 5 5 3

Editar:

En honor a Bloomsday , decidí probar el rendimiento de estos enfoques utilizando el Ulises de Joyce:

joyce <- readLines("http://www.gutenberg.org/files/4300/4300-8.txt")
joyce <- unlist(strsplit(joyce, " "))

Ahora que tengo todas las palabras, podemos hacer nuestros sentidos:

> # original version
> system.time(print(summary(sapply(joyce, function (x) length(strsplit(x,"")[[1]])))))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   4.000   4.666   6.000  69.000 
   user  system elapsed 
   2.65    0.03    2.73 
> # vectorized function
> system.time(print(summary(nchar(joyce))))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   4.000   4.666   6.000  69.000 
   user  system elapsed 
   0.05    0.00    0.04 
> # with lapply
> system.time(print(summary(as.numeric(lapply(strsplit(joyce,""), length)))))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   4.000   4.666   6.000  69.000 
   user  system elapsed 
    0.8     0.0     0.8 
> # with laply (from plyr)
> system.time(print(summary(laply(strsplit(joyce,""), length))))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   4.000   4.666   6.000  69.000 
   user  system elapsed 
  17.20    0.05   17.30
> # with ldply (from plyr)
> system.time(print(summary(ldply(strsplit(joyce,""), length))))
       V1        
 Min.   : 0.000  
 1st Qu.: 3.000  
 Median : 4.000  
 Mean   : 4.666  
 3rd Qu.: 6.000  
 Max.   :69.000  
   user  system elapsed 
   7.97    0.00    8.03 

La función vectorizado y lapply son considerablemente más rápido que la versión original sapply. Todas las soluciones de devolver la misma respuesta (como se ve por el resumen de la salida).

Al parecer, la última versión del plyr es más rápido (esto es utilizando una versión ligeramente mayores).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top