La version originale de ce chapitre a été écrite par Ewen Gallic dans le cadre de son support de cours d’Ewen Gallic intitulé Logiciel R et programmation, chapitre 4 Boucles et calculs vectoriels.

Les boucles sont des opérations lentes en R. Il est cependant possible, dans de nombreux cas, d’éviter de les employer, en ayant recours à la vectorisation : au lieu d’appliquer une fonction à un scalaire, on l’applique à un vecteur. En fait, nous avons déjà eu recours à maintes reprises aux calculs vectoriels. En effet, lorsque nous avons procédé à des additions, des multiplications, etc. sur des vecteurs, nous avons effectué des calculs vectoriels.

Empruntons un exemple à Burns (2011) : dans des langages comme le C, pour effectuer la somme des logarithmes naturels des n premiers entiers, voici une manière de faire :

# Somme des logarithmes des 10 premiers entiers
somme_log <- 0
for (i in seq_len(10)) {
  somme_log <- somme_log + log(i)
}
somme_log
[1] 15.10441

Il est possible d’obtenir le même résultat, à la fois d’une manière plus élégante, mais surtout plus efficace en vectorisant le calcul :

sum(log(seq_len(10)))
[1] 15.10441

Derrière ce code, la fonction log applique la fonction logarithme sur toutes les valeurs du vecteur donné en paramètre. La fonction sum, quant à elle, se charge d’additionner tous les éléments du vecteur qui lui est donné en paramètre. Ces deux fonctions utilisent la vectorisation, mais d’une manière différente : la fonction log applique une opération à chaque élément d’un vecteur, tandis que la fonction sum produit un résultat basé sur l’ensemble du vecteur. L’avantage d’utiliser des fonctions vectorielles plutôt que d’écrire une boucle pour effectuer le calcul, est que ces premières font appel à des fonctions rédigées en C ou FORTRAN, qui utilisent aussi des boucles, mais comme ce sont des langages compilés et non pas interprétés, les itérations sont réalisées dans un temps réduit.

Il existe des fonctions, rédigées en C qui effectuent des boucles for. On leur donne souvent le nom de “fonctions de la famille apply”. Il ne s’agit pas de la vectorisation, mais ces fonctions sont souvent mentionnées dès que l’on parle de ce sujet. Ce sont des fonctionnelles qui prennent une fonction en input et retournent un vecteur en output (Wickham, 2014). Ces fonctions sont très utilisées, mais elles souffrent d’un manque d’uniformité. En effet, elles ont été rédigées par des personnes différentes, ayant chacune leur convention. L’extension plyr remédie à ce problème, et ajoute par la même occasion des fonctions supplémentaires, pour couvrir plus de cas que les “fonctions de la famille apply”.

Nous allons donc présenter dans un premier temps les fonctions du package plyr. Les fonctions du même type du package base seront tout de même présentées par la suite.

Les fonctions de l’extension purrr

