Question

Lors de la création des fonctions que l'utilisation strsplit, les entrées de vecteur ne se comportent pas comme on le souhaite, et les besoins de sapply à utiliser. Cela est dû à la sortie de liste qui strsplit produit. Est-il possible de vectoriser le processus - qui est la fonction produit l'élément correct dans la liste pour chacun des éléments de l'entrée

?

Par exemple, pour compter les longueurs de mots dans un vecteur de caractères:

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

Idéalement, quelque chose comme length(strsplit(words,"")[[.]]). est interprété comme étant la partie pertinente du vecteur d'entrée.

Était-ce utile?

La solution

En général, vous devriez essayer d'utiliser une fonction vectorisée pour commencer. L'utilisation strsplit nécessitera souvent une sorte d'itération après (qui sera plus lent), alors essayez de l'éviter si possible. Dans votre exemple, vous devez utiliser à la place nchar:

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

De manière plus générale, tirer profit du fait que strsplit retourne une liste et de l'utilisation lapply:

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

Ou utilisez bien une fonction de la famille l*ply de plyr. Par exemple:

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

Edit:

En l'honneur de Bloomsday , j'ai décidé de tester les performances de ces approches utilisant Ulysse de Joyce:

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

Maintenant que j'ai tous les mots, nous pouvons faire nos comptes:

> # 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 fonction vectorisé et lapply sont considérablement plus rapide que la version originale sapply. Toutes les solutions renvoient la même réponse (comme on le voit par la sortie de synthèse).

Apparemment, la dernière version de plyr est plus rapide (ce qui utilise une version légèrement plus).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top