2.7 Opérateurs et expressions

Dans ce chapitre, nous allons voir les différents opérateurs qui existent en R, en particulier les opérateurs qui produisent des valeurs TRUE et FALSE , et comment les utiliser au sein d'expressions.

Un peu de vocabulaire

Commencons par un peu de vocabulaire : qu'est ce qu'un opérateur ? C'est tout simplement un élément du langage, comme + , - ou encore = , qui sont des opérateurs que vous connaissez déja. Ainsi + est appelée l'opérateur de l'addition, - celui de la soustraction, et = est appellé l'opérateur d'affectation (car il permet d'affecter des valeurs à des variables).

Chaque fois que vous réalisez un calcul ou créer une variable, vous utilisez en réalité un opérateur :

print(2+2) #on utilise l'opérateur d'addition
print(-4) #on utilise l'opérateur de soustraction
age = 5 + 5 #On utilise l'opérateur = et l'opérateur + dans une même instruction

Les élément sur lesquels s'applique un opérateur sont appellés les opérandes.

La plupart des opérateurs sont binaires, ce qui veut dire qu'ils ont besoin de deux opérandes. Par exemple dans 4 + 2 on utilise l'opérateur binaire + , qui utilise deux opérandes : les nombres de type double 4 et 2 .

L'opérateur d'effectation = est lui aussi binaire : il à besoin d'un nom de variable à gauche, et d'une valeur ou expression à droite pour fonctionner.

Certains opérateurs sont eux des opérateurs unitaires : ils ont besoin d'un seul opérande pour fonctionner. Nous en avons rencontré plusieurs, en particulier l'opérateur - . En effet, vous pouvez simplement écrire -5 pour prendre l'oposé du nombre 5 . Un seul opérante, ici le nombre 5 , est requis. Cet opérateur - est à la fois unitaire et binaire : on peut aussi lui donner deux arguments pour réaliser une soustraction, comme dans 12 - 4 .

Maintenant que vous avons connaissons du vocabulaire de base, partons à la découverte de nouveaux opérateurs !

Les opérateurs relationnels

Il existe en R plusieurs opérateurs qui nous permettent de comparer des valeurs entre elles, que l'on appelle pour cela des opérateurs de comparaison, ou opérateurs relationnels. Ces opérateurs comparent deux éléments entre eux, produisent un logical selon le résultat de cette comparaison. Les opérateurs relationnels en R sont les suivants :

  • == qui indique si deux valeurs sont indentiques
  • != qui indique si deux valeurs sont différentes
  • < et > qui comparent respectivement si une valeur est strictement inférieur ou supérieure à l'autre
  • <= et >= qui font la même chose mais respectivement pour inférieur ou égale et supérieur ou égale

Entrons un peu dans les détails pour voir comment ces opérateurs relationnels se comportent.

L'opérateur d'égalité ==

Le premier opérateur relationnel que nous allons voir est l'opérateur == . Cet opérateur binaire permet de tester si les deux opérantes placé de chaque coté sont égaux entre eux. Il renvoit TRUE si les deux valeurs sont égales, et FALSE si ce n'est pas le cas.

print(5 == 5) #affiche TRUE car 5 est égal à 5
print(5 == 4) #affiche FALSE car 5 est différent de 4
print(2+2i == 2+2i) #affiche TRUE
print(2+3i == 2+2i) #FALSE car les parties imaginaires sont différentes

L'opérateur == devient tout de suite plus intéressant quand on l'utilise pour comparer des variables :

age = 25 
x = 10 
y = 25
print(age == 10) #FALSE
print(age == 25) #TRUE
print(age == x) #FALSE
print(age == y) #TRUE

Avec des vecteurs :

Comme les opérateurs d'opérations mathématiques (+ , - ,* , etc.), l'opérateur == fonctionne également sur les vecteurs. Les comparaisons se font membre à membre, et un vecteur de même taille que les vecteurs d'orgine est retourné :

