Les tests

Un petit article aujourd’hui sur les tests pour vous présenter if / ifelse / switch

Si vous programmez déjà vous connaissez obligatoirement ce qu’est un test : il s’agit d’une structure qui exécute selon un résultat logique un ensemble d’instruction, ou un autre si ce résultat est négatif.

Typiquement, il s’agit de (par exemple en python) :

if (condition) :
   print("instructions en cas de résultat conditionnel positif.")
else :
   print("instructions en cas de résultat conditionnel négatif.")

print("suite du programme.")

On parle de contrôle du flot de l’exécution (control flow).

Et si vous utilisez Excel, vous connaissez une version “fonctionnelle” (au sens qui prend la forme d’une fonction et retourne une valeur) :

SI(TEST;VALEUR_SI_VRAI;VALEUR_SI_FAUX)

Et bien R fait de même… pour les 2 approches.

IF – ELSEIF – ELSE

R possède un similaire de la première présentation.

Le langage attend entre les parenthèses () une valeur assimilable à un booléen [TRUE|FALSE]. Nous pouvons faire par exemple :

#En supposant que "x" contienne une chaine de caractères
if (x == "RSS") {
   y <- 1
} else if (x == "RSF") {
   y <- 2
} else {
   y <- NA
}

Ainsi on obtiendrait selon la chaine en entrée :

Valeur en entrée (x)Valeur en sortie (y)
“RSS”1
“RSF”2
toute autre chaineNA

La particularité est que “if” n’est pas vectorisé. Cela signifie que si x est un vecteur, c’est uniquement le 1er élément du vecteur qui est testé et non chacun de ses constituants un à un.

Valeur en entrée (x)Valeur en sortie (y)
c(“RSS”,”RSF”)Warning message:
In if (x == "RSS") { :
the condition has length > 1 and only the first element will be used

et y = 1 (comme si x = “RSF”)

Par ailleurs, if ne retourne pas vraiment de valeur, il retourne l’évaluation du bloc conditionnel qu’il a exécuté. Nous pourrions donc faire :

y <- if (x == "RSS") 1 else if (x == "RSF") 2 else NA

(Les accolades { } sont facultatives si il n’y a qu’une instruction dans chaque groupe d’instructions. A titre personnel, je préfère les mettre pour une question de lisibilité)

Ifelse()

ifelse(), le pendant du SI() d’Excel existe aussi sous R.

Le prototype en est ifelse(TEST,SI_VRAI,SI_FAUX) et retourne la valeur SI_VRAI ou SI_FAUX selon le résultat du test.

On peut donc écrire y <- ifelse(x == "RSS",1,NA). Cependant ce code n’est pas superposable à ci-dessus. Il manque le else if. Pour le faire, il faut imbriquer des ifelse :

y <- ifelse(x == "RSS",1,ifelse(x == "RSF",2,NA))

# Pour une meilleure lisibilité, cela peut s'écrire sur plusieurs lignes :
y <- ifelse(x == "RSS",
            1,
            ifelse(x == "RSF",
                   2,
                   NA)
            )

L’avantage de ifelse est qu’à l’opposé de la structure de flux if, cette fonction est vectorisée. Ainsi, si x est égal à c("RSS", "RSF", "autre chose") , le résultat sera :

x <- c("RSS", "RSF", "VIDHOSP")
ifelse(x == "RSS",1,ifelse(x == "RSF",2,NA))
[1]  1  2 NA

Pour un vecteur de longueur X, ifelse() répond donc par un autre vecteur de longueur X.

Ainsi, si nous voulions créer une nouvelle colonne dans un jeu de données en se basant sur la valeur d’une autre, il suffit de faire (notez que j’utilise ici la notation de base et non une version dplyr, avec la librairie, il “suffit” de faire la même chose au sein d’un mutate() ) :

#soit rss un jeu de données contenant DENT et DSORT, 2 dates
rss[, "TYPE"] <- ifelse(rss[, "DENT"] == rss[, "DSORT"], "séjour zéro jour", "hospitalisation complète")
rss[,"TYPE"]
 RSS [,"TYPE"]
# A tibble: 84,377 x 1
   TYPE                    
   <chr>                   
 1 séjour zéro jour        
 2 séjour zéro jour        
 3 hospitalisation complète
 4 hospitalisation complète
 5 hospitalisation complète
 6 hospitalisation complète
 7 séjour zéro jour        
 8 hospitalisation complète
 9 hospitalisation complète
10 séjour zéro jour        

# La version dplyr :
rss <- rss %>% mutate(TYPE = ifelse(DENT == DSORT, "séjour zéro jour", "hospitalisation complète")

Le type des données retournées est par contre unique (on ne peut pas mixer par exemple des nombres et des caractères dans la même colonne, le type numérique sera transformé automatiquement en chaine de caractère pour garantir l’homogénéité et si R n’arrive pas à réconcilier les types il générera une erreur)

A noter enfin, que la librairie dplyr, fournit sa propre version nommée if_else()qui offre une option de plus : missing qui permet de rajouter une valeur par défaut si le résultat du test est NA.

Switch()

Switch est une autre construction d’un alternat, son fonctionnement est cependant assez différent : le 1er paramètre est évalué et comparé aux noms (x doit impérativement évaluer une chaine de caractère ou un nombre) des suivants et si il y a une correspondance, la valeur à droite du “=” est renvoyée :

switch(x,
       "RSS" = 1,
       "RSF" = 2,
       NA)

Problème, comme if, switch() n’est pas vectorisé et n’est donc pas utilisable tel quel dans un mutate ou un calcul de colonne. Il est cependant assez pratique car très lisible dans le cas d’un alternat à multiples valeurs.

Laisser un commentaire

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