Programmation efficace en R – Éviter les boucles

le 23 janvier 2013 à 09:31
dtalbot

Je n’ai certainement pas la prétention d’être un expert en programmation avec le logiciel R : il y a probablement plus de choses que je ne connais pas de ce logiciel que de choses que je connais. J’ai par contre souvent utilisé R pour différentes raisons et j’ai eu l’occasion d’apprendre différents trucs qui pourraient être utiles à d’autres. J’entreprends ici de créer une nouvelle chronique récurrente qui, un peu comme la chronique SAS de Sylvain Tremblay, vous permettra peut-être d’en apprendre un peu plus sur un logiciel d’analyse statistique.

Je consacre cette première chronique à quelques trucs qui permettent d’éliminer des boucles et d’améliorer l’efficacité de vos programmes en R.

Le premier moyen d’éviter les boucles consiste à profiter du fait que R effectue ses opérations élément par élément. Par exemple, si x est le vecteur [2, 2] et y le vecteur [2, 3], alors x + y = [4, 5]. De la même façon, la soustraction, la multiplication et bien d’autres opérations de base s’appliquent élément par élément, tant pour des vecteurs que pour des matrices.

Le deuxième moyen d’éviter les boucles est d’utiliser la fonction apply. Cette fonction s’utilise lorsqu’on désire appliquer la même fonction colonne par colonne ou ligne par ligne à l’intérieur d’une matrice (ou d’un tableau array). Le premier argument de cette fonction est la matrice en question. Son deuxième argument est un «1» si la fonction doit être appliquée ligne par ligne et un «2» si la fonction doit être appliquée colonne par colonne. Son troisième argument est la fonction à appliquer.

Voici un exemple où on met en pratique les deux trucs pour éliminer plusieurs boucles. Dans cet exemple, on simule 1000 observations comportant 100 variables numériques. On souhaite calculer, pour chaque observation, la somme sur les 100 variables des différences en valeur absolue entre la valeur observée pour une variable et la moyenne de cette variable. Le code suivant effectue une première programmation intuitive qui utilise deux boucles :

require(mvtnorm); # package pour la simulation

set.seed(558413514); # germe de la simulation

avant = Sys.time(); # enregistrer le temps avant

donnees = rmvnorm(n = 1000, mean = rep(0, 100), sigma = diag(1, 100));

# simulation des données

elem = matrix(0, nrow = 1000, ncol = 1); # initialisation d’une matrice qui contiendra les résultats

for(var in 1:100) # boucler sur la variable

{

moy = mean(donnees[,var]); # moyenne de la variable

for(obs in 1:1000) # boucler sur les observations

{

elem[obs] = elem[obs] + abs(donnees[obs, var] – moy);

}

}

apres = Sys.time(); # temps après

apres – avant; # time difference of 0.413023 secs

head(elem); # une partie des résultats

Bien que le temps d’exécution apparaisse déjà très court, on peut facilement grandement améliorer la rapidité d’exécution de ce programme. Si on devait répéter souvent cette partie de code (des milliers de fois par exemple), on aurait tout avantage à trouver une manière de faire plus rapide.

Pour l’améliorer, remarquons d’abord qu’on peut créer un vecteur qui contiendra les moyennes pour chaque variable en une seule opération avec la fonction apply ou encore mieux, avec la fonction raccourcie colMeans :

moy = colMeans(donnees);

Puisque les opérations s’effectuent élément par élément, on peut obtenir le résultat voulu pour une ligne donnée x en prenant sum(abs(x – moy)). Un programme efficace est donc :

require(mvtnorm);

set.seed(558413514);

avant = Sys.time();

donnees = rmvnorm(n = 1000, mean = rep(0, 100), sigma = diag(1, 100));

elem = matrix(0, nrow = 1000, ncol = 1);

moy = colMeans(donnees);

elem = apply(donnees, 1, function(x){sum(abs(x – moy))});

apres = Sys.time();

apres – avant; # time difference of 0.07000399 secs

head(elem);

En éliminant simplement deux boucles, on a réussi à rendre le programme presque 6 fois plus rapide. Si vous avez à créer vos propres fonctions en R, gardez en mémoire ces deux trucs simples pour éliminer des boucles et réduire vos temps de calcul!

Denis Talbot
Retour à la table des matières

FacebookTwitterGoogle+LinkedIn