vect1 = c(1,2,3)
vect2 = c(2,2,2) 
print(vect1 == vect2) #affiche FALSE  TRUE FALSE 
vect3 = vect1 == vect2 #on peut aussi affecter le résultat à un autre vecteur

Si les deux vecteurs sont de longueur différente, alors le même fonctionne s'applique qu'avec les opérateurs mathématiques : le vecteur le plus court est à nouveau réutilisé pour être comparé avec les éléments restant du plus grand vecteur :

vect1 = c(1,2,3)
vect2 = c(3,2)
print(vect1 == vect2) #affiche FALSE  TRUE  TRUE

Selectionner des éléments dans un vecteur :

L'opérateur == est trés pratique car on peut l'utiliser pour selectionner uniquement certains éléments dans un vecteur. Supposons que nous ayons un vecteur de nombres, et que nous voulions en extraire uniquement les éléments dont la valeur est 2 . On peut utiliser cet opérateur == pour créer un vecteur de logical qui indique TRUE pour chaque élément si il est égal à 2 et FALSEsinon. Puis on se sert de ce vecteur logical pour selectionner les valeurs à TRUE dans notre vecteur de départ comme nous l'avons vu au chapitre précédent :

vect = c(1,2,3,4,2,5,2) 
index = vect == 2
only_two_vect = vect[index] #Nous avons vu cela au chapitre précédent, vous vous souvenez ?
print(only_two_vect) #2 2 2
#On peut aussi le faire de façon plus compacte :
print(vect[vect == 2 ])

L'opérateur == et les chaines de caractéres

L'opérateur == fonctionne également sur les chaines de caractéres, et renvois TRUE uniquement si les deux chaines ont exactement la même valeur :

president = "Washington" 
print(president == "Washington") #TRUE car la variable president est égale à "Washington"
print(president == "Bashington") #FALSE 
print(president == "WAshington") #FAUX car la comparaison est sensible aux majuscules

L'opérateur == et les logical

Si vous utiliser l'opérateur == sur des vecteurs de logical, il donnera TRUE si les deux valeurs sont identiques, et FALSE sinon :

print(TRUE == TRUE) #TRUE car TRUE est toujours égal à TRUE
print(TRUE == FALSE) #FALSE car TRUE est différent de FALSE
print(FALSE == FALSE) #TRUE car FALSE est égal à FALSE

L'opérateur de différence : !=

Il existe un opérateur "opposé" à l'opérateur d'égalité== , qui est l'opérateur de différence != . Il nous permet cette fois non pas de tester si deux valeurs sont identiques, mais si elles sont différentes. Cet opérateur != renvois TRUE quand les deux opérandes utilisés ne sont pas identiques :

print(5 != 5) #affiche FALSE car 5 est égal à 5
print(5 != 4) #affiche TRUE car 5 est différent de 4
print(2+2i != 2+2i) #affiche FALSE
print(2+3i != 2+2i) #TRUE car les parties imaginaires sont différentes

Cet opérateur != fonctionne exactement comme l'opérateur == , mais ils renvoient chaque un booléen opposé. Selon que vous ayez besoin de savoir si deux valeurs sont égales ou différentes, l'un des deux opérateurs sera plus approprié que l'autre.

Reprenons notre exemple vu plus haut où nous voulions afficher uniquement les élements égaux à 2 de notre vecteur. Si nous souhaitons maintenant au contraire ne garder que les éléments différents de 2 , on peut utiliser l'opérateur != pour cela :

vect = c(1,2,3,4,2,5,2) 
print(vect[vect != 2 ])
#affiche 1  3  4  5

Les deux opérateurs ont donc leur utilité propre pour exprimer facilement ce que vous voulez faire, selon le contexte de la tache demandée.

Egalité et nombres flottants

Au premier chapitre de cette partie, nous avons dis que R ne peut stocker correctement les nombres avec un nombre infini de décimale. R va alors retenir la valeur la plus proche possible qu'il lui est possible de retenir. Ceci peut entraine des erreurs lors d'opérations, en particulier lors de test d'égalité entre des nombres :

0.1 + 0.2 == 0.3#affiche... FALSE !

Aussi surprenant que cela puisse paraitre, en R cette égalité es fausse. La raison est simple : en binaire, les deux coté de l'opérateur == ont une écriture avec un nombre infini de décimales, qui est différente.

Dans notre base décimale, nous savons que certains nombres ont une écriture "infinie", comme par exemple 1/3 = 0.3333... . Et bien ceci est aussi vraie pour la base binaire (composée de 0 et de 1 au lieu des chiffres de 0 a 9) qui est la base que tous les langages de programmations utilisent. Un nombre pour en base décinmale peut avoir une écriture toute à fait finie, alors que l'écriture de ce même nombre en base binaire posera probléme. Par exemple 0.1 s'écrit parfaitement pour nous humains, mais base binaire cela donne : 0.0001100110011001100110011 avec le patern 00011 qui se répéte à l'infini !

Comme R ne dispose que d'une place limitée pour stocker les nombres, il doit en stocker une valeur approchée. Il ne peut donc pas retenir la "vraie" valeur de 0.2, mais un nombre proche. Le nombre le plus proche que R peut retenir est le nombre 0.200000000000000011102230246251565404236316680908203125 dans notre base décimale.

C'est à cause de ce problème que la somme des valeurs approchées de 0.1 et de 0.2 n'est pas égal à 0.3 pour R. L'opération exacte réalisée par R est la suivante : 0.1000000000000000055511151231257827021181583404541015625 + 0.200000000000000011102230246251565404236316680908203125 = 0.3000000000000000444089209850062616169452667236328125 . Hors la représentation de 0.3 est égale à 0.299999999999999988897769753748434595763683319091796875 . Les deux cotés de l'opérateur ne sont donc pas égaux pour R, voilà pourquoi il nous renvois que l'égalité est fausse.

C'est pour cette raison qu'il faut être prudent quand on manipule les nombres en R, en particulier quand on cherche à réaliser des tests d'égalité comme ceux que l'on vient d'essayer de faire. Le résultat obtenu par R peut parfois être surprenant pour nous humains, qui oublions que R manipule du binaire et non des nombres décimaux !

Les opérateurs >, <, >= et <=

Aprés l'opérateur de comparaison d'égalité == et l'opérateur d'inégalité !=, nous allons avoir les quatres opérateurs de supériorité/infériorité. Les opérateurs > et < permettent de tester si une valeur est strictement supérieure ou strictement inférieure à une autre; >= et <= font la même chose, mais avec l'inégalité non stricte.

Ces opérateurs fonctionnent tous selon le même principe : Ils renvoient TRUE si la comparaison est vraie; et FALSE sinon. Regardons quelques exemples pour l'inégalité stricte :

print( 5 > 4) #TRUE, car 5 est supérieur à 4
print( 4 > 5) #FALSE, 4 n'est pas supérieur à 5
print(5 < 4) #FALSE, 5 n'est pas inférieur à 5
print(4 < 5) #TRUE car 4 est inférieur à 5

De même pour l'égalité stricte :

#Inégalités non stricte :
print( 5 >= 4) #TRUE, car 5 est supérieur ou égal à 4
print( 5 >= 5) ##TRUE, 5 est supérieur ou égal 5
print(5 <= 4) #FALSE, 5 n'est pas inférieur ou égal à 4
print(4 <= 5) #TRUE car 4 est inférieur ou égal à 5

Comparaison entre logicial

Ces opérateurs permettent également de comparer des boolens entre eux, comme on peut le voir :

 print(TRUE > FALSE) #TRUE
 print(FALSE < TRUE) #TRUE
 print(TRUE > TRUE) #FALSE
 print(TRUE <= FALSE) #TRUE

La régle est intuitive et facile à deveniner : TRUE est toujours considéré comme supérieur à FALSE, et la comparaison large entre deux logical de même valeur donne toujours TRUE , comme par exemple TRUE >= TRUE qui sera évalué à TRUE.

Comparaisons entre complex

