Note préliminaire : Lors de leur dernière mise à jour, ces notes ont été révisées en utilisant R version 4.0.3.
Dans un contexte d’analyse de données, il est courant de devoir effectuer un calcul mathématique simple, par exemple pour transformer une variable ou tester si des observations remplissent une certaine condition. Il est donc essentiel pour tout utilisateur de R de connaître les opérateurs et fonctions mathématiques de base, qui sont présentés ici.
De plus, il n’est pas rare qu’un programmeur R cherchant à implémenter une méthode de calcul doive utiliser de l’algèbre linéaire, du calcul différentiel et intégral ou encore de l’optimisation numérique. Ces possibilités de calculs mathématiques plus avancées en R sont aussi abordées ici (mais ces sujets ne seront pas évalués dans le cadre du cours STT-4230 / STT-6230 R pour scientifique).
Tous les opérateurs et plusieurs des fonctions qui sont présentés dans cette fiche agissent de façon vectorielle. Ils effectuent un traitement élément par élément sur le ou les objets reçus en entrée.
Par exemple, si les deux matrices suivantes sont additionnées avec l’opérateur +
,
matrix(1:6 , nrow = 2, ncol = 3)
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
matrix(6:1 , nrow = 2, ncol = 3)
## [,1] [,2] [,3]
## [1,] 6 4 2
## [2,] 5 3 1
l’élément en position (i,j) dans la première matrice sera additionné à l’élément à la même position dans la deuxième matrice, et ce, pour toutes les positions. Le résultat de cette addition terme à terme est donc le suivant :
matrix(1:6 , nrow = 2, ncol = 3) + matrix(6:1 , nrow = 2, ncol = 3)
## [,1] [,2] [,3]
## [1,] 7 7 7
## [2,] 7 7 7
Si les deux objets intervenant dans l’opération ne sont pas de mêmes dimensions, la règle de recyclage s’applique. Cette règle avait déjà été mentionnée dans les notes sur les structures de données en R. Étant donné son importance, revoyons-là plus en profondeur ici.
<- c(5, 6)
x <- c(2, 5, 3, 1)
y + y x
## [1] 7 11 8 7
L’instruction précédente effectue 4 additions, une pour chacun des 4 éléments du plus long des deux vecteurs dans l’opération, soit ici le deuxième. Le premier vecteur est plutôt de longueur 2. R répète donc ses éléments pour créer un vecteur aussi long que le deuxième
rep(x, times = length(y)/length(x))
## [1] 5 6 5 6
et effectue en réalité l’opération suivante.
c(5, 6, 5, 6) + c(2, 5, 3, 1)
## [1] 7 11 8 7
Cette règle de recyclage est exploitée, souvent sans que l’utilisateur en soit pleinement conscient, lorsque l’un des deux vecteurs impliqués dans une opération est de longueur 1. Par exemple, la commande suivante impliquant un exposant,
^ 2 y
## [1] 4 25 9 1
est en fait traduite par R en la commande suivante :
^ rep(2, times = length(y)) y
## [1] 4 25 9 1
La règle de recyclage s’applique aussi dans des opérations faisant intervenir des objets à plus d’une dimension. Par exemple, pour additionner le même vecteur, disons
<- 3:1
y y
## [1] 3 2 1
à chacune des colonnes d’une matrice, disons
<- matrix(1:12 , nrow = 3, ncol = 4)
mat mat
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
il suffit de lancer la commande suivante
+ y mat
## [,1] [,2] [,3] [,4]
## [1,] 4 7 10 13
## [2,] 4 7 10 13
## [3,] 4 7 10 13
au lieu de la suivante, qui retourne exactement le même résultat.
+ matrix(rep(y, times = length(mat)/length(y)), nrow = nrow(mat), ncol = ncol(mat)) mat
Dans cette dernière commande, les deux arguments fournis à l’opérateur +
sont réellement de mêmes dimensions, car la deuxième matrice est la suivante
matrix(rep(y, length(mat)/length(y)), nrow = nrow(mat), ncol = ncol(mat))
## [,1] [,2] [,3] [,4]
## [1,] 3 3 3 3
## [2,] 2 2 2 2
## [3,] 1 1 1 1
Une règle de recyclage utilisée pour former une matrice de dimension appropriée va donc remplir la matrice une colonne à la fois, comme le fait la fonction matrix
par défaut.
Lorsque la longueur de l’objet le plus long n’est pas multiple de la longueur de l’objet le plus court, la règle de recyclage fonctionne quand même. R recycle l’objet le plus court assez de fois pour arriver à un objet de longueur égale ou supérieure à l’objet le plus long. Ensuite, si l’objet recyclé est plus long que l’autre objet, il est tronqué de façon à ce que les deux objets aient la même longueur.
Prenons par exemple les deux vecteurs suivants :
<- 1:12
x x
## [1] 1 2 3 4 5 6 7 8 9 10 11 12
<- 5:1
y y
## [1] 5 4 3 2 1
Supposons que la commande suivante soit soumise en R.
+ y x
L’objet de gauche dans l’addition est de longueur 12 et l’objet de droite de longueur 5. L’objet de droite sera donc recyclé 3 fois,
<- rep(5:1, times = ceiling(length(x)/length(y)))
y_recycle y_recycle
## [1] 5 4 3 2 1 5 4 3 2 1 5 4 3 2 1
puis sa longueur sera réduite à la longueur de l’objet de gauche.
length(y_recycle) <- length(x)
y_recycle
## [1] 5 4 3 2 1 5 4 3 2 1 5 4
Ensuite l’addition terme à terme sera effectuée.
+ y_recycle x
## [1] 6 6 6 6 6 11 11 11 11 11 16 16
Cependant, R émettra un avertissement pour nous informer qu’il a dû faire cet ajustement de longueur.
+ y x
## Warning in x + y: longer object length is not a multiple of shorter object
## length
## [1] 6 6 6 6 6 11 11 11 11 11 16 16
Voici une liste d’opérateurs arithmétiques disponibles en R :
+
: addition,-
: soustraction,*
: multiplication,/
: division,^
: puissance,%/%
: division entière,%%
: modulo = reste de la division entière.Les premiers opérateurs sont usuels et ne requièrent aucune explication. Expliquons cependant brièvement les deux derniers opérateurs de cette liste.
L’opérateur %/%
réalise une division entière. Pour illustrer ce type de division, prenons l’exemple suivant.
5 / 2
## [1] 2.5
L’opérateur de division ordinaire /
retourne un nombre réel. L’opérateur %/%
retourne la partie entière du résultat obtenu avec /
. La partie décimale est tronquée.
5 %/% 2
## [1] 2
L’opérateur modulo %%
retourne le reste de la division entière. Dans l’exemple traité ici, ce reste vaut 1 car 5 - 2*2 = 1.
5 %% 2
## [1] 1
Astuces :
x %% 2
retourne 0 pour les nombres pairs et 1 pour les nombres impairs.double
est en réalité un entier au sens mathématique. S’il s’agit d’un entier, x %% 1
retournera 0.Les opérateurs de comparaison permettent de comparer des valeurs. Ils retournent TRUE
ou FALSE
. Il s’agit des opérateurs suivants :
==
: égalité,!=
: non-égalité,>
: plus grand,>=
: plus grand ou égal,<
: plus petit,<=
: plus petit ou égal.Supposons x
et y
les deux vecteurs numériques suivants.
<- c(2, 5, 7, 3)
x <- c(3, 5, 6, 4) y
Comparons ces vecteurs à l’aide d’un opérateur de comparaison. Est-ce que les valeurs contenues dans x
sont supérieures aux valeurs contenues dans y
?
> y x
## [1] FALSE FALSE TRUE FALSE
L’opérateur fonctionne de façon vectorielle, donc une comparaison est effectuée pour toutes les paires d’éléments à la même position dans les vecteurs x
et y
. Les valeurs dans le résultat retourné sont de type logique.
Les valeurs dans un vecteur peuvent aussi être comparées à une seule valeur, auquel cas la règle de recyclage s’applique.
!= 5 x
## [1] TRUE FALSE TRUE TRUE
Les opérateurs de comparaison ne fonctionnent pas seulement avec des valeurs numériques. Ils peuvent aussi être utilisés pour comparer des valeurs logiques ou caractères. Dans ce cas, il faut savoir que R considère que FALSE
est inférieure à TRUE
.
FALSE < TRUE
## [1] TRUE
Quant aux caractères, les opérateurs de comparaison utilisent l’ordre de classement des caractères pour déterminer, entre deux valeurs, celle qui est inférieure. Cet ordre dépend des paramètres régionaux de la session R. D’une langue à l’autre, cet ordre peut varier.
Pour connaître l’ordre utilisé dans une session R, les instructions suivantes sont utiles :
<-
caracteres_speciaux c("!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";",
"<", "=",">", "?", "@", "[", "\\", "]", "^", "_", "{", "|", "}", "~")
<- c("à", "â", "é", "è", "ê", "ë", "ï", "î", "ô", "ù", "ü", "û", "ç")
lettres_accentuees <- sort(c(caracteres_speciaux, 0:9, letters, LETTERS,
catacteres_ordonnes toupper(lettres_accentuees)))
lettres_accentuees, paste(catacteres_ordonnes, collapse = "")
J’ai obtenu le résultat suivant, qui sera peut-être différent sur votre ordinateur si vous n’avez pas les mêmes paramètres régionaux que moi.
"'-!\"#$%&()*,./:;?@[\\]^_{|}~+<=>0123456789aAàÀâÂbBcCçÇdDeEéÉèÈêÊëËfFgGhHiIîÎïÏjJkKlLmM
nNoOôÔpPqQrRsStTuUùÙûÛüÜvVwWxXyYzZ"
Ainsi, dans ma session R :
Pour des chaînes à plus d’un caractère, la comparaison s’effectue caractère par caractère (premiers caractères comparés entre eux, puis deuxièmes en cas d’égalité, puis troisièmes en cas d’égalités aux deux premières positions, etc.).
"arborescence" < "arbre"
## [1] TRUE
Aussi, l’absence de caractères vaut moins que la présence.
"a" < "aa"
## [1] TRUE
Remarque : Afin de correctement ordonner des nombres, il faut s’assurer de les stocker sous un format numérique. S’ils sont stockés sous forme de chaînes de caractères, les résultats obtenus ne seront pas toujours ceux attendus, comme dans cet exemple pour lequel 2 est dit non inférieur à 10 lorsque les nombres sont fournis à l’opérateur de comparaison sous forme de chaînes de caractères.
2 < 10
## [1] TRUE
"2" < "10"
## [1] FALSE
Un opérateur ou une fonction logique vectoriel prend en entrée un ou deux vecteurs de logiques et retourne un autre vecteur de valeurs logiques. Le R de base comporte les opérateurs et la fonction logiques vectoriels suivants :
!
: négation,&
: et,|
: ou,xor
: ou exclusif.!
L’opérateur !
n’a qu’un seul argument, alors que les autres opérateurs logiques en ont deux. Il effectue une négation, donc transforme les TRUE
en FALSE
et les FALSE
en TRUE
.
!c(TRUE, FALSE)
## [1] FALSE TRUE
&
et |
, fonction xor
Les opérateurs &
et |
, ainsi que la fonction xor
, appliquent de façon vectorielle les tables de vérité des fonctions mathématiques logiques « et », « ou » et « ou exclusif » respectivement.
Rappel : table de vérité de « et », « ou » et « ou exclusif »
<- rep(c(FALSE, TRUE), each = 2)
p <- rep(c(FALSE, TRUE), times = 2)
q cbind(p, q, "p et q" = p & q, "p ou q" = p | q, "p xor q" = xor(p, q))
## p q p et q p ou q p xor q
## [1,] FALSE FALSE FALSE FALSE FALSE
## [2,] FALSE TRUE FALSE TRUE TRUE
## [3,] TRUE FALSE FALSE TRUE TRUE
## [4,] TRUE TRUE TRUE TRUE FALSE
Ainsi,
p & q
retournera un vecteur contenant des TRUE
aux positions pour lesquelles la valeur en p
et la valeur en q
sont toutes les deux TRUE
et contenant des FALSE
partout ailleurs;p | q
retournera un vecteur contenant des FALSE
aux positions pour lesquelles la valeur en p
et la valeur en q
sont toutes les deux FALSE
et contenant des TRUE
partout ailleurs;xor(p, q)
retournera un vecteur contenant des TRUE
aux positions pour lesquelles la valeur en p
ou la valeur en q
est TRUE
, mais pas les deux, et contenant des FALSE
partout ailleurs.Dans une expression R contenant plusieurs opérateurs, mathématiques ou non, ceux-ci sont évalués dans un certain ordre, selon leur priorité d’opération. La fiche d’aide nommée Syntax
(ouverte par la commande help(Syntax)
) détaille l’ordre de préséance des différents opérateurs.
Pour les calculs mathématiques, les priorités d’opération usuelles sont respectées. Par exemple, dans l’expression 2 + 3 * 4
, la multiplication est effectuée avant l’addition.
2 + 3 * 4
## [1] 14
Pour forcer l’évaluation d’un opérateur avant un autre de priorité plus élevée, il faut utiliser des parenthèses, comme dans cet exemple.
2 + 3) * 4 (
## [1] 20
R offre aussi plusieurs fonctions de calculs mathématiques, travaillant de façon vectorielle, dont les suivantes :
sqrt
, abs
, sign
;exp
, log
(= logarithme naturel), log10
, log2
;sin
, cos
, tan
, acos
, asin
, atan
, atan2
;ceiling
, floor
, round
, trunc
, signif
;beta
, gamma
, factorial
, choose
, etc.Ces fonctions font un calcul distinct pour tous les éléments de l’objet fourni en entrée et retournent un résultat de même dimension que l’objet en entrée. Voici quelques exemples.
# Vecteur de données numériques pour les exemples
<- seq(from = -1.25, to = 1.5, by = 0.25)
x x
## [1] -1.25 -1.00 -0.75 -0.50 -0.25 0.00 0.25 0.50 0.75 1.00 1.25 1.50
# Arrondissement régulier au dixième près
round(x, digits = 1)
## [1] -1.2 -1.0 -0.8 -0.5 -0.2 0.0 0.2 0.5 0.8 1.0 1.2 1.5
# Arrondissement à l'entier supérieur
ceiling(x)
## [1] -1 -1 0 0 0 0 1 1 1 1 2 2
# Arrondissement à la partie entière
trunc(x)
## [1] -1 -1 0 0 0 0 0 0 0 1 1 1
Ces fonctions arrivent aussi à effectuer des calculs par élément dans un objet atomique de dimension supérieure à un ou dans un data frame.
# Matrice de données numériques pour les exemples
<- matrix(x, nrow = 2)
x_mat x_mat
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] -1.25 -0.75 -0.25 0.25 0.75 1.25
## [2,] -1.00 -0.50 0.00 0.50 1.00 1.50
# Extraction du signe
sign(x_mat)
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] -1 -1 -1 1 1 1
## [2,] -1 -1 0 1 1 1
Certaines fonctions mathématiques en R effectuent des calculs faisant intervenir plus d’un élément de l’objet donné en entrée, plutôt que d’effectuer un calcul distinct pour chacun des éléments. C’est le cas des fonctions suivantes :
sum
, prod
;cummsum
, cumprod
;diff
.Voici quelques exemples.
# Matrice de données numériques pour les exemples
<- matrix(c(2, 5, 3, 4, 6, 5, 4, 3, 1, 2, 9, 8), nrow = 3, ncol = 4)
mat mat
## [,1] [,2] [,3] [,4]
## [1,] 2 4 4 2
## [2,] 5 6 3 9
## [3,] 3 5 1 8
# Produit de tous les éléments
prod(mat)
## [1] 6220800
# Somme cumulative des éléments (ici 2, 2+5, 2+5+3, 2+5+3+4, ...)
cumsum(mat)
## [1] 2 7 10 14 20 25 29 32 33 35 44 52
diff
Pour une matrice ou un data frame, diff
calcule les différences terme à terme des éléments composant les lignes. Par défaut, la fonction calcule pour chaque ligne, à l’exception de la première, la différence entre la ligne et la ligne au-dessus.
diff(mat)
## [,1] [,2] [,3] [,4]
## [1,] 3 2 -1 7
## [2,] -2 -1 -2 -1
La commande suivante retourne donc le même résultat que la précédente.
-1, ] - mat[-nrow(mat), ] mat[
## [,1] [,2] [,3] [,4]
## [1,] 3 2 -1 7
## [2,] -2 -1 -2 -1
Pour un vecteur, la fonction diff
retourne les différences entre un élément (sauf le premier) et l’élément précédent.
diff(c(2, 5, 3, 4))
## [1] 3 -2 1
La fonction diff
peut calculer des différences entre les éléments séparés par plus d’une position grâce à l’argument lag
, comme dans cet exemple.
diff(c(2, 5, 3, 4), lag = 2)
## [1] 1 -1
# soustractions effectuées : 3-2 et 4-5
Les fonctions R d’opérations sur des ensembles sont les suivantes :
union
: union,intersect
: intersection,setdiff
: différence,setequal
: test d’égalité,is.element
: test d’appartenance.Les quatre premières fonctions permettent de comparer de différentes façons deux ensembles. Pour présenter des exemples d’utilisation des fonctions, créons donc d’abord deux ensembles fictifs. Ceux-ci sont stockés sous forme de vecteurs puisque le langage R de base n’offre pas de structure de données spécifique aux ensembles (contrairement au langage Python par exemple qui propose des sets).
<- c("m", "s", "e", "f", "a")
A <- c("m", "e", "h", "i") B
Rappelons que, par définition, un ensemble mathématique est une collection non ordonnée d’éléments uniques et, en conséquence, ne contient aucun élément dupliqué.
La fonction union
permet d’obtenir l’union des éléments de deux ensembles. Il s’agit d’un nouvel ensemble réunissant tous les éléments présents dans le premier ou le deuxième ensemble. Les éléments qui étaient présents dans les deux ensembles ne sont cependant pas en double dans l’union, car celle-ci est aussi un ensemble dont tous les éléments sont uniques.
union(A, B)
## [1] "m" "s" "e" "f" "a" "h" "i"
Pour arriver au même résultat sans utiliser une fonction d’opération sur des ensembles, nous aurions pu concaténer les vecteurs A
et B
,
c(A, B)
## [1] "m" "s" "e" "f" "a" "m" "e" "h" "i"
puis retirer les doublons du vecteur résultant avec la fonction unique
(que nous reverrons dans les notes sur le prétraitement de données).
unique(c(A, B))
## [1] "m" "s" "e" "f" "a" "h" "i"
La fonction intersect
retourne l’intersection entre deux ensembles. Elle permet donc d’identifier les éléments communs à ces ensembles.
intersect(A, B)
## [1] "m" "e"
La fonction setdiff
permet quant à elle d’identifier les éléments présents dans un premier ensemble sans être présents dans un second ensemble.
setdiff(A, B)
## [1] "s" "f" "a"
Contrairement aux fonctions union
, intersect
et setequal
, l’ordre dans lequel les deux ensembles sont fournis en entrée à la fonction setdiff
a un impact sur le résultat produit. L’exemple précédent a permis d’identifier les éléments appartenant à A
sans appartenir à B
, alors que la commande suivante retourne les éléments appartenant à B
sans appartenir à A
.
setdiff(B, A)
## [1] "h" "i"
La fonction setequal
retourne toujours une seule valeur logique : TRUE
si les deux ensembles fournis en entrée sont égaux, FALSE
sinon.
setequal(A, B)
## [1] FALSE
Pour être égaux, deux ensembles doivent contenir les mêmes éléments, mais pas nécessairement dans le même ordre.
setequal(c(5, 3, 2), c(2, 3, 2, 5, 5))
## [1] TRUE
Notons que les fonctions union
, intersect
, setdiff
et setequal
ne vont pas rechigner si les ensembles qu’elles reçoivent en entrée contiennent des éléments dupliqués. Si c’est le cas, elles vont simplement retirer les doublons avant de procéder à l’opération.
Finalement, R offre le fonction is.element
pour tester la présence d’éléments dans un ensemble. Par exemple, la commande suivante test l’appartenance de "d"
et "e"
à l’ensemble A
:
is.element(el = c("d", "e"), set = A)
## [1] FALSE TRUE
La fonction retourne une valeur logique par élément testé, en respectant l’ordre dans lequel les éléments ont été identifiés via l’argument el
. Ainsi, la sortie précédente indique que "d"
n’est pas présent dans A
, mais que "e"
l’est.
Pour calculer des distances entre des observations numériques, la package stats
offre la fonction dist
. Voici un exemple d’utilisation de cette fonction traitant les célèbres données iris, incluses dans l’installation de base de R dans le data frame nommé iris
(du package datasets
). Prenons uniquement les 5 premières observations du jeu de données et conservons uniquement les variables numériques.
<- iris[1:5, c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")]
iris_ech_num iris_ech_num
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 5.1 3.5 1.4 0.2
## 2 4.9 3.0 1.4 0.2
## 3 4.7 3.2 1.3 0.2
## 4 4.6 3.1 1.5 0.2
## 5 5.0 3.6 1.4 0.2
Calculons les distances euclidiennes entre toutes les paires d’observations dans ce jeu de données, basées sur les 4 variables numériques.
dist(x = iris_ech_num, method = "euclidean", diag = TRUE)
## 1 2 3 4 5
## 1 0.0000000
## 2 0.5385165 0.0000000
## 3 0.5099020 0.3000000 0.0000000
## 4 0.6480741 0.3316625 0.2449490 0.0000000
## 5 0.1414214 0.6082763 0.5099020 0.6480741 0.0000000
La distance euclidienne est un cas particulier de la distance de Minkowski, avec un paramètre \(p = 2\).
dist(x = iris_ech_num, method = "minkowski", p = 2, diag = TRUE)
## 1 2 3 4 5
## 1 0.0000000
## 2 0.5385165 0.0000000
## 3 0.5099020 0.3000000 0.0000000
## 4 0.6480741 0.3316625 0.2449490 0.0000000
## 5 0.1414214 0.6082763 0.5099020 0.6480741 0.0000000
La fonction dist
propose quelques autres distances pour variables numériques (voir la fiche d’aide de la fonction pour la liste complète). Le package stats
offre aussi la fonction mahalanobis
pour calculer des distances de Mahalanobis.
Pour faire le tour des fonctions de mesure de distances incluses dans l’installation R de base, mentionnons aussi la fonction adist
du package utils
qui calcule la distance de Levenshtein entre des chaînes de caractères, par exemple :
adist(x = "Allo", y = "Hello")
## [,1]
## [1,] 2
La distance de Levenshtein, aussi appelée distance minimale d’édition, compte le nombre minimal d’insertions, de retraits et de substitutions à effectuer pour transformer la première chaîne de caractères en la deuxième. Il est possible d’associer un coût différent à chacune de ces opérations. Par défaut, elles ont toutes un coût de 1. La distance de Levenshtein entre "Allo"
et "Hello"
vaut 2 parce que pour transformer "Allo"
en "Hello"
il faut au minimum faire les deux opérations suivantes :
H
au début);"A"
en "e"
).En R, le nombre \(\pi\) est représenté par la constante pi
.
pi
## [1] 3.141593
Inf
est la constante R pour l’infini \(\infty\).
-5 / 0
## [1] -Inf
NaN
est une constante signifiant Not A Number. Cette constante est retournée par R lorsqu’un utilisateur lui demande d’effectuer une opération mathématique impossible, par exemple :
log(-1)
## Warning in log(-1): NaNs produced
## [1] NaN
Rappel : Attention à ne pas confondre la constante NaN
avec la constante NA
qui signifie plutôt Not Available et qui sert à représenter les données manquantes.
Une condition logique est simplement une expression R qui retourne une ou des valeurs logiques (TRUE
ou FALSE
). Ce type d’expression a différentes utilités, par exemple :
if ... else
;Les deux premières utilités potentielles des conditions logiques énumérées ci-dessus requièrent la création d’un vecteur de valeurs logiques de la même longueur que l’objet R sur lequel la condition est testée. Nous avons vu au début de cette fiche des outils pour écrire de telles conditions logiques :
==
, !=
, >
, >=
, <
et <=
;!
(négation), &
(et), |
(ou) et xor
(ou exclusif).Voici des exemples d’écriture de conditions logiques utilisant le vecteur suivant, que nous avons déjà manipulé dans des notes précédentes.
<- c(2, 3, 4, 1, 2, 3, 5, 6, 5, 4) de
Supposons que nous voulions connaître le nombre d’éléments dans ce vecteur numérique dont la valeur est supérieure à 3. La condition logique suivante nous permet d’identifier ces valeurs.
<- de > 3
condition condition
## [1] FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE TRUE TRUE
Compter le nombre de valeurs supérieures à 3 dans de
revient à compter le nombre de TRUE
dans le vecteur précédent. Ce calcul se réalise facilement avec la fonction sum
comme suit.
sum(condition)
## [1] 5
Même si une somme est une opération mathématique sur des valeurs numériques, la commande précédente ne retourne par d’erreur, car R réalise d’abord une conversion implicite de type de données pour transformer les valeurs logiques en nombres (TRUE
devient 1 et FALSE
devient 0), puis effectue la somme.
Le vecteur condition
serait aussi utile pour extraire les éléments de de
ayant une valeur supérieure à 3. Nous savons que l’opérateur d’indiçage [
et la fonction d’extraction subset
acceptent en entrée un vecteur logique. Nous pouvons donc extraire les éléments respectant la condition comme suit.
de[condition]
## [1] 4 5 6 5 4
which
La fonction which
permet de connaître les positions des TRUE
dans le vecteur, comme l’illustre cet exemple :
which(condition)
## [1] 3 7 8 9 10
L’utilisation de which
n’est cependant pas nécessaire lors de l’extraction d’éléments à partir d’un vecteur logique. Par exemple, les commandes de[which(condition)]
et de[condition]
produisent le même résultat, mais la commande sans appel à la fonction which
a l’avantage d’être plus succincte.
La condition précédente était plutôt simple. Une condition plus complexe requiert souvent de combiner des vecteurs logiques à l’aide d’un opérateur logique. Par exemple, l’instruction suivante identifie les éléments du vecteur de
dont la valeur se situe dans l’intervalle \([3, 5]\).
>= 3 & de <= 5 de
## [1] FALSE TRUE TRUE FALSE FALSE TRUE TRUE FALSE TRUE TRUE
L’instruction suivante identifie pour sa part les éléments du vecteur de
égaux à 1, 4 ou 6.
== 1 | de == 4 | de == 6 de
## [1] FALSE FALSE TRUE TRUE FALSE FALSE FALSE TRUE FALSE TRUE
Pour identifier les éléments du vecteur de
non-égaux à 1, 4 ou 6, nous pourrions inverser le vecteur logique précédent avec l’opérateur de négation comme suit.
!(de == 1 | de == 4 | de == 6)
## [1] TRUE TRUE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE
Rappelons qu’en logique mathématique, la négation d’une disjonction est équivalente à la conjonction de négations. L’instruction suivante retourne donc le même résultat que la précédente.
!= 1 & de != 4 & de != 6 de
## [1] TRUE TRUE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE
%in%
de comparaison à plusieurs valeursPour effectuer une comparaison à un ensemble de valeur, telle que le fait l’instruction de == 1 | de == 4 | de == 6
, R offre un opérateur raccourcissant la syntaxe : l’opérateur %in%
. Cet opérateur compare les éléments d’un vecteur (placé avant l’opérateur) aux éléments d’un ensemble présenté sous la forme d’un vecteur (placé après). Il retourne TRUE
pour un élément égal à n’importe lequel des éléments de l’ensemble, FALSE
sinon. L’instruction de == 1 | de == 4 | de == 6
est donc équivalent à la suivante.
%in% c(1, 4, 6) de
## [1] FALSE FALSE TRUE TRUE FALSE FALSE FALSE TRUE FALSE TRUE
Combiné à un opérateur de négation !
, l’opérateur %in%
permet de facilement tester si les valeurs dans un vecteur sont différentes des valeurs d’un ensemble, comme dans cet exemple.
! de %in% c(1, 4, 6)
## [1] TRUE TRUE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE
Notons que tester si un ou des éléments sont égaux à NA
, NaN
, Inf
ou -Inf
, ne se fait pas directement avec l’opérateur ==
comme suit.
c(1, 2, NA, 4, 5) == NA
## [1] NA NA NA NA NA
Il faut plutôt utiliser la fonction is.na
, is.nan
ou is.infinite
.
is.na(c(1, 2, NA, 4, 5))
## [1] FALSE FALSE TRUE FALSE FALSE
La fonction is.finite
retourne pour sa part TRUE
pour les éléments non égaux à NA
, NaN
, Inf
ou -Inf
.
is.finite(c(NA, NaN, Inf, -Inf, 4.5, 3))
## [1] FALSE FALSE FALSE FALSE TRUE TRUE
Lors de l’écriture d’une condition logique, il faut parfois s’assurer de retourner un vecteur logique de longueur 1. C’est le cas lors de l’écriture d’une condition logique dans une structure de contrôle conditionnelle if ... else
(que nous verrons plus loin). La condition dans un if
doit être obligatoirement de longueur 1.
Les opérateurs et fonctions logiques suivants garantissent que le résultat retourné est de longueur 1.
&&
: et,||
: ou,isTRUE
et isFALSE
.Les opérateurs &&
et ||
appliquent les mêmes tables de vérité que les opérateurs &
et |
, mais ils ne travaillent pas de façon vectorielle. Si, par inadvertance, &&
ou ||
reçoit en entrée des vecteurs de longueurs supérieures à 1, il effectue une opération seulement sur les premiers éléments de ces vecteurs, comme dans cet exemple.
== 1 || de == 4 || de == 6 de
## [1] FALSE
Les fonctions isTRUE
et isFALSE
, pour leur part, sont des fonctions raccourcies permettant d’effectuer les tests suivants.
is.logical(x) && length(x) == 1 && !is.na(x) && x # isTRUE
is.logical(x) && length(x) == 1 && !is.na(x) && !x # isFALSE
Elles permettent donc de s’assurer qu’une condition possède toutes les caractéristiques requises pour être fournie à un if
(contenir des données logiques, être de longueur 1 et ne pas prendre la valeur NA
).
all
et any
Les fonctions all
et any
font partie des fonctions R retournant toujours une seule valeur logique. La fonction all
indique si tous les éléments d’un vecteur logique sont TRUE
. Par exemple, pour tester si toutes les valeurs dans le vecteur de
sont entières au sens mathématique, nous pourrions utiliser la commande suivante.
all(de %% 1 == 0)
## [1] TRUE
La fonction any
indique pour sa part si au moins un élément d’un vecteur logique est TRUE
. Nous pourrions par exemple vérifier si le vecteur de
comporte des valeurs négatives comme suit.
any(de < 0)
## [1] FALSE
Finalement, les fonctions is.numeric
, is.character
, is.logical
, is.vector
, is.matrix
, is.data.frame
, is.factor
, is.null
, is.function
, etc., testent une condition et retournent toujours un logique de longueur unitaire. Par exemple, testons si le vecteur de
contient bien des données numériques.
is.numeric(de)
## [1] TRUE
Les opérateurs de comparaison vus ci-dessus permettent de comparer les éléments d’objets R. Mais comment comparer des objets entiers? Cela dépend de ce qui doit être comparé.
all(x == y)
TRUE
si toutes les données sont égales,FALSE
sinon,NA
si un des deux objets comparés contient au moins une donnée manquante et que l’argument na.rm
de la fonction all
prend la valeur FALSE
,identical(x, y)
TRUE
si les deux objets comparés sont totalement identiques,FALSE
sinon.all.equal(x, y)
TRUE
en cas d’égalité respectant la tolérance,Voici quelques exemples.
# Objets comparés
<- 1:5
x <- 1:5
y names(x) <- letters[1:5]
str(x)
## Named int [1:5] 1 2 3 4 5
## - attr(*, "names")= chr [1:5] "a" "b" "c" "d" ...
str(y)
## int [1:5] 1 2 3 4 5
# Résultats des différentes comparaisons
all(x == y)
## [1] TRUE
identical(x, y)
## [1] FALSE
all.equal(x, y)
## [1] "names for target but not for current"
# Objets comparés
<- as.double(x)
x str(x)
## num [1:5] 1 2 3 4 5
str(y)
## int [1:5] 1 2 3 4 5
# Résultats des différentes comparaisons
all(x == y)
## [1] TRUE
identical(x, y)
## [1] FALSE
all.equal(x, y)
## [1] TRUE
# Objets comparés
<- 1:5 + 1e-10
y str(x)
## num [1:5] 1 2 3 4 5
str(y)
## num [1:5] 1 2 3 4 5
Bien que les données numériques dans x
et y
ne soient pas tout à fait identiques, elles semblent identiques à l’affichage de x
et y
.
# Résultats des différentes comparaisons
all(x == y)
## [1] FALSE
identical(x, y)
## [1] FALSE
all.equal(x, y)
## [1] TRUE
Rappel : Il est possible de contrôler le nombre de chiffres composant un nombre affiché dans la console R avec l’option digits
de la session R.
<- options()
optionsDefaut options(digits = 11)
y
## [1] 1.0000000001 2.0000000001 3.0000000001 4.0000000001 5.0000000001
options(digits = optionsDefaut$digits)
Voici des informations concernant trois sujets mathématiques plus poussés. Cette matière ne sera pas évaluée dans le cadre du cours, car certains étudiants n’ont pas les connaissances préalables pour facilement la comprendre. Il est cependant fort probable que certaines des informations présentées ci-dessous soient un jour utiles aux étudiants gradués en statistique. L’implémentation de méthodes statistiques fait souvent intervenir ces types de calculs.
Il existe plusieurs fonctions en R pour faire de l’algèbre linéaire.
%*%
;t
;solve
(en fait solve
résout A %*% x = B
, mais par défaut B
est la matrice identité);crossprod
;outer
, %o%
;kronecker
, %x%
;diag
;det
;eigen
;svd
, qr
, chol
.Faisons quelques exemples pour illustrer certaines de ces fonctions.
%*%
L’opérateur usuel de multiplication effectue une multiplication terme à terme entre deux matrices.
<- matrix(1:6, nrow = 3, ncol = 2)
A A
## [,1] [,2]
## [1,] 1 4
## [2,] 2 5
## [3,] 3 6
<- matrix(6:1, nrow = 3, ncol = 2)
B B
## [,1] [,2]
## [1,] 6 3
## [2,] 5 2
## [3,] 4 1
*B A
## [,1] [,2]
## [1,] 6 12
## [2,] 10 10
## [3,] 12 6
Pour effectuer une multiplication matricielle, il faut utiliser l’opérateur %*%
. Les dimensions des matrices doivent évidemment concorder.
%*% B A
## Error in A %*% B: non-conformable arguments
<- matrix(c(5, 2, 3, 7), nrow = 2, ncol = 2)
C C
## [,1] [,2]
## [1,] 5 3
## [2,] 2 7
%*% C A
## [,1] [,2]
## [1,] 13 31
## [2,] 20 41
## [3,] 27 51
solve
L’inverse d’une matrice s’obtient avec la fonction solve
.
solve(C)
## [,1] [,2]
## [1,] 0.24137931 -0.1034483
## [2,] -0.06896552 0.1724138
crossprod
La fonction crossprod
sert à calculer \(A^T B\) ou \(A^T A\).
crossprod(A, B)
## [,1] [,2]
## [1,] 28 10
## [2,] 73 28
# équivalent à
t(A) %*% B
## [,1] [,2]
## [1,] 28 10
## [2,] 73 28
Parfois, nous avons besoin d’effectuer une opération en prenant toutes les paires de termes possibles entre deux vecteurs ou matrices. C’est ce que font les produits dyadique (outer product) (opérateur %o%
) et de Kronecker (opérateur %x%
). Cependant, ils n’assemblent pas les résultats de la même façon. Voici des exemples avec des vecteurs.
1:3 %o% 4:5
## [,1] [,2]
## [1,] 4 5
## [2,] 8 10
## [3,] 12 15
1:3 %x% 4:5
## [1] 4 5 8 10 12 15
Les deux commandes ont permis le calcul des mêmes 6 produits (\(1 \times 4 = 4\), \(2 \times 4 = 8\), \(3 \times 4 = 12\), \(1 \times 5 = 5\), \(2 \times 5 = 10\) et \(3 \times 5 = 15\)). Cependant, l’opérateur %o%
a rassemblé les produits dans une matrice de dimension 3 par 2, et l’opérateur %x%
dans un vecteur de longueur \(3 \times 2 = 6\).
Avec deux matrices en entrée, le résultat de A %o% B
est un array à 4 dimensions dont les tailles sont, dans l’ordre, nrow(A)
, ncol(A)
, nrow(B)
et ncol(B)
. Le résultat de A %x% B
est pour sa part une matrice à 2 dimensions comprenant nrow(A)*nrow(B)
lignes et ncol(A)*ncol(B)
colonnes.
Voici des exemples.
<- matrix(12:1, nrow = 3, ncol = 4)
A A
## [,1] [,2] [,3] [,4]
## [1,] 12 9 6 3
## [2,] 11 8 5 2
## [3,] 10 7 4 1
<- matrix(c(1,2), nrow = 2, ncol = 1)
B B
## [,1]
## [1,] 1
## [2,] 2
%o% B A
## , , 1, 1
##
## [,1] [,2] [,3] [,4]
## [1,] 12 9 6 3
## [2,] 11 8 5 2
## [3,] 10 7 4 1
##
## , , 2, 1
##
## [,1] [,2] [,3] [,4]
## [1,] 24 18 12 6
## [2,] 22 16 10 4
## [3,] 20 14 8 2
%x% B A
## [,1] [,2] [,3] [,4]
## [1,] 12 9 6 3
## [2,] 24 18 12 6
## [3,] 11 8 5 2
## [4,] 22 16 10 4
## [5,] 10 7 4 1
## [6,] 20 14 8 2
Les deux opérations se généralisent à l’emploi d’un autre opérateur que le produit, grâce aux fonctions outer
et kronecker
.
outer(1:3, 4:5, FUN = '+')
## [,1] [,2]
## [1,] 5 6
## [2,] 6 7
## [3,] 7 8
kronecker(1:3, 4:5, FUN = '+')
## [1] 5 6 6 7 7 8
diag
Finalement, la fonction diag
a plusieurs utilités. Selon le type de l’objet qu’elle reçoit comme premier argument, elle permet de :
C
## [,1] [,2]
## [1,] 5 3
## [2,] 2 7
diag(C)
## [1] 5 7
diag(1:3)
## [,1] [,2] [,3]
## [1,] 1 0 0
## [2,] 0 2 0
## [3,] 0 0 3
diag(3)
## [,1] [,2] [,3]
## [1,] 1 0 0
## [2,] 0 1 0
## [3,] 0 0 1
(Ce qui est offert en R dans ce domaine n’est pas très performant ni facile d’utilisation.)
D
, deriv
et deriv3
Tout comme les logiciels Maple ou Mathematica, R peut faire du calcul symbolique de dérivées. Cependant, il est loin d’être le meilleur outil pour ces tâches. Pour illustrer les capacités (limitées) de R dans ce domaine, tentons d’abord de calculer la dérivée suivante :
\(\frac{d}{dx}( log(x) + sin(x) ).\)
<- deriv(expr = ~ log(x) + sin(x), namevec = "x")
df df
## expression({
## .value <- log(x) + sin(x)
## .grad <- array(0, c(length(.value), 1L), list(NULL, c("x")))
## .grad[, "x"] <- 1/x + cos(x)
## attr(.value, "gradient") <- .grad
## .value
## })
L’objet df
est particulier. Il s’agit d’une expression. La ligne .grad[, "x"] <- 1/x + cos(x)
permet de constater que R a bien trouvé que la dérivée symbolique de \(log(x) + sin(x)\) est \(1/x + cos(x)\). Nous pouvons maintenant utiliser df
pour calculer cette dérivée en certains points. Étant donné que nous avons nommé x
la variable dans la fonction à dériver, il faut d’abord créer un objet nommé x
contenant les valeurs en lesquelles nous souhaitons calculer la dérivée.
<- 2:5 x
Ensuite, nous soumettons la commande suivante pour obtenir le résultat recherché.
eval(df)
## [1] 1.6024446 1.2397323 0.6294919 0.6505136
## attr(,"gradient")
## x
## [1,] 0.08385316
## [2,] -0.65665916
## [3,] -0.40364362
## [4,] 0.48366219
Cette sortie contient les valeurs de la fonction d’origine aux points d’intérêt,
log(x) + sin(x)
## [1] 1.6024446 1.2397323 0.6294919 0.6505136
suivies des valeurs de la dérivée de la fonction en ces points.
1/x + cos(x)
## [1] 0.08385316 -0.65665916 -0.40364362 0.48366219
Ainsi, R peut faire du calcul symbolique de dérivée, mais il n’offre pas une façon très conviviale de le faire. Plus d’information peut être trouvée dans la fiche d’aide des fonctions D
, deriv
et deriv3
. Le R de base n’offre pas de fonctions pour le calcul symbolique d’intégrales. Cependant, le package Ryacas
en offre : https://CRAN.R-project.org/package=Ryacas
numericDeriv
Le calcul de dérivées numériques est un peu plus simple. Par exemple, dérivons la fonction de répartition d’une loi normale standard en quelques points avec la fonction numericDeriv
. Cette fonction de répartition est implémentée dans la fonction R pnorm
, qui sera vue dans les notes sur les calculs statistiques.
# Points en lesquels nous allons dériver
<- as.double(-3:3)
x # Valeur de la fonction en ces points
pnorm(x)
## [1] 0.001349898 0.022750132 0.158655254 0.500000000 0.841344746 0.977249868 0.998650102
# Calcul de la dérivée en ces points
numericDeriv(expr = quote(pnorm(x)), theta = "x")
## [1] 0.001349898 0.022750132 0.158655254 0.500000000 0.841344746 0.977249868 0.998650102
## attr(,"gradient")
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] 0.004431849 0.00000000 0.0000000 0.0000000 0.0000000 0.00000000 0.000000000
## [2,] 0.000000000 0.05399097 0.0000000 0.0000000 0.0000000 0.00000000 0.000000000
## [3,] 0.000000000 0.00000000 0.2419707 0.0000000 0.0000000 0.00000000 0.000000000
## [4,] 0.000000000 0.00000000 0.0000000 0.3989423 0.0000000 0.00000000 0.000000000
## [5,] 0.000000000 0.00000000 0.0000000 0.0000000 0.2419707 0.00000000 0.000000000
## [6,] 0.000000000 0.00000000 0.0000000 0.0000000 0.0000000 0.05399096 0.000000000
## [7,] 0.000000000 0.00000000 0.0000000 0.0000000 0.0000000 0.00000000 0.004431849
Nous arrivons au bon résultat, soit la fonction de densité de loi normale standard aux mêmes points. Cette fonction de densité est implémentée dans la fonction R dnorm
, qui sera aussi vue dans les notes sur les calculs statistiques.
dnorm(x)
## [1] 0.004431848 0.053990967 0.241970725 0.398942280 0.241970725 0.053990967 0.004431848
L’appel de la fonction numericDeriv
n’est pas standard. Il fait intervenir une expression R à créer avec la fonction quote
.
Nous pourrions aussi programmer à la main une version simpliste de la dérivation numérique comme suit :
<- .000001
delta pnorm(x + delta) - pnorm(x - delta)) / (2 * delta) (
## [1] 0.004431848 0.053990967 0.241970724 0.398942280 0.241970725 0.053990967 0.004431848
integrate
Effectuons maintenant l’opération inverse : intégrons la fonction de densité de la loi normale standard avec la fonction integrate
.
integrate(f = dnorm, lower = -Inf, upper = 1)
## 0.8413448 with absolute error < 1.5e-05
Nous arrivons au bon résultat, soit la fonction de répartition de loi normale standard au point 1
pnorm(1)
## [1] 0.8413447
Remarque : La fonction integrate
ne travaille pas de façon vectorielle. Elle ne peut pas calculer des intégrales numériques pour plusieurs intervalles en un seul appel de la fonction.
En mathématiques, l’optimisation consiste à trouver en quel(s) point(s) une fonction mathématique atteint sa valeur maximale ou minimale. En statistique, ce problème est souvent abordé en ces termes : trouver les valeurs des paramètres pour lesquels une fonction atteint son maximum ou son minimum.
Parfois, il est possible de trouver une solution algébrique à ce problème à l’aide du calcul différentiel et intégral. Par contre, il arrive qu’il soit trop difficile, voire impossible, de dériver la fonction en question. L’optimisation numérique est une bonne solution dans un tel cas.
Fonctions R utiles en optimisation numérique :
optimize
,nlm
, optim
,constrOptim
.Exemple d’optimisation d’une fonction à une variable en R : trouvons en quel point la fonction de densité de la loi normale atteint son maximum. La théorie nous dit que ce maximum est atteint en la valeur de l’espérance de la loi. Voyons si l’optimisation numérique saura retourner le bon résultat.
curve(
expr = dnorm(x, mean = 3), from = -3, to = 10,
main = "Maximum de la densité normale", ylab = "densité N(3,1)"
)abline(v = 3, lty = 2, col = "blue")
optimize(f = dnorm, interval = c(-3, 10), mean = 3, maximum = TRUE)
## $maximum
## [1] 3
##
## $objective
## [1] 0.3989423
Oui, pour une loi normale d’espérance 3 et de variance 1, nous arrivons bien numériquement au résultat que le maximum de la densité est atteint en la valeur 3. La fonction optimize
nous dit aussi que ce maximum vaut :
dnorm(3, mean = 3)
## [1] 0.3989423
Les fonctions nlm
, optim
et constrOptim
utilisent des algorithmes itératifs. Elles ont besoin de valeurs initiales pour les paramètres (argument par
à fournir obligatoirement). À chaque itération de l’algorithme, elles modifient ces valeurs en tentant de se diriger vers l’optimum de la fonction. Elles peuvent :
Il faut être prudent lors de leur utilisation. Par exemple, optim
est sensible au choix de plusieurs arguments, notamment :
Ces fonctions sont tout de même très utiles pour effectuer une optimisation lorsque celle-ci est difficile ou impossible à réaliser algébriquement.
Voici un exemple d’optimisation d’une fonction à plusieurs variables. La fonction lm
minimise le critère des moindres carrés, en implémentant des formules algébriques. Les estimations des paramètres du modèle linéaire que lm
retourne sont les points en lesquelles la fonction des moindres carrés est minimisée. Tentons de minimiser cette fonction de façon numérique. Pour ce faire, nous avons d’abord besoin d’une fonction qui calcule le critère des moindres carrés et qui prend comme premier argument les paramètres du modèle. Nous n’avons pas encore vu dans le cours comment créer des fonctions, mais je me permets tout de même ici d’en créer une, pour illustrer l’optimisation numérique. La syntaxe pour créer des fonctions R sera vue au prochain cours.
Le critère des moindres carrés est calculé en sommant les différences au carré entre les valeurs observées d’une variable et les valeurs prédites par le modèle. Pour un modèle de régression linéaire, la fonction suivante calcule de façon matricielle la valeur du critère.
<- function(beta, y, X) {
moindresCarres as.vector(crossprod(y - X %*% matrix(beta, ncol = 1)))
}
Le vecteur y
doit contenir les valeurs observées de la variable réponse et la matrice X
est la matrice de design du modèle. Cette dernière contient les observations des variables explicatives pour les termes présents dans le modèle. Le vecteur y
et la matrice X
sont des composantes du modèle supposées connues ici. C’est le vecteur de paramètre beta
que nous cherchons à estimer. Nous allons utiliser les données du jeu de données cars
dans cet exemple.
Voyons d’abord le résultat obtenu avec la fonction lm
pour un modèle quadratique.
<- lm(dist ~ speed + I(speed^2), data = cars)
reg coefficients(reg)
## (Intercept) speed I(speed^2)
## 2.4701378 0.9132876 0.0999593
Pour retrouver ce résultat par optimisation numérique, il faut d’abord construire le vecteur y
et la matrice X
comme suit.
<- cars$dist
y <- cbind(intercept = 1, cars$speed, cars$speed^2) X
La fonction lm
arrive à la valeur minimale des moindres carrés suivante
moindresCarres(beta = coefficients(reg), y = y, X = X)
## [1] 10824.72
pour les valeurs de paramètres \(\beta\) = (2.4701378, 0.9132876, 0.0999593). Quel résultat est obtenu avec optim
?
<- optim(par = c(3,3,3), fn = moindresCarres, y = y, X = X)
op1 op1
## $par
## [1] 7.2212674 0.2859028 0.1191485
##
## $value
## [1] 10848.71
##
## $counts
## function gradient
## 144 NA
##
## $convergence
## [1] 0
##
## $message
## NULL
L’algorithme a convergé (car il retourne une valeur de 0 pour l’élément convergence
dans la sortie), mais il n’arrive pas au bon résultat.
Solution potentielle : changer d’algorithme d’optimisation.
<- optim(par = c(3,3,3), fn = moindresCarres, y = y, X = X, method = "BFGS")
op2 op2
## $par
## [1] 2.47011519 0.91329056 0.09995889
##
## $value
## [1] 10824.72
##
## $counts
## function gradient
## 43 6
##
## $convergence
## [1] 0
##
## $message
## NULL
Autre solution potentielle : changer les bornes initiales.
<- optim(par = c(2.5,1,0.1), fn = moindresCarres, y = y, X = X)
op3 op3
## $par
## [1] 2.46514183 0.91414522 0.09993205
##
## $value
## [1] 10824.72
##
## $counts
## function gradient
## 150 NA
##
## $convergence
## [1] 0
##
## $message
## NULL
Ici, même en partant de valeurs initiales très proches des paramètres optimaux, l’algorithme d’optimisation utilisé par défaut avec optim
n’arrive pas tout à fait à trouver l’optimum global de la fonction. Seule la solution de changer l’algorithme d’optimisation nous permet d’arriver approximativement au même résultat que celui trouvé algébriquement par lm
.
coefficients(reg)
## (Intercept) speed I(speed^2)
## 2.4701378 0.9132876 0.0999593
$par op2
## [1] 2.47011519 0.91329056 0.09995889
Cet exemple illustre comment la fonction optim
s’emploie. Il faut d’abord lui donner en entrée des valeurs initiales pour les paramètres de la fonction à optimiser (argument par
). Ensuite, il faut lui fournir la fonction R qui implémente la fonction mathématique à optimiser (argument fn
). Cette fonction doit retourner une seule valeur, numérique. De plus, son premier argument doit obligatoirement être le vecteur des paramètres que nous cherchons à estimer par l’optimisation effectuée. Après les arguments par
et fn
, il faut fournir, au besoin, des arguments à passer à la fonction donnée en entrée via l’argument fn
(les arguments y
et X
dans l’exemple). Finalement, nous pouvons configurer le fonctionnement de la fonction optim
en modifiant les valeurs des arguments method
, lower
, upper
, control
, ou hessian
.
Calcul | opère de façon vectorielle | combine, retourne une valeur | combine, retourne un vecteur |
---|---|---|---|
arithmétique | + , - , * , / , ^ , %% , %/% |
sum , prod |
cumsum , cumprod , diff |
comparaison | == , != , > , >= , < , <= |
||
logique | ! , & , | , xor |
&& , || |
sqrt
, abs
, sign
;exp
, log
(= logarithme naturel), log10
, log2
;sin
, cos
, tan
, acos
, asin
, atan
, atan2
;ceiling
, floor
, round
, trunc
, signif
;beta
, gamma
, factorial
, choose
, etc.union
, intersect
, setdiff
, setequal
, is.element
;dist
(distance euclidienne et autres distances), mahalanobis
, adist
(distance de Levenshtein entre des chaînes de caractères);pi
, Inf
, NaN
.Fonctions opérant de façon vectorielle :
==
, !=
, >
, >=
, <
, <=
.!
(négation), &
(et), |
(ou), xor
(ou exclusif).which
;%in%
.is.na
, is.nan
, is.infinite
, is.finite
.Fonctions retournant toujours un logique de longueur 1 :
&&
(et), ||
(ou), isTRUE
, isFALSE
.all
, any
.is.
(numeric
/character
/logical
/vector
/matrix
/array
/list
/data.frame
/factor
/null
/…)all(x == y)
.identical(x, y)
.all.equal(x, y)
.
(Non évalué à partir d’ici.)
%*%
;t
;solve
(en fait solve
résout A %*% x = B
, mais par défaut B
est la matrice identité);crossprod
;outer
, %o%
;kronecker
, %x%
;diag
;det
;eigen
;svd
, qr
, chol
.D
, deriv
et deriv3
.numericDeriv
;integrate
.Définition générale : Trouver en quel(s) point(s) une fonction mathématique atteint sa valeur maximale ou minimale.
Application usuelle en statistique : Trouver les valeurs des paramètres pour lesquels une fonction (ex. log-vraisemblance ou somme des erreurs au carré) atteint son maximum ou son minimum.
optimize
,nlm
, optim
,constrOptim
.Ces fonctions prennent en entrée une fonction R
Les informations présentées dans ces notes proviennent des fiches d’aide du logiciel R :
Pour aller plus loin :