Domanda

Durante la creazione di funzioni che uso strsplit, ingressi vettore non si comportano come desiderato, e le esigenze sapply da utilizzare. Ciò è dovuto all'uscita lista che strsplit produce. C'è un modo vectorize processo - cioè, la funzione produce l'elemento corretto nell'elenco per ciascuno degli elementi di input

?

Ad esempio, per contare le lunghezze delle parole in un vettore di carattere:

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, qualcosa come length(strsplit(words,"")[[.]]) dove . viene interpretato come essendo la parte rilevante del vettore di ingresso.

È stato utile?

Soluzione

In generale, si dovrebbe cercare di utilizzare una funzione vettorializzare per cominciare. Utilizzando strsplit frequentemente richiedono un certo tipo di iterazione successiva (che sarà più lenta), in modo da cercare di evitare se possibile. Nel tuo esempio, si dovrebbe usare nchar invece:

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

Più in generale, approfittare del fatto che strsplit restituisce una lista e l'uso lapply:

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

In alternativa all'uso altro una funzione di famiglia l*ply da plyr. Per esempio:

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

Modifica:

In onore di Bloomsday , ho deciso di testare le prestazioni di questi approcci con l'Ulisse di Joyce:

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

Ora che ho tutte le parole, possiamo fare i nostri conteggi:

> # 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 funzione vettorializzare e lapply sono notevolmente più veloce rispetto alla versione originale sapply. Tutte le soluzioni restituiscono la stessa risposta (come si vede dalla uscita di sintesi).

A quanto pare l'ultima versione di plyr è più veloce (questo sta usando una versione leggermente più vecchio).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top