Le “problème” de la vectorisation

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.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *