En plus de la construction habituelle if-then-else trouvée dans la plupart des langues, R comprend également une version vectorisée, la fonction ifelse (). Le formulaire est le suivant: ifelse (b, u, v) où b est un vecteur booléen, et u et v sont des vecteurs.
La valeur de retour est elle-même un vecteur; element i est u [i] si b [i] est vrai, ou v [i] si b [i] est faux. Le concept est assez abstrait, alors allons bien à l'exemple suivant:

  1. > x <- 1:10
  2. > y <- ifelse (x %% 2 == 0,5,12) # %% est l'opérateur de mod
  3. > y
  4. [1] 12 5 12 5 12 5 12 5 12 5
Source code
Ici, nous souhaitons produire un vecteur dans lequel il y a un 5 où x est égal ou 12 partout où x est impair. Ainsi, l'argument réel correspondant à l'argument formel b est (F, T, F, T, F, T, F, T, F, T). Le deuxième argument réel, 5, correspondant à u, est traité comme (5,5, ...) (dix 5s) par recyclage. Le troisième argument, 12, est également recyclé, à (12,12, ...).
  1. > x <- c (5,2,9,12)
  2. > ifelse (x> 6,2 * x, 3 * x) [1] 15 6 18 24
Source code
Nous renvoyons un vecteur constitué des éléments de x multipliés par 2 ou 3, selon que l'élément est supérieur à 6.
Encore une fois, cela contribue à réfléchir à ce qui se passe réellement ici. L'expression x> 6 est un vecteur de booléens. Si le ième composant est vrai, le ième élément de la valeur de retour sera défini sur le ième élément de 2 * x; sinon, il sera réglé sur 3 * x [i], et ainsi de suite.
L'avantage de ifelse () sur la construction standard if-then-else est qu'elle est vectorisée, donc potentiellement beaucoup plus rapide.


1 Exemple étendu: une mesure de l'association
En évaluant la relation statistique de deux variables, il existe de nombreuses alternatives à la mesure de corrélation standard (Pearson product-moment correlation). Certains lecteurs ont peut-être entendu parler de la corrélation de rang de Spearman, par exemple. Ces mesures alternatives ont diverses motivations, telles que la robustesse aux valeurs aberrantes, qui sont des éléments de données extrêmes et éventuellement erronés.
Ici, proposons une nouvelle mesure de ce genre, pas nécessairement pour de nouveaux mérites statiques (en fait, elle est liée à une utilisation large, Kendall's T), mais pour illustrer certaines des techniques de programmation R introduites dans ce chapitre, en particulier ifelse () .
Considérons les vecteurs x et y, qui sont des séries chronologiques, par exemple pour les mesures de la température et de la pression de l'air recueillies une fois par heure. Nous définirons notre mesure d'association entre eux pour être la fraction du temps x et y augmenter ou diminuer ensemble, c'est-à-dire la proportion de i pour laquelle y [i + 1] -y [i] a le même signe que x [i + 1] -x [i]. Voici le code:

  1. # findud () convertit le vecteur v en 1s, 0s, représentant un élément
  2. # augmentant ou non, par rapport à la précédente; la longueur de sortie est 1
  3. # less than input
  4. findud <- function(v) {
  5. vud <- v[-1] - v[-length(v)]
  6. return(ifelse(vud > 0,1,-1))
  7. }
  8. udcorr <- function(x,y) {
  9. ud <- lapply(list(x,y),findud)
  10. return(mean(ud[[1]] == ud[[2]]))
  11. }
Source code

Voici un exemple:

  1. > x
  2. [1] 5 12 13 3 6 0 1 15 16 8 88
  3. > y
  4. [1] 4 2 3 23 6 10 11 12 6 3 2
  5. > udcorr(x,y)
  6. [1] 0.4
Source code
Dans cet exemple, x et y ont augmenté ensemble dans 3 des 10 opportunités (la première fois étant les augmentations de 12 à 13 et 2 à 3) et ont diminué ensemble une fois. Cela donne une mesure d'association de 4/10 = 0,4.
Voyons comment cela fonctionne. Le premier ordre d'activité est de recoder x et y aux séquences de 1s et -1s, avec une valeur de 1 signifiant une augmentation de l'observation actuelle par rapport à la dernière. Nous l'avons fait dans les lignes 5 et 6.
Par exemple, pensez ce qui se passe dans la ligne 5 lorsque nous appelons findud () avec v ayant une longueur de, par exemple, 16 éléments. Alors v [-1] sera un vecteur de 15 éléments, en commençant par le second élément dans v. De même, v [-length (v)] sera encore un vecteur de 15 éléments, cette fois à partir du premier élément in v. Le résultat est que nous soustrayons la série originale de la série obtenue en changeant vers la droite d'une seule période. La différence nous donne la séquence des états d'augmentation / diminution pour chaque période, exactement ce dont nous avons besoin.

 

Nous devons ensuite modifier ces différences à 1 et -1, selon que la différence soit positive ou négative. L'appel ifelse () est facile, compact et avec un temps d'exécution plus petit qu'une version en boucle du code aurait.
Nous aurions alors écrit deux appels à findud (): l'un pour x et l'autre pour y. Mais en mettant x et y dans une liste, puis en utilisant lapply (), nous pouvons le faire sans dupliquer le code. Si nous appliquions la même opération à plusieurs vecteurs au lieu de seulement deux, surtout dans le cas d'un nombre variable de vecteurs, utiliser lapply () comme ceci serait d'une grande aide pour compacter et clarifier le code, et il pourrait être légèrement plus rapide ainsi que.
Nous trouvons alors la fraction des correspondances, comme suit:
  1. return(mean(ud[[1]] == ud[[2]]))
Source code
Notez que lapply () renvoie une liste. Les composants sont nos vecteurs codés 1 / -1. L'expression ud [[1]] == ud [[2]] renvoie un vecteur de valeurs TRUE et FALSE, qui sont traitées comme 1 et 0 valeurs par moyenne (). Cela nous donne la fraction désirée.
Une version plus avancée utiliserait la fonction diff () de R, qui fait des opérations de retard pour les vecteurs. Nous pourrions, par exemple, comparer chaque élément avec l'élément trois points derrière lui, appelé un retard de 3. La valeur de décalage par défaut est une période unique, juste ce dont nous avons besoin ici.
  1. > u
  2. [1] 1 6 7 2 3 5
  3. > diff(u)
  4. [1] 5 1 -5 1 2
Source code
Ensuite, la ligne 5 de l'exemple précédent deviendrait ceci:
  1. vud <- diff(d)
Source code
Nous pouvons rendre le code vraiment compact en utilisant une autre fonction R avancée, signe (), qui convertit les nombres dans son vecteur d'argument en 1,
0 ou -1, selon qu'ils sont positifs, zéro ou négatifs. Voici un exemple:
  1. > u
  2. [1] 1 6 7 2 3 5
  3. > diff(u)
  4. [1] 5 1 -5 1 2
  5. > sign(diff(u))
  6. [1] 1 1 -1 1 1
Source code
L'utilisation du signe () nous permet ensuite de transformer cette fonction udcorr () en un one-liner, comme suit:
  1. > udcorr <- function(x,y) mean(sign(diff(x)) == sign(diff(y)))
Source code
C'est certainement beaucoup plus court que la version originale. Mais est-ce mieux? Pour la plupart des gens, il faudra probablement plus longtemps pour écrire. Et bien que le code soit court, il est difficile de comprendre.
Tous les programmeurs R doivent trouver leur propre «moyen heureux» dans la brièveté des opérations pour plus de clarté.