L’extension purrr du tidyverse a beaucoup évolué ces dernières années et permet d’itérer facilement des opérations sur une liste ou un tableau. Cette extension s’articule également avec les tableaux imbriqués rendus possibles par tibble et tidyr (voir la fonction nest et sa vignette dédiée : https://tidyr.tidyverse.org/articles/nest.html).

Concernant purrr, on pourra consulter le chapitre Itérer avec purrr de l’excellente Introduction à R et au tidyverse de Julien Barnier (https://juba.github.io/tidyverse).

Julien Barnier y aborde notamment la fonction map et ses variantes comme map_dbl, map_chr, map_int, map_dfr, map_dfc, modify, imap, walk

Les fonctions de l’extension plyr

Les fonctions que nous allons aborder dans cette section possèdent des noms faciles à se remémorer : la première lettre correspond au format d’entrée des données, la seconde au format de sortie souhaité, et la fin du nom se termine par le suffixe ply. Ainsi, la fonction llpply prend en entrée une liste, effectue une opération sur les éléments, et retourne une liste (Anderson, 2012).

Les différentes fonctions que nous allons passer en revue sont consignées dans le tableau ci-après, où les lignes correspondent aux formats d’entrée, et les lignes aux formats de sortie. Pour y avoir accès, il faut charger le package :

library(plyr)
----------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
----------------------------------------------------------

Attachement du package : 'plyr'
L'objet suivant est masqué depuis 'package:gtExtras':

    mutate
Les objets suivants sont masqués depuis 'package:plotly':

    arrange, mutate, rename, summarise
Les objets suivants sont masqués depuis 'package:Hmisc':

    is.discrete, summarize
Les objets suivants sont masqués depuis 'package:srvyr':

    mutate, rename, summarise, summarize
L'objet suivant est masqué depuis 'package:gtsummary':

    mutate
L'objet suivant est masqué depuis 'package:purrr':

    compact
L'objet suivant est masqué depuis 'package:ggpubr':

    mutate
Les objets suivants sont masqués depuis 'package:dplyr':

    arrange, count, desc, failwith, id, mutate,
    rename, summarise, summarize
Format de sortie
array data.frame list
Format d’entée array aaply adply alply
Format d’entée data.frame daply ddply dlply
Format d’entée list laply ldply llply

Il est possible d’avoir plusieurs paramètres en input au lieu d’un seul objet. Les fonctions mlply, mdply et maply. Si à la place du m, la première lettre est un r, il s’agit alors de fonction de réplications. Enfin, si la seconde lettre est un trait de soulignement (_), alors le résultat retourné n’est pas affiché (le code utilise la fonction invisible.

Tous les paramètres de ces fonctions commencent par un point (.), afin d’éviter des incompatibilités avec la fonction à appliquer.

Array en input : a*ply

Les fonctions aaply, adply et alply appliquent une fonction à chaque portion d’un array et ensuitent joignent le résultat sous forme d’un array, d’un data.frame ou d’une list respectivement.

Un array peut être vu comme un vecteur à plusieurs dimensions. Comme pour un vecteur, toutes les valeurs doivent être du même type. Un vecteur n’est finalement qu’un array à une seule dimension. De même, un array à deux dimensions correspond à ce qu’on appelle usuelement une matrice.

Le paramètre .margins détermine la manière de découper le tableau. Il y en a quatre pour un tableau en deux dimensions :

  1. .margins = 1 : par lignes ;
  2. .margins = 2 : par colonnes ;
  3. .margins = c(1,2) : par cellule ;
  4. .margins = c() : ne pas faire de découpement.

Pour un tableau en trois dimensions, il y a trois découpages possibles en deux dimensions, trois en une dimension et une en zéro dimension (voir (Wickham, 2011)) au besoin.

tableau <- array(
  1:24,
  dim = c(3, 4, 2),
  dimnames = list(
    ligne = letters[1:3],
    colonne = LETTERS[1:4],
    annee = 2001:2002
  )
)
tableau
, , annee = 2001

     colonne
ligne A B C  D
    a 1 4 7 10
    b 2 5 8 11
    c 3 6 9 12

, , annee = 2002

     colonne
ligne  A  B  C  D
    a 13 16 19 22
    b 14 17 20 23
    c 15 18 21 24
# La moyenne des valeurs pour chaque ligne
aaply(tableau, 1, mean) # résultat sous forme de tableau
   a    b    c 
11.5 12.5 13.5 
adply(tableau, 1, mean) # résultat sous forme de data.frame
ligne V1
a 11.5
b 12.5
c 13.5
alply(tableau, 1, mean) # résultat sous forme de liste
$`1`
[1] 11.5

$`2`
[1] 12.5

$`3`
[1] 13.5

attr(,"split_type")
[1] "array"
attr(,"split_labels")
  ligne
1     a
2     b
3     c
# La moyenne des valeurs pour chaque colonne
# en ne simplifiant pas le résultat
aaply(tableau, 2, mean, .drop = FALSE)
1
A 8
B 11
C 14
D 17
# Par lignes et colonnes
aaply(tableau, c(1, 2), mean)
A B C D
a 7 10 13 16
b 8 11 14 17
c 9 12 15 18
adply(tableau, c(1, 2), mean)
ligne colonne V1
a A 7
b A 8
c A 9
a B 10
b B 11
c B 12
a C 13
b C 14
c C 15
a D 16
b D 17
c D 18
# Avec une fonction définie par l'utilisateur
standardise <- function(x) (x - min(x)) / (max(x) - min(x))
# Standardiser les valeurs par colonne
aaply(tableau, 2, standardise)
, , annee = 2001

       ligne
colonne a          b         c
      A 0 0.07142857 0.1428571
      B 0 0.07142857 0.1428571
      C 0 0.07142857 0.1428571
      D 0 0.07142857 0.1428571

, , annee = 2002

       ligne
colonne         a         b c
      A 0.8571429 0.9285714 1
      B 0.8571429 0.9285714 1
      C 0.8571429 0.9285714 1
      D 0.8571429 0.9285714 1

Data.frame en input : d*ply

Dans le cas de l’analyse d’enquêtes, on utilise principalement des tableaux de données ou data.frame. Aussi, la connaissance des fonction daply, ddply et dlply peut être utile. En effet, elles sont très utiles pour appliquer des fonctions à des groupes basés sur des combinaisons de variables, même si dans la majorité des cas il est maintenant plus facile de passer par les extensions dplyr ou data.table avec les opérations groupées (voir la section sur groub_by de dplyr ou encore celle sur le paramètre by de data.table.

Avec les fonctions d*ply, il est nécessaire d’indiquer quelles variables, ou fonctions de variables on souhaite utiliser, en l’indiquant au paramètre .variables. Elles peuvent être contenue dans le data frame fourni au paramètre .data, ou bien provenir de l’environnement global. R cherchera dans un premier temps si la variable est contenue dans le data.frame et, s’il ne trouve pas, ira chercher dans l’environnement global.

Pour indiquer que l’on désire faire le regroupement selon une variable – mettons variable_1 – il faudra fournir l’expression .(variable_1) au paramètre .variables. Si on souhaite effectuer les regroupement selon les interactions de plusieurs variables – variable_1, variable_2 et variable_3, il faut alors utiliser l’expression suivante : .(variable_1, variable_2, variable_3).

chomage <- data.frame(
  region = rep(c(rep("Bretagne", 4), rep("Corse", 2)), 2),
  departement = rep(c(
    "Cotes-d'Armor", "Finistere",
    "Ille-et-Vilaine", "Morbihan",
    "Corse-du-Sud", "Haute-Corse"
  ), 2),
  annee = rep(c(2011, 2010), each = 6),
  ouvriers = c(
    8738, 12701, 11390, 10228, 975, 1297,
    8113, 12258, 10897, 9617, 936, 1220
  ),
  ingenieurs = c(
    1420, 2530, 3986, 2025, 259, 254,
    1334, 2401, 3776, 1979, 253, 241
  )
)
chomage
region departement annee ouvriers ingenieurs
Bretagne Cotes-d’Armor 2011 8738 1420
Bretagne Finistere 2011 12701 2530
Bretagne Ille-et-Vilaine 2011 11390 3986
Bretagne Morbihan 2011 10228 2025
Corse Corse-du-Sud 2011 975 259
Corse Haute-Corse 2011 1297 254
Bretagne Cotes-d’Armor 2010 8113 1334
Bretagne Finistere 2010 12258 2401
Bretagne Ille-et-Vilaine 2010 10897 3776
Bretagne Morbihan 2010 9617 1979
Corse Corse-du-Sud 2010 936 253
Corse Haute-Corse 2010 1220 241
# Total chomeurs en Bretagne et en Corse pour les années 2010 et 2011
# sous forme de data.frame
ddply(chomage, .(annee), summarise, total_chomeurs = sum(ouvriers + ingenieurs))
annee total_chomeurs
2010 53025
2011 55803
# sous forme de array
daply(chomage, .(annee), summarise, total_chomeurs = sum(ouvriers + ingenieurs))
$`2010`
[1] 53025

$`2011`
[1] 55803
# sous forme de list
dlply(chomage, .(annee), summarise, total_chomeurs = sum(ouvriers + ingenieurs))
$`2010`
  total_chomeurs
1          53025

$`2011`
  total_chomeurs
1          55803

attr(,"split_type")
[1] "data.frame"
attr(,"split_labels")
  annee
1  2010
2  2011
# Total chomeurs pour les années 2010 et 2011, par région du data frame
ddply(chomage, .(annee, region), summarise,
  total_chomeurs = sum(ouvriers + ingenieurs)
)
annee region total_chomeurs
2010 Bretagne 50375
2010 Corse 2650
2011 Bretagne 53018
2011 Corse 2785
# Nombre d'observations pour chaque groupe
ddply(chomage, .(annee, region), nrow)
annee region V1
2010 Bretagne 4
2010 Corse 2
2011 Bretagne 4
2011 Corse 2
# En utilisant une fonction définie par l'utilisateur
ddply(chomage, .(annee, region), function(x) {
  moy_ouvriers <- mean(x$ouvriers)
  moy_ingenieurs <- mean(x$ingenieurs)
  data.frame(moy_ouvriers = moy_ouvriers, moy_ingenieurs = moy_ingenieurs)
})
annee region moy_ouvriers moy_ingenieurs
2010 Bretagne 10221.25 2372.50
2010 Corse 1078.00 247.00
2011 Bretagne 10764.25 2490.25
2011 Corse 1136.00 256.50

List en input : l*ply

Les fonctions du type l*ply prennent une liste en entrée. Il n’y a donc pas de paramétrage à effectuer pour choisir un découpage, il est déjà fait.

set.seed(1)
liste <- list(normale = rnorm(10), logiques = c(TRUE, TRUE, FALSE), x = c(0, NA, 3))
# Obtenir la longueur de chaque élément de la liste
laply(liste, length)
[1] 10  3  3
ldply(liste, length)
.id V1
normale 10
logiques 3
x 3
llply(liste, length)
$normale
[1] 10

$logiques
[1] 3

$x
[1] 3
# Calculer la moyenne pour chaque élément
unlist(llply(liste, mean, na.rm = TRUE))
  normale  logiques         x 
0.1322028 0.6666667 1.5000000 
# Appliquer une fonction définie par l'utilisateur
llply(liste, function(x, y) x / mean(x, na.rm = TRUE) + y, y = 2)
$normale
 [1] -2.7385827  3.3891033 -4.3208096 14.0669232  4.4924421
 [6] -4.2061356  5.6869803  7.5847895  6.3552892 -0.3099997

$logiques
[1] 3.5 3.5 2.0

$x
[1]  2 NA  4

Calcul parallèle

En utilisant plusieurs processeurs, on peut effectuer des calculs parallèles, ce qui accélère les calculs dans certains cas. En effet, quand il est possible de fractionner les opérations à effectuer en morceaux, on peut en réaliser une partie sur un processeur, une autre sur un second processeur, et ainsi de suite. Les résultats obtenus sont ensuite rassemblés avant d’être retournés. Le package doMC (ou doSMP sur Windows) peut être chargé pour utiliser la fonction de calcul parallèle proposé par les fonctions **ply. Il suffit de préciser le nombre de coeurs souhaité en faisant appel à la fonction registerDoMC, et de fixer la valeur TRUE au paramètre .parallel de la fonction **ply.

Les fonctions de la famille apply du package base

Le tableau ci-après recense les fonctions principales de la famille apply du package base.

Fonction Input Output
apply Matrice ou tableau Vecteur ou tableau ou liste
lapply Liste ou vecteur Liste
sapply Liste ou vecteur Vecteur ou matrice ou liste
vapply Liste ou vecteur Vecteur ou matrice ou liste
tapply Tableau et facteurs Tableau ou liste
mapply Listes et/ou vecteurs Vecteur ou matrice ou liste

La fonction lapply

La fonction lapply applique à chaque élément du premier paramètre qui lui est donné une fonction indiquée en second paramètre et retourne le résultat sous forme de liste. La syntaxe est la suivante :

lapply(X, FUN, ...)

avec X la liste ou le vecteur donné en paramètre sur lequel on désire appliquer la fonction FUN. La paramètre ... permet de fournir des paramètres à une fonction imbriquée, en l’occurance à celle que l’on souhaite appliquer à tous les éléments de X.

liste <- list(normale = rnorm(10), logiques = c(TRUE, TRUE, FALSE), x = c(0, NA, 3))

# Obtenir la liste des longueurs de chaque élément
lapply(liste, length)
$normale
[1] 10

$logiques
[1] 3

$x
[1] 3
# Calculer la moyenne pour chaque élément
lapply(liste, mean, na.rm = TRUE)
$normale
[1] 0.248845

$logiques
[1] 0.6666667

$x
[1] 1.5

On peut créer une fonction à l’intérieur de l’appel à lapply. Le premier paramètre est nécessairement un élément du vecteur auquel on souhaite appliquer la fonction.

lapply(liste, function(x) x / mean(x, na.rm = TRUE))
$normale
 [1]  6.07519277  1.56661087 -2.49649643 -8.89991820
 [5]  4.52060941 -0.18056868 -0.06506164  3.79286833
 [9]  3.30013177  2.38663180

$logiques
[1] 1.5 1.5 0.0

$x
[1]  0 NA  2
# Si la fonction doit posséder plusieurs paramètres
lapply(liste, function(x, y) x / mean(x, na.rm = TRUE) + y, y = 2)
$normale
 [1]  8.0751928  3.5666109 -0.4964964 -6.8999182  6.5206094
 [6]  1.8194313  1.9349384  5.7928683  5.3001318  4.3866318

$logiques
[1] 3.5 3.5 2.0

$x
[1]  2 NA  4

On peut appliquer la lapply sur des tableaux de données, dans la mesure où ces derniers sont des listes. Cela s’avère pratique pour réaliser des opérations pour chaque colonne d’un tableau de données. Afin de prendre moins de place dans l’affichage, l’exemple suivant utilise la fonction unlist pour aplatir la liste obtenue.

data(cars)

# Afficher le type de chaque colonne de la data frame "cars"
unlist(lapply(cars, class))
    speed      dist 
"numeric" "numeric" 
# Calculer la moyenne pour chaque colonne
unlist(lapply(cars, mean))
speed  dist 
15.40 42.98 

Attention, ce qui suit relève plus d’un tour de passe-passe que de la programmation élégante.

Si la fonction que l’on souhaite appliquer aux éléments de notre vecteur retourne un vecteur ligne de même longueur pour chaque élément, la fonction do.call peut devenir un outil très pratique pour créer une data frame. Voyons-le à travers un exemple.

l <- lapply(1:3, function(x) cbind(valeur = x, lettre = LETTERS[x]))
l
[[1]]
     valeur lettre
[1,] "1"    "A"   

[[2]]
     valeur lettre
[1,] "2"    "B"   

[[3]]
     valeur lettre
[1,] "3"    "C"   
data.frame(do.call("rbind", l))
valeur lettre
1 A
2 B
3 C

L’appel de do.call("rbind", x) revient à faire rbind(x[[1]], x[[2]], ..., x[[n]]) avec x une liste de taille n.

La fonction sapply

La fonction sapply applique une fonction aux éléments d’un vecteur ou d’une liste et peut retourner un vecteur, une liste ou une matrice. Elle possède la syntaxe suivante :

sapply(X, FUN, simplify, USE.NAMES)

X est le vecteur ou la liste auquel on souhaite appliquer la fonction FUN. Lorsque simplify vaut FALSE, le résultat est retourné sous forme de liste, exactement comme lapply (la fonction sapply s’appuie sur la fonction lapply). Lorsque simplify vaut TRUE (par défaut), le résultat est retourné dans une forme simplifiée, si cela est possible. Si tous les éléments retournés par la fonction FUN sont des scalaires, alors sapply retourne un vecteur ; sinon, si les éléments retournés ont la même taille, sapply retourne une matrice avec une colonne pour chaque élément de X auquel la fonction FUN est appliquée. Le paramètre USE.NAMES, quand il vaut TRUE (par défaut), et si X est de type character, utilise X comme nom pour le résultat, à moins que le résultat possède déjà des noms.

(x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE, FALSE, FALSE, TRUE)))
$a
 [1]  1  2  3  4  5  6  7  8  9 10

$beta
[1]  0.04978707  0.13533528  0.36787944  1.00000000
[5]  2.71828183  7.38905610 20.08553692

$logic
[1]  TRUE FALSE FALSE  TRUE
# Application de la fonction quantile() à chaque élément
# pour obtenir la médiane et les quartiles
# Avec lapply()
lapply(x, quantile)
$a
   0%   25%   50%   75%  100% 
 1.00  3.25  5.50  7.75 10.00 

$beta
         0%         25%         50%         75%        100% 
 0.04978707  0.25160736  1.00000000  5.05366896 20.08553692 

$logic
  0%  25%  50%  75% 100% 
 0.0  0.0  0.5  1.0  1.0 
# Avec sapply
sapply(x, quantile)
a beta logic
0% 1.00 0.0497871 0.0
25% 3.25 0.2516074 0.0
50% 5.50 1.0000000 0.5
75% 7.75 5.0536690 1.0
100% 10.00 20.0855369 1.0
# Exemple avec USE.NAMES
sapply(LETTERS[1:3], nchar)
A B C 
1 1 1 
sapply(LETTERS[1:3], nchar, USE.NAMES = FALSE)
[1] 1 1 1

La fonction vapply

La fonction vapply est similaire à sapply, mais elle possède un type de valeurs spécifié, ce qui peut rendre l’utilisation plus sûre (et parfois plus rapide). Lorsqu’on lui fournit un data.frame, vapply retourne le même résultat que sapply. Cependant, quand on lui fournit une liste vide, vapply retourne un vecteur logique de longueur nulle (ce qui est plus sensé que la liste vide que returne sapply).

vapply(X, FUN, FUN.VALUE, ..., USE.NAMES)

avec X, FUN, ... et USE.NAMES les mêmes paramètres que pour sapply. Le paramètre FUN.VALUE doit être un vecteur, un masque pour la valeur retournée par la fonction de FUN.

# Retourner le vecteur
sapply(cars, is.numeric)
speed  dist 
 TRUE  TRUE 
vapply(cars, is.numeric, FUN.VALUE = logical(1))
speed  dist 
 TRUE  TRUE 
# Avec la liste vide
sapply(list(), is.numeric)
list()
vapply(list(), is.numeric, FUN.VALUE = logical(1))
logical(0)

La fonction apply

La fonction apply possède la syntaxe suivante :

apply(X, MARGIN, FUN, ...)

avec X une matrice ou un tableau, MARGIN indiquant si on souhaite appliquer la fonction FUN aux lignes (MARGIN = 1) ou aux colonnes (MARGIN = 2), et ... des paramètres supplémentaires éventuels à passer à la fonction FUN.

(X <- matrix(1:9, ncol = 3))
1 4 7
2 5 8
3 6 9
# Somme par ligne
apply(X, MARGIN = 1, sum)
[1] 12 15 18
# Somme par colonne
apply(X, MARGIN = 2, sum)
[1]  6 15 24
# Fonction définie par l'utilisateur
apply(X, MARGIN = 1, function(x) sum(x) / sum(X))
[1] 0.2666667 0.3333333 0.4000000

La fonction tapply

La fonction tapply s’applique à chaque cellule d’un tableau, sur des regroupements définis par les variables catégorielles fournies. La syntaxe est la suivante :

tapply(X, INDEX, FUN, ..., simplify)

avec X le tableau de données, INDEX une liste d’un ou plusieurs facteurs, chacun de même taille que X. Le paramètre FUN renseigne la fonction que l’on souhaite appliquer. Si simplify vaut FALSE, le résultat est un tableau de mode list. Sinon (par défaut), le résultat est un tableau de scalaires.

data(iris)
head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5.0 3.6 1.4 0.2 setosa
5.4 3.9 1.7 0.4 setosa
# Moyenne de la longueur des sépales par espèce
tapply(iris$Sepal.Length, iris$Species, mean)
    setosa versicolor  virginica 
     5.006      5.936      6.588 
# Pour retourner le résultat sous forme de liste
tapply(iris$Sepal.Length, iris$Species, mean, simplify = FALSE)
$setosa
[1] 5.006

$versicolor
[1] 5.936

$virginica
[1] 6.588

La fonction mapply

La fonction mapply applique une fonction à plusieurs listes ou vecteurs. La syntaxe est la suivante :

mapply(FUN, ..., MoreArgs, SIMPLIFY, USE.NAMES)

avec FUN la fonction à appliquer aux vecteurs ou listes fournies (grâce à ...), MoreArgs une liste de paramètres supplémentaires à fournir à la fonction à appliquer. Les paramètres SIMPLIFY et USE.NAMES ont le même usage que pour la fonction sapply.

(l1 <- list(a = c(1:5), b = c(6:10)))
$a
[1] 1 2 3 4 5

$b
[1]  6  7  8  9 10
(l2 <- list(c = c(11:15), d = c(16:20)))
$c
[1] 11 12 13 14 15

$d
[1] 16 17 18 19 20
# La somme des éléments correspondants de l1 et l2
mapply(sum, l1$a, l1$b, l2$c, l2$d)
[1] 34 38 42 46 50
# Attention au recyclage silencieux !
(l1 <- list(a = c(1:5), b = c(6:20)))
$a
[1] 1 2 3 4 5

$b
 [1]  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
mapply(sum, l1$a, l1$b, l2$c, l2$d)
 [1] 34 38 42 46 50 39 43 47 51 55 44 48 52 56 60

La fonction Vectorize

La fonction Vectorize permet de convertir une fonction scalaire en une fonction vectorielle. Attention, cela ne permet pas d’améliorer la rapidité d’exécution du code. Par contre, son utilisation assez intuitive permet de gagner du temps. Il s’agit donc de faire l’arbitrage entre le temps passé à trouver un moyen élégant et efficace pour effectuer une opération en passant par de réels calculs vectoriels et le gain d’exécution que ce calcul vectoriel apporte vis-à-vis d’une boucle. La syntaxe de la Vectorize est la suivante :

Vectorize(FUN, vectorize.args, SIMPLIFY, USE.NAMES)

avec FUN une fonction à appliquer, vectorize.args un vecteur de paramètres (de type caractère) qui devraient être vectorisés (par défaut, tous les paramètre de FUN). Les paramètres SIMPLIFY et USE.NAMES on le même emploi que dans la fonction sapply.

f <- function(x = 1:3, y) c(x, y)
# On "vectorise" la fonction f
vf <- Vectorize(f, SIMPLIFY = FALSE)
f(1:3, 1:3)
[1] 1 2 3 1 2 3
vf(1:3, 1:3)
[[1]]
[1] 1 1

[[2]]
[1] 2 2

[[3]]
[1] 3 3
# Vectorise seulement y, pas x
vf(y = 1:3)
[[1]]
[1] 1 2 3 1

[[2]]
[1] 1 2 3 2

[[3]]
[1] 1 2 3 3