Ou comment ne pas vectoriser à tort.
La problématique
Nous en avons déjà discuté, R manipule des vecteurs. Ceux-ci peuvent donc être passés à des fonctions ainsi :
multiplie(1,2)
est possible mais aussi multiplie(c(1,2),3)
(pour rappel, c() est la fonction de concaténation permettant de créer manuellement des vecteurs).
Voici la définition de notre fonction d’exemple :
multiplie <- function(x, y) { x * y }
Sans regarder la solution, pouvez-vous deviner le résultat ?
> multiplie(c(1,2),3)
[1] 3 6
R a bouclé automatiquement sur le vecteur pour appliquer la fonction.
Cependant, essayons d’autres variantes :
> multiplie(c(1,2),c(3,5)) # <-- R a bouclé sur les 2 vecteurs en même temps et réalisé
# la multiplication membre à membre
[1] 3 10
> multiplie(1,c(3,5)) # <-- R a bouclé sur le 2ème vecteur en réutilisant les
# valeurs du premier
# (sans "Warning" car il n'y a qu'un élément)
[1] 3 5
> multiplie(c(1,2,3),c(3,5)) # <-- R a bouclé sur le vecteur le plus long en réutilisant
# les valeurs du plus court d'où le "Warning"
[1] 3 10 9
Warning message:
In a * b : longer object length is not a multiple of shorter object length
Donc lorsque les paramètres sont des vecteurs, ceux-ci sont automatiquement répétés jusqu’à extinction du plus long.
Dans certains cas, les fonctions ne sont pas prévues pour avoir ce comportement.
Par exemple, si je voulais une fonction à laquelle je passe un vecteur de numéro de GHS et une table contenant tous les GHS avec la DMS nationale pour qu’il me retourne la DMS (prototype : dms_ghs(ghs, liste_ghs)
). Techniquement, il faut donc boucler sur ghs
mais pas sur liste_ghs
et ça R ne peut pas le deviner. Il est possible de programmer directement une fonction de ce type mais pour l’instant vu les connaissances acquises on va profiter des mécaniques prévues par R pour simplifier la vie car il existe une fonction qui le fait à notre place : Vectorize()
(avec un “Z”, attention)
La solution : Vectorize
Ecrire notre fonction devient donc :
dms_ghs <- Vectorize( function(ghs, liste_ghs){ liste_ghs %>% filter(NGHS == ghs)[[1,"DMS"]] }, vectorize.args = "ghs")
Ainsi seuls le paramètre ghs sera vectorisé, liste_ghs sera passé en tant que paramètre simple.
Un exemple tout simple avec des print
:
> f <- Vectorize(function(a, b){print (a); print(b)},vectorize.args = "a") > f(c(1,2,3,4),c(10,20,30)) [1] 1 [1] 10 20 30 [1] 2 [1] 10 20 30 [1] 3 [1] 10 20 30 [1] 4 [1] 10 20 30 [,1] [,2] [,3] [,4] [1,] 10 10 10 10 [2,] 20 20 20 20 [3,] 30 30 30 30
Nous avons pu en quelque sorte forcer la non-évaluation de notre vecteur.
Bonne bidouille pour développer votre fonction de valorisation à titre d’entrainement.