163 votes

Est R ' s appliquer famille de plus de sucre syntaxique ?

... moment de l’exécution de délégation et / ou de mémoire.

Si ce n’est pas vrai, prouvez-le avec un extrait de code. Remarque Cette accélération par vectorisation ne compte pas. L’accélération doit provenir de ( , `` ,...) lui-même.

163voto

Shane Points 40885

L' apply fonctions dans R de ne pas fournir de meilleures performances que les autres en boucle fonctions (par exemple, for). Une exception à cette règle est - lapply qui peut être un peu plus rapide car il n'a plus de travail dans le code C que dans R (voir à cette question pour un exemple).

Mais en général, la règle est que vous devez utiliser une application de fonction pour plus de clarté, pas pour la performance.

Je voudrais ajouter à ce que s'appliquent les fonctions n'ont pas d'effets secondaires, ce qui est une distinction importante quand il s'agit de la programmation fonctionnelle avec R. Cela peut être substituée à l'aide d' assign ou <<-, mais qui peuvent être très dangereux. Effets secondaires aussi faire un programme plus difficile à comprendre parce qu'une variable d'état dépend de l'histoire.

Edit:

Juste pour souligner ce point avec un exemple trivial que de manière récursive qui calcule la suite de Fibonacci, ce qui pourrait être exécuté plusieurs fois afin d'obtenir une mesure exacte, mais le point est qu'aucune de ces méthodes sont très différentes de la performance:

> fibo <- function(n) {
+   if ( n < 2 ) n
+   else fibo(n-1) + fibo(n-2)
+ }
> system.time(for(i in 0:26) fibo(i))
   user  system elapsed 
   7.48    0.00    7.52 
> system.time(sapply(0:26, fibo))
   user  system elapsed 
   7.50    0.00    7.54 
> system.time(lapply(0:26, fibo))
   user  system elapsed 
   7.48    0.04    7.54 
> library(plyr)
> system.time(ldply(0:26, fibo))
   user  system elapsed 
   7.52    0.00    7.58 

Edit 2:

Concernant l'utilisation en parallèle des packages de R (par exemple, rpvm, l'ipmb, neige), elles ne fournissent généralement apply les fonctions de la famille (même l' foreach package est essentiellement équivalent, malgré le nom). Voici un exemple simple de l' sapply fonction snow:

library(snow)
cl <- makeSOCKcluster(c("localhost","localhost"))
parSapply(cl, 1:20, get("+"), 3)

Cet exemple utilise un socket cluster, pour lequel aucun logiciel supplémentaire ne doit être installé; sinon, vous aurez besoin de quelque chose comme PVM ou MPI (voir Tierney de clustering page). snow a la suite d'appliquer les fonctions de:

parLapply(cl, x, fun, ...)
parSapply(cl, X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
parApply(cl, X, MARGIN, FUN, ...)
parRapply(cl, x, fun, ...)
parCapply(cl, x, fun, ...)

Il est logique qu' apply fonctions doivent être utilisées pour l'exécution en parallèle car ils ont pas d' effets secondaires. Lorsque vous modifiez la valeur d'une variable à l'intérieur d'un for de la boucle, il est défini globalement. D'autre part, tous apply fonctions peuvent en toute sécurité être utilisés en parallèle parce que les changements sont locales à l'appel de la fonction (à moins que vous essayez d'utiliser assign ou <<-, dans ce cas, vous pouvez présenter des effets secondaires). Inutile de dire, il est essentiel d'être prudent quant à local vs global variables, surtout au moment de l'exécution en parallèle.

Edit:

Voici un exemple trivial pour démontrer la différence entre for et *apply jusqu'à présent que les effets secondaires sont concernés:

> df <- 1:10
> # *apply example
> lapply(2:3, function(i) df <- df * i)
> df
 [1]  1  2  3  4  5  6  7  8  9 10
> # for loop example
> for(i in 2:3) df <- df * i
> df
 [1]  6 12 18 24 30 36 42 48 54 60

Notez comment l' df dans le parent de l'environnement est modifiée par l' for mais pas *apply.

74voto

Joris Meys Points 38980

Parfois l’accélération peut être substantielle, comme quand vous devez imbriquer les boucles for pour obtenir la moyenne basée sur un regroupement de plus d’un facteur. Ici vous avez deux approches qui vous donnent exactement le même résultat :

Les deux donnent exactement le même résultat, étant une matrice de 5 x 10 avec les moyennes et les lignes nommées et les colonnes. Mais :

Et voilà. Ce que je gagne ? ;-)

48voto

Tommy Points 16323

.. .et comme je viens a écrit ailleurs, vapply est votre ami ! ... c’est comme sapply, mais vous également spécifier le type de valeur de retour, ce qui le rend beaucoup plus rapide.

29voto

John Points 11714

J'ai écrit ailleurs qu'un exemple comme Shane n'a pas vraiment de stress a la différence de performance entre les différents types de syntaxe de boucle parce que le temps est passé au sein de la fonction plutôt que de réellement soulignant la boucle. En outre, le code injustement compare une boucle for avec pas de mémoire avec la famille de fonctions qui retournent une valeur. Voici un exemple légèrement différent qui met l'accent sur le point.

foo <- function(x) {
   x <- x+1
 }
y <- numeric(1e6)
system.time({z <- numeric(1e6); for(i in y) z[i] <- foo(i)})
#   user  system elapsed 
#  4.967   0.049   7.293 
system.time(z <- sapply(y, foo))
#   user  system elapsed 
#  5.256   0.134   7.965 
system.time(z <- lapply(y, foo))
#   user  system elapsed 
#  2.179   0.126   3.301 

Si vous envisagez d'enregistrer le résultat d'appliquer ensuite les fonctions de la famille peut être BEAUCOUP plus de sucre syntaxique.

(le simple unlist de z n'est que de 0,2 s de sorte que le lapply est beaucoup plus rapide. L'initialisation de la z dans la boucle for est assez rapide parce que je suis en train de faire la moyenne des 5 dernières de 6 pistes jusqu'à se déplacer qu'à l'extérieur du système.le temps ne serait guère affecter des choses)

5voto

Michele Points 3199

Lors de l’application de fonctions sur des sous-ensembles d’un vecteur, `` peut être un peu plus rapide qu’une boucle for. Exemple :

``, cependant, ne fournit pas une augmentation de la vitesse dans la plupart des cas, et dans certains cas, peut être même beaucoup plus lent :

Mais pour ces situations, nous avons colSums et rowSums :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X