Les opérateurs >, < , <= et >= ne fonctionnent pas en rechanche avec les nombres complexes, et vont toujours produire une erreur. R refusera de réaliser la comparaison entre nombres complexes :

print(5+2i > 4+1i) #erreur : invalid comparison with complex values
print(4+4i >= 4+1i) #erreur : invalid comparison with complex values

La seule chose possible est de tester leur égalité ou non avec les opérateurs == et != que nous avons vu plus haut. La raison de ce refus de R de comparer les nombres complexes ainsi est que quand les parties réelle et imaginaire sont différentes, R ne saurait pas si c'est le nombre avec la partie réelle la plus grande qui l'emporte ou celui avec la partie imaginaire la plus grande.

Comparaisons entre chaines de caractéres :

La comparaison entre chaines de caractéres est en revanche possible. Elle se fait par ordre lexicographique, qui l'ordre utilisé pour classé les mots dans un dictionnaire. Les lettres de chaque chaine sont comparées les unes avec les autres, et celle qui vient en premier dans l'ordre alphabétique est considérée comme la plus petite. Ainsi un mot qui parrait en premier dans le dictionnaire est considéré plus petit que celui qui vient aprés.

print("A" > "B") #affiche... FALSE car A est avant B dans l'alphabet donc A est plus petit
print("Obama" < "Washington") #TRUE comme W est aprés A, il est plus grand
print("chat" > "chats") #FAUX car chats est aprés chat dans un dictionnaire

Il faut donc bien faire attention : c'est la chaine qui vient en dernier dans l'ordre lexicographique qui est considérée comme la plus grande des deux.

Langue locale et caractéres spéciaux :

Il faut toujours être prudent en comparant les chaines de caractéres. En effet, R utilise pour cela l'ordre alphabétique de la langue installée sur votre ordinateur. Or dans certaines langues, l'ordre des lettres est différents de celui de notre alphabet latin. Ainsi en Estonian la lettre z est entre le s et le t , et en suédois aa compte comme une seule lettre. De plus, si vous comparer des chaines qui contiennent des caractéres spéciaux comme des signes de ponctuation, un certain ordre sera attribué à ces caractéres par rapport aux lettres de l'alphabet, change aussi selon la langue.

Si votre langue est le français ou l'anglais et que vous comparer des chaines de ces langues, vous ne devriez en principe pas rencontrer de problémes, sauf éventuellement avec la ponctuation. Il existe des solutions avancée pour travailler correctement avec les chaines de caractéres, mais cela sortirait du cadre de ce cours. Gardez simplement en tête que comparer des chaines avec les opérateurs de base ne fonctionne pas toujours comme attendu, et que le résultat dépend de la langue de votre machine et parfois de votre systéme d'exploitation.

Opérations entre deux éléments de types différents

Pour l'instant nous avons seulement appliqué nos opérateurs sur des éléments de même type. Que ce passe-t-il si nous essayons d'utiliser des opérandes de types différents ? R va simplement convertir les deux éléments que chaque coté de l'opérateur, pour qu'ils puissent avoir le même type. Il suivra pour cela exactement les mêmes régles que celles que nous avons vu il y a deux chapitres. Ainsi les opérantes seront converti dans le type dominant (character , complex , double , integer puis logical ) et comparés entre eux.

Regardons quelques exemples :

print( 5 == 5L) #TRUE
print(5 == "5") #TRUE
print( 5 < "A") #TRUE, les nombres viennent aprés les lettres pour R 
print(5 >= 5 + 0i) #Erreur, R refuse de comparer des complexes

Il est en général déconseillé de comparer des éléments de types différents entre eux, en particulier des chaines avec des nombres. Comme avec les vecteurs, il faut toujours faire attention quand on manipule ensemble des éléments qui ne sont pas tous du même type.

Les opérateurs logiques

Nous vennons de voir les six opérateurs relationnels : == ,!= , < , > ,<= et >= . Nous allons maintenant parler d'un autre type d'opérateurs, les opérateurs logiques.

L'opérateur de négation !

L'opérateur de négation ! permet d'inverser la valeur d'un logical : Tous les TRUE deviennent FALSE et tous les FALSE se transforment en TRUE :

print(!TRUE) #affiche FALSE
print(!FALSE) #affiche TRUE
print(c(TRUE,FALSE)) #affiche FALSE  TRUE

Comme nous l'avons vu au chapitre précédent, cet opérateur peut être pratique pour inverser un vecteur logical pour selectionner uniquement certaines valeurs.

Les opérateurs & et &&

Les opérateurs & et && correspondent au "ET" logique (AND en anglais). L'opérateur & est vrai si les deux opérandes de chaque coté sont vrai :

print(TRUE & TRUE) #TRUE
print(FALSE & FALSE) #FALSE
print((10 > 5) & (6 > 5)) #TRUE car 10>5 est vrai et 6>5 est vrai aussi

Cet opérateur & fonctionne également sur les vecteurs, où il va réaliser la comparaison membre à membre :

vect1 = c(TRUE, TRUE, FALSE)
vect2 = c(TRUE, FALSE, FALSE)
print(vect1 & vect2) #affiche TRUE FALSE FALSE

L'opérateur && fonctionne de la même façon que & , si ce n'est que dans le cadre d'un vecteur il ne regardera que le premier élement de chaque vecteurs :

vect1 = c(TRUE, TRUE, FALSE)
vect2 = c(TRUE, FALSE, FALSE)
print(vect1 && vect2) #affiche TRUE car ne regarde que le premier élément

Ainsi, selon la comparaison que vous voulez faire, il faudra utiliser l'opérateur ET approprié.

Les opérateurs | et ||

Ces opérateurs correspondent au OU logique (OR en anglais). | est vrai si au moins un des deux opérande de chaque coté est vrai.

print(TRUE || FALSE) #TRUE 
print(TRUE || TRUE) #TRUE, le OU est inclusive, les deux peuvent être vrais en même temps 
print(10 > 5 || 5 <10) #TRUE car 10>5 est vrai

Dans le cas d'un vecteur, il réalise cette comparaison membres à membres, alors que || n'opére que sur le premier élément.

vect1 = c(TRUE, TRUE, FALSE)
vect2 = c(TRUE, FALSE, FALSE)
print(vect1 | vect2) #affiche TRUE TRUE FALSE
print(vect1 || vect2) #affiche TRUE car regarde uniquement le premier element

Remarque : Il existe également en R la possibilité d'un OU exclusif, ou XOR en anglais. Mais ce n'est pas un opérateur, mais une fonction (la fonction xor() ). Nous parlerons de cette fonction ainsi que des autres fonctions de ce type qui produisent des boolens au chapitre suivant.

Remarque 2: Quand NA est impliqué dans l'opérateur | ou || le résultat est déterminé correctement. Par exemple NA || TRUE donnera TRUE . En effet, l'indétermination n'empêche pas de faire le calcul, le résultat n'a donc pas de raison de donner NA .

Expressions à l'aide des opérateurs

Les différents opérateurs que nous avons vu sont particuliérement utiles quand on les combine entre eux pour calculer le résultat logique d'expressions. Imaginons une banque qui souhaite ouvrir un compte à un client uniquement si celui ci est majeur et si il à plus de 100 000€ sur son compte à déposer. Elle pourrait écrire le code suivant :

age = 25
montant = 98000
autorisation_ouverture = (age >= 18) && (montant > 100000) 
print(autorisation_ouverture) #FALSE, car montant < 100000

L'expression (age >= 18) && (montant > 100000) est évaluée à TRUE uniquement si age>=18 est vraie et si montant > 100000 est vrai en même temps. Alors le résultat sera affecté à la variable autorisation_ouverture.

On peut également combiner les différents opérateurs logiques entre eux. Par exemple on imagine qu'un individu qui aurait entre 15 et 18 ans mais qui serait vraiment riche (disons plus qu'un 1 million d'euro) pourrait obtenir une exception et ouvrir aussi un compte. Codons cette condition :

age = 17
montant = 1200000
autorisation_ouverture = ((age >= 18) && (montant > 100000)) || ((age >= 15) && (montant > 1000000))
print(autorisation_ouverture) #TRUE car l'individu à 17 et 1 200 000€

On peut voir que notre expression est plus complexe, et utilise à la fois le ET et le OU logique. ((age >= 18) && (montant > 100000)) || ((age >= 15) && (montant > 1000000)) est vrai uniquement si (age >= 18) && (montant > 100000) est évalué à TRUE OU alors si ((age >= 15) && (montant > 1000000)) est évalué à TRUE (ou les deux vrais en même temps).

Remarquez bien l'utilisons des parenthéses pour séparer correctement les différentes conditions entre elles.

On préfère souvent utiliser &&et || , car c'est comme ça que s'écrivent ces opérateurs dans la plupart des langages de programmations, c'est donc une habitude. On l'utilisera la forme & et | uniquement pour travailler sur des vecteurs de longueur supérieur à 1.

Opérations impliquants NA

Terminons ce chapitre en parlant un peu des NA . Nous avons vu lors du chapitre précédent que toute opération mathématique impliquant NA produisait également NA . Comme nous savons maintenant que les opérateurs mathématiques sont des opérateurs parmis d'autres, nous pouvons présenter la régle générale : toute opérateur dont au moins un des opérande est NA produira un résultat NA , sauf si le résultat ne dépend jamais de la valeur que pourrait prendre NA. Là encore, l'explication est la même que dans le chapitre précédent : cela permet de savoir que l'opération échoue car une des valeurs est une observation manquante, et non à cause d'un problème mathématique quelquconque.

print(5 == NA) #affiche NA 
print("Obama" > NA) #affiche NA
print( NA == NA) #affiche NA aussi !
print(NA && TRUE) #NA
print(NA || (5 > 4)) #TRUE car NA c'est pas utile à la détermination du résultat !

A retenir :

  • Un opérateur s'applique sur un ou plusieurs opérandes. On parle alors d'opérateur unitaire ou binaire. Nous connaissons déjà certains opérateurs, comme + , - ou = qui sont les opérateurs d'addition, de soustraction et d'affectation.
  • On peut tester l'égalité de deux variables ou valeurs avec l'opérateur == . Il renvoit TRUE en cas d'égalité et FALSE sinon. Il existe un opérateur != qui renvois les valeurs inverse. Ces opérateurs sont particuliérement utiles pour selectionner des valeurs dans un vecteur.
  • On peut réaliser des comparaisons entre valeurs/variables avec les opérateurs > ,< ,<= ,>= . Ces opérateurs ne fonctionnent pas avec les nombres complexes, et classent les chaines par ordre lexicographique (la chaine la plus loin dans le dictionnaire est la plus grande). Cet ordre lexicographique repose sur la langue de votre ordinateur.
  • Tous les opérateurs doivent utiliser des opérandes de même type. Si ce n'est pas le cas, alors il y aura une conversion de type selon les régles vuent aux chapitres précedents.
  • Les opératations se font membres à membres quand elles s'appliquent à des vecteurs.
  • L'opérateur logique ! renvoit l'opposé d'un vecteur de logical , en transformant TRUE en FALSE et vis versa.
  • L'opérateur & renvoit TRUE si les deux opérandes sont vrais de chaque coté. Il s'applique aux vecteurs (comparaison membres à membres) alors que && lui ne fonctionne sur le premier élement que chaque opérande.
  • L'opérateur logique | renvoit TRUE si au moins un des deux opérandes est vrai. Il fonctionne membre à membre sur les vecteurs, alors sa version || ne prend en compte que le premier élément de chaque opérande.
  • On peut combiner tous les opérateurs entre eux pour produire des expressions sur seront évaluée. C'est trés utile pour exprimer des ensembles de conditions.
  • NA produit toujours NA , sauf si la valeur potentiellement prise par NA n'a aucune influence sur le résultat.

results matching ""

    No results matching ""