Accéder au contenu principal

Tutoriel sur les formules R

Découvrez la formule R et comment l’utiliser dans les fonctions de modélisation et graphiques de packages renommés comme stats et ggplot2.
Actualisé 19 sept. 2026  · 15 min lire

Explorer avec l’IA

ChatGPTClaudePerplexity

bannière

Quand on y pense, de nombreuses fonctions en R reposent sur les formules : des packages comme ggplot2, stats, lattice et dplyr les utilisent tous ! Parmi les fonctions où vous manipulerez souvent ces objets R : glm(), lm(), facet_wrap(), etc. Mais qu’est-ce qu’une formule, exactement, et pourquoi l’utiliser ?

Structures de données en R

Les formules étant une classe spéciale du langage R, il est utile de revoir rapidement les types et structures de données disponibles dans ce langage.

À retenir : R est un langage orienté objet : tout y est objet, et l’organisation du langage tourne autour de ces objets.

Repartons de la base : en programmation, vous travaillez avec des structures de données qui stockent vos données, et des fonctions qui les traitent. Une structure de données est l’interface vers des données organisées en mémoire. Comme le rappelle la définition du langage R, R ne donne pas un accès direct à la mémoire de l’ordinateur ; il propose plutôt des structures spécialisées auxquelles vous faites référence sous le nom « d’objets ». Chaque structure de données vise à optimiser un aspect du stockage, de l’accès ou du traitement.

Les cinq principales structures de données en R sont :

  • Vecteur atomique,
  • Liste,
  • Matrice,
  • Data frame, et
  • Tableau (array)
# Create variables
a <- c(1,2,3,4,5,6,7,8,9)

b <- list(x = LifeCycleSavings[,1], y = LifeCycleSavings[,2])

Astuce : utilisez la fonction typeof() pour renvoyer le type interne d’un objet R. Le type vous renseigne sur le type (interne à R) ou le mode de stockage de tout objet :

# Retrieve the types of `a` and `b`
typeof(a)

typeof(b)

'double'

'list'

Dans l’exemple ci-dessus où vous avez défini les variables a et b, vous voyez que ces structures contiennent des séquences d’éléments. Ces éléments peuvent être de même type ou de types différents. On retrouve les 6 types atomiques suivants en R :

  • numeric, par exemple 100, 5, 4, inclut les entiers ;
  • character, par exemple "Hello", "True" ou "23.4", des chaînes de caractères ;
  • logical, par exemple TRUE ou FALSE, des « valeurs de vérité » ;
  • raw, par exemple 48 65 6c 6c 6f, des octets ;
  • complex, par exemple 2+5i, des nombres complexes ; et enfin,
  • double, par exemple 3.14, des nombres décimaux.

Presque tous les objets ont des attributs en R. Par exemple, vous savez sans doute que les matrices et les tableaux ne sont que des vecteurs avec l’attribut dim (et éventuellement dimnames) attaché. Les attributs servent notamment à implémenter la structure de classes utilisée en R. En tant que langage orienté objet, le couple classe/méthodes est central. Une classe définit un objet, les informations qu’il contient et la manière de l’utiliser.

Regardez l’exemple suivant :

# Retrieve the classes of `a` and `b`
class(a)

class(b)

'numeric'

'list'

Remarque : si un objet n’a pas d’attribut class, il a une classe implicite « matrix », « array » ou la valeur renvoyée par mode().

Parmi les classes spéciales que vous pouvez croiser : les dates et les formules. Et c’est justement ce dernier point qui nous intéresse aujourd’hui !

Qu’est-ce qu’une formule en R ?

Comme indiqué en introduction, vous avez probablement vu des formules en travaillant avec des packages comme ggplot2 ou des fonctions comme lm(). Comme on les utilise généralement pour exprimer un modèle statistique, il est logique de retrouver ces objets R dans les fonctions de modélisation et certaines fonctions graphiques.

N’est-ce pas ?

Cependant, les formules ne se limitent pas aux modèles. Ce sont des outils généraux et puissants qui permettent de capturer deux choses :

  • Une expression non évaluée, et
  • Le contexte ou l’environnement dans lequel l’expression a été créée.

C’est pourquoi les formules, passées en argument, déclenchent souvent un « comportement spécial » : elles capturent les valeurs sans les évaluer immédiatement, afin que la fonction puisse les interpréter.

En gardant à l’esprit les structures de données, vous pouvez décrire ces objets R comme des objets « language » (langage) ou des expressions non évaluées, de classe « formula », avec un attribut qui stocke l’environnement.

Comme vu précédemment, les objets ont des types internes indiquant leur mode de stockage. Ici, une formule est un objet de type « language ».

Mais qu’est-ce que cela signifie concrètement ?

Vous rencontrez ce type d’objets quand vous manipulez le langage R lui-même. Observez l’exemple suivant :

# Retrieve the object type
typeof(quote(x * 10))

# Retrieve the class
class(quote(x * 10))

'language'

'call'

Dans l’exemple ci-dessus, vous demandez à R de renvoyer le type et la classe de quote(x*10). Le type est 'language' et la class est 'call'.

Ce n’est donc pas une formule, car class() devrait renvoyer 'formula' !

Alors, qu’est-ce qui caractérise une formule ?

Un élément distinctif est l’opérateur tilde ~. Avec cet opérateur, vous dites en quelque sorte : « capture le sens de ce code, sans l’évaluer tout de suite ». D’où l’idée qu’une formule en R agit comme un opérateur de « quotation ».

À quoi ressemble une formule ? Regardez de plus près le code suivant :

# A formula
c <- y ~ x
d <- y ~ x + b

# Double check the class of `c`
class(c)

'formula'

La variable à gauche du tilde (~) est la « variable dépendante », tandis que celles à droite sont les « variables indépendantes », reliées par des +.

Selon le contexte, ces noms varient : variables indépendantes, « prédicteurs », « features », variables de contrôle… Les variables dépendantes deviennent « réponse », « cible », « label », etc.

Remarque : même si la formule d ci-dessus contient plusieurs variables, la structure de base d’une formule est simplement le symbole tilde ~ et au moins une variable du côté droit.

À retenir : les formules sont des objets de langage avec des attributs qui stockent l’environnement :

# Return the type of `d`
typeof(d)

# Retrieve the attributes of `d`
attributes(d)

'language'

$class
[1] "formula"

$.Environment
<environment: R_GlobalEnv>

Comme montré, les variables incluses dans une formule peuvent être, par exemple, des vecteurs. Mais on les récupère souvent depuis un data frame, comme dans l’exemple suivant :

Sepal.Width ~ Petal.Width + log(Petal.Length) + Species

Remarque : les valeurs associées aux symboles de la formule ne sont pas accédées lors de la création de la formule elle-même.

Selon qu’une formule comporte un côté gauche ou non, l’objet sous-jacent varie : ~ x est une formule « unilatérale » (one-sided).

Conséquence : une formule unilatérale a une longueur de 2, et une bilatérale une longueur de 3.

Pas convaincu ? Voyez le code ci-dessous. Vous pouvez accéder aux éléments d’une formule avec les crochets : [[ et ]].

e <- ~ x + y + z
f <- y ~ x + b 

# Return the length of `g`
length(e)
length(f)

# Retrieve the elements at index 1 and 2
e[[1]]
e[[2]]
f[[3]]

2

3

`~`



x + y + z



x + b

Pourquoi utiliser des formules en R ?

Vous l’avez vu, les formules sont des outils puissants et génériques qui permettent de capturer des valeurs sans les évaluer, afin que la fonction les interprète. C’est déjà une raison clé de les utiliser.

Elles servent aussi à exprimer une relation entre variables.

Par exemple, dans la première ligne ci-dessous, vous dites « y est une fonction de x, a et b ». Plus complexe, la seconde ligne signifie « la largeur du sépale dépend de la largeur du pétale, conditionnellement à l’espèce ».

y ~ x + a + b

Sepal.Width ~ Petal.Width | Species
y ~ x + a + b



Sepal.Width ~ Petal.Width | Species

Utiliser les formules en R

Maintenant que vous maîtrisez le « quoi » et le « pourquoi », voyons le « comment ». Dans cette section, vous apprendrez à créer et concaténer des formules de base, puis à construire des formules plus complexes grâce à des opérateurs.

Comment créer une formule en R

Vous savez déjà faire ! Vous en avez vu plusieurs exemples ; récapitulons :

y ~ x
~ x + y + z
g <- y ~ x + b

Exact : il suffit de taper la formule.

Mais vous aurez parfois besoin de créer une formule à partir d’un objet R, comme une chaîne de caractères. Dans ce cas, utilisez formula ou as.formula() :

"y ~ x1 + x2"

h <- as.formula("y ~ x1 + x2")

h <- formula("y ~ x1 + x2")

Simple !

Comment concaténer des formules

Pour « coller » plusieurs formules, deux options : créer des variables pour chaque formule puis utiliser list() :

# Create variables
i <- y ~ x
j <- y ~ x + x1
k <- y ~ x + x1 + x2

# Concatentate
formulae <- list(as.formula(i),as.formula(j),as.formula(k))

# Double check the class of the list elements
class(formulae[[1]])

'formula'

Ou utiliser lapply(), en passant un vecteur de formules en premier argument et as.formula comme fonction à appliquer à chaque élément :

# Join all with `c()`
l <- c(i, j, k)

# Apply `as.formula` to all elements of `f`
lapply(l, as.formula)
[[1]]
y ~ x

[[2]]
y ~ x + x1

[[3]]
y ~ x + x1 + x2

Opérateurs de formules

Avec ces bases, passons aux formules plus complexes. Vous avez vu que la formule se caractérise par le tilde ~ et des variables dépendantes/indépendantes reliées par +.

Mais il y a plus !

Outre +, d’autres symboles ajoutent une sémantique particulière :

  • - pour retirer des termes ;
  • : pour l’interaction ;
  • * pour le croisement (variables + interaction) ;
  • %in% pour l’emboîtement (nesting) ; et
  • ^ pour limiter le croisement au degré indiqué.

Vous verrez des exemples de chacun. Commençons par + et - :

# Plusieurs variables indépendantes
y ~ x1 + x2

# Ignorer des objets dans l’analyse
y ~ x1 - x2

Remarque : : et * sont fréquents en régression pour spécifier des interactions. : ne garde que l’interaction (sans effets principaux), alors que * inclut les deux variables et leur interaction.

Attention ! Selon les opérateurs, des formules différentes peuvent être équivalentes. Par exemple, ces deux écritures donnent la même régression :

y ~ x1 * x2

y ~ x1 + x2 + x1:x2

Pas sûr de voir pourquoi ? Regardez ces extraits :

# Set seed
set.seed(123)

# Data
x = rnorm(5)
x2 = rnorm(5)
y = rnorm(5)

# Model frame
model.frame(y ~ x * x2, data = data.frame(x = x, y = y, x2=x2))
y x x2
1.7150650 -0.56047565 1.2240818
0.4609162 -0.23017749 0.3598138
-1.2650612 1.55870831 0.4007715
-0.6868529 0.07050839 0.1106827
-0.4456620 0.12928774 -0.5558411
model.frame(y ~ x + x2 + x:x2, data = data.frame(x = x, y = y, x2))
y x x2
1.7150650 -0.56047565 1.2240818
0.4609162 -0.23017749 0.3598138
-1.2650612 1.55870831 0.4007715
-0.6868529 0.07050839 0.1106827
-0.4456620 0.12928774 -0.5558411

Pas d’inquiétude si vous ne connaissez pas encore model.frame() ; on y revient plus loin.

Voici un exemple d’emboîtement, qui s’étend à y ~ a + a:b :

y ~ a + b %in% a

Tous ces opérateurs sont utiles, mais que faire pour réaliser une opération arithmétique réelle ? Supposons que vous vouliez inclure x et x^2 dans votre modèle. Vous seriez tenté d’écrire : y ~ x + x^2.

Mais est-ce le bon résultat ? Regardez :

model.frame( y ~ x + x^2, data = data.frame(x = rnorm(5), y = rnorm(5)))
y ~ x + x^2
y x
-0.2053091 1.18231565
-0.3030972 0.04779636
-0.7621604 0.86382418
-0.1377784 -1.18333097
-0.3813125 -1.25247842

Ce n’est pas ce que vous attendiez !

Ici, l’expression arithmétique n’est pas protégée ; R supprime le terme x^2 car il est considéré comme un doublon de x.

Pourquoi ?

x fournit l’effet principal de x, et x^2 produirait l’effet principal et l’interaction d’ordre 2 de x. Au final, seul x est inclus car son effet principal est déjà pris en compte et il n’y a rien à croiser pour obtenir l’interaction d’ordre 2 de x^2.

Pour éviter cela, deux solutions :

  • Calculer et stocker les variables en amont ;
  • Utiliser l’opérateur « tel quel » I() : y ~ x + I(x^2)

Voyez la conséquence de I() :

model.frame( y ~ x + I(x^2), data = data.frame(x = rnorm(5), y = rnorm(5)))
y ~ x + I(x^2)
y x I(x^2)
1.414090 -0.1996230 0.039849....
1.777646 -1.0675904 1.139749....
1.710137 -1.4071841 1.980167....
1.259111 -1.3747289 1.889879....
-1.490866 0.8323668 0.692834....

Ici, vous indiquez à R de calculer x^2 avant d’utiliser la formule. Remarque : vous pouvez aussi utiliser l’opérateur « tel quel » pour mettre à l’échelle une variable ; il suffit d’englober le nom dans I() :

y ~ I(2 * x)

Si tout cela reste abstrait, prenons d’autres cas : en régression polynomiale, vous recourrez à I(). Pour une ANOVA factorielle limitée aux interactions d’ordre depth=2, vous n’en avez pas besoin, car vous souhaitez développer une formule contenant les effets principaux de a, b et c et leurs interactions d’ordre 2 :

# Polynomial Regression
y ~ x + I(x^2) + I(x^3)

# Factorial ANOVA
y ~ (a*b*c)^2

Enfin, un autre opérateur utile avec de multiples variables : .. Dans une formule, il désigne toutes les autres variables de la matrice qui n’ont pas encore été incluses dans le modèle. Pratique quand vous lancez une régression sur une matrice ou un data frame sans tout retaper :

y ~ .

Comment inspecter les formules en R

Une fois la formule créée, vous voudrez sans doute l’inspecter. Voici quelques outils pour explorer ces objets spéciaux.

Remarque : vous avez déjà vu certaines fonctions utiles : attributes(), typeof(), class(), etc.

terms() function

Pour examiner et comparer des formules, utilisez terms() :

m <- formula("y ~ x1 + x2")
terms(m)
y ~ x1 + x2
attr(,"variables")
list(y, x1, x2)
attr(,"factors")
   x1 x2
y   0  0
x1  1  0
x2  0  1
attr(,"term.labels")
[1] "x1" "x2"
attr(,"order")
[1] 1 1
attr(,"intercept")
[1] 1
attr(,"response")
[1] 1
attr(,".Environment")
<environment: R_GlobalEnv>

all.vars

Pour connaître les noms de variables du modèle, utilisez all.vars. La fonction renvoie un vecteur de caractères contenant tous les noms présents dans une formule :

print(all.vars(m))
[1] "y"  "x1" "x2"

update() function

Pour modifier des formules sans les convertir en chaîne, utilisez update() :

update(y ~ x1 + x2, ~. + x3)
y ~ x1 + x2 + x3

Remarque : vous auriez aussi pu convertir en chaîne avec as.character() puis construire des formules via paste(). Par exemple, pour ajouter une variable à droite :

as.formula(paste("y ~ x1 + x2", "x3", sep = "+"))

factors <- c("x2", "x3")
as.formula(paste("y~", paste(factors, collapse="+")))
y ~ x1 + x2 + x3



y ~ x2 + x3

Vous pouvez utiliser les arguments sep ou collapse pour contrôler la séparation des termes.

Mais paste() n’est pas la seule voie : reformulate() fonctionne aussi très bien :

reformulate(termlabels = factors, response = 'y')
y ~ x2 + x3

is.formula()

Vérifiez qu’une variable est bien une formule avec is.formula(). Cette fonction appartient à plyr : chargez-le avant appel !

# Load `plyr`
library(plyr)

# Check `m`
is.formula(m)

TRUE

Quand utiliser des formules

Vous avez vu que les formules R sont des outils génériques, pas limités à la modélisation, et quelques cas d’usage. Approfondissons avec des exemples dans les fonctions de modélisation et graphiques de packages comme lattice et stats, ainsi qu’avec l’évaluation non standard dans dplyr.

Fonctions de modélisation

R excelle en modélisation statistique. Celle-ci formalise mathématiquement une version simplifiée de la réalité et, éventuellement, permet de faire des prédictions. Un modèle statistique représente souvent un processus de génération de données de façon idéalisée. Pour modéliser, vous utilisez des fonctions de modélisation.

Ces fonctions demandent typiquement un objet formula en argument. On y trouve aussi souvent data pour spécifier le data frame à utiliser, subset pour sélectionner les données, etc. Pour connaître les arguments d’une fonction donnée, utilisez help() ou ? dans votre console.

Les fonctions de modélisation renvoient un objet modèle qui contient toutes les informations d’ajustement. Des fonctions génériques comme print(), summary(), plot(), anova(), etc., disposent de méthodes par classe pour renvoyer des informations adaptées.

Sans doute la plus connue : lm(), qui utilise tous les arguments évoqués. lm() ajuste des modèles linéaires : régression, ANOVA simple, ANCOVA. Exemple avec lm() et print() :

lm.m <- lm(Sepal.Width ~ Petal.Width + log(Petal.Length) + Species, 
        data = iris, 
        subset = Sepal.Length > 4.6)

print(lm.m)
Call:
lm(formula = Sepal.Width ~ Petal.Width + log(Petal.Length) + 
    Species, data = iris, subset = Sepal.Length > 4.6)

Coefficients:
      (Intercept)        Petal.Width  log(Petal.Length)  Speciesversicolor  
           3.1531             0.6620             0.4612            -1.9265  
 Speciesvirginica  
          -2.3088   

lm() utilise d’abord la formule et l’environnement approprié pour traduire les relations en un data frame contenant les données.

Il existe aussi des méthodes model.frame() (vous en avez vu une) pour récupérer ou recréer le « model frame » à partir de l’objet ajusté, sans autres arguments. Cela permet d’obtenir des colonnes correspondant à des arguments de l’appel initial autres que formula, subset et weights ; par exemple, la méthode glm() gère offset, etastart et mustart.

Ci-dessous, on récupère un data frame de l’objet ajusté via model.frame() ; notez la légère différence de subset par rapport à l’exemple précédent.

stats::model.frame(formula = Sepal.Width ~ Petal.Width + log(Petal.Length) + Species, 
                   data = iris, 
                   subset = Sepal.Length > 6.9, 
                   drop.unused.levels = TRUE)
  Sepal.Width Petal.Width log(Petal.Length) Species
51 3.2 1.4 1.547563 versicolor
103 3.0 2.1 1.774952 virginica
106 3.0 2.1 1.887070 virginica
108 2.9 1.8 1.840550 virginica
110 3.6 2.5 1.808289 virginica
118 3.8 2.2 1.902108 virginica
119 2.6 2.3 1.931521 virginica
123 2.8 2.0 1.902108 virginica
126 3.2 1.8 1.791759 virginica
130 3.0 1.6 1.757858 virginica
131 2.8 1.9 1.808289 virginica
132 3.8 2.0 1.856298 virginica
136 3.0 2.3 1.808289 virginica

Astuce : d’autres fonctions du package stats exploitent les formules, comme aggregate().

Pour des modèles linéaires à effets mixtes, qui modélisent des effets aléatoires (variations dues, par exemple, aux observateurs), utilisez le package nlme et la fonction lme(). Là encore, formula est le premier argument, suivi de data.

# Load packages
library(MASS)
library(nlme)

# Get some data 
data(oats)

# Adjust the data names and columns
names(oats) = c('block', 'variety', 'nitrogen', 'yield')
oats$mainplot = oats$variety
oats$subplot = oats$nitrogen

# Fit a non-linear mixed-effects model 
nlme.m = lme(yield ~ variety*nitrogen,
             random = ~ 1|block/mainplot,
             data = oats)

# Retrieve a summary
summary(nlme.m)
Linear mixed-effects model fit by REML
 Data: oats 
       AIC      BIC    logLik
  559.0285 590.4437 -264.5143

Random effects:
 Formula: ~1 | block
        (Intercept)
StdDev:    14.64496

 Formula: ~1 | mainplot %in% block
        (Intercept) Residual
StdDev:    10.29863 13.30727

Fixed effects: yield ~ variety * nitrogen 
                                    Value Std.Error DF   t-value p-value
(Intercept)                      80.00000  9.106958 45  8.784492  0.0000
varietyMarvellous                 6.66667  9.715028 10  0.686222  0.5082
varietyVictory                   -8.50000  9.715028 10 -0.874933  0.4021
nitrogen0.2cwt                   18.50000  7.682957 45  2.407927  0.0202
nitrogen0.4cwt                   34.66667  7.682957 45  4.512152  0.0000
nitrogen0.6cwt                   44.83333  7.682957 45  5.835427  0.0000
varietyMarvellous:nitrogen0.2cwt  3.33333 10.865342 45  0.306786  0.7604
varietyVictory:nitrogen0.2cwt    -0.33333 10.865342 45 -0.030679  0.9757
varietyMarvellous:nitrogen0.4cwt -4.16667 10.865342 45 -0.383482  0.7032
varietyVictory:nitrogen0.4cwt     4.66667 10.865342 45  0.429500  0.6696
varietyMarvellous:nitrogen0.6cwt -4.66667 10.865342 45 -0.429500  0.6696
varietyVictory:nitrogen0.6cwt     2.16667 10.865342 45  0.199411  0.8428
 Correlation: 
                                 (Intr) vrtyMr vrtyVc ntr0.2 ntr0.4 ntr0.6
varietyMarvellous                -0.533                                   
varietyVictory                   -0.533  0.500                            
nitrogen0.2cwt                   -0.422  0.395  0.395                     
nitrogen0.4cwt                   -0.422  0.395  0.395  0.500              
nitrogen0.6cwt                   -0.422  0.395  0.395  0.500  0.500       
varietyMarvellous:nitrogen0.2cwt  0.298 -0.559 -0.280 -0.707 -0.354 -0.354
varietyVictory:nitrogen0.2cwt     0.298 -0.280 -0.559 -0.707 -0.354 -0.354
varietyMarvellous:nitrogen0.4cwt  0.298 -0.559 -0.280 -0.354 -0.707 -0.354
varietyVictory:nitrogen0.4cwt     0.298 -0.280 -0.559 -0.354 -0.707 -0.354
varietyMarvellous:nitrogen0.6cwt  0.298 -0.559 -0.280 -0.354 -0.354 -0.707
varietyVictory:nitrogen0.6cwt     0.298 -0.280 -0.559 -0.354 -0.354 -0.707
                                 vM:0.2 vV:0.2 vM:0.4 vV:0.4 vM:0.6
varietyMarvellous                                                  
varietyVictory                                                     
nitrogen0.2cwt                                                     
nitrogen0.4cwt                                                     
nitrogen0.6cwt                                                     
varietyMarvellous:nitrogen0.2cwt                                   
varietyVictory:nitrogen0.2cwt     0.500                            
varietyMarvellous:nitrogen0.4cwt  0.500  0.250                     
varietyVictory:nitrogen0.4cwt     0.250  0.500  0.500              
varietyMarvellous:nitrogen0.6cwt  0.500  0.250  0.500  0.250       
varietyVictory:nitrogen0.6cwt     0.250  0.500  0.250  0.500  0.500

Standardized Within-Group Residuals:
        Min          Q1         Med          Q3         Max 
-1.81300898 -0.56144838  0.01758044  0.63864476  1.57034166 

Number of Observations: 72
Number of Groups: 
              block mainplot %in% block 
                  6                  18  

Remarque : outre nlme, d’autres packages comme lme4 sont dédiés aux modèles linéaires et généralisés à effets mixtes.

Autre exemple avec nls() pour des modèles non linéaires :

# Set seed
set.seed(20160227)

# Data
x <- seq(0,50,1)
y <- ((runif(1,10,20)*x)/(runif(1,0,10)+x))+rnorm(51,0,1)

# Non-linear model
nls.m <- nls(y ~ a*x/(b+x), 
             start=c(a=4, b=1))

Enfin, pour les modèles linéaires généralisés (GLM), utilisez glm(). Là encore, formula et data sont au rendez-vous :

# Load package
library(MPDiR)

# Get the data
data(Chromatic)

# Model
glm.m <- glm(Thresh ~ Axis:(I(Age^-1) + Age),
             family = Gamma(link = "identity"), 
             data = Chromatic)

# Get back a summary
summary(glm.m)
Call:
glm(formula = Thresh ~ Axis:(I(Age^-1) + Age), family = Gamma(link = "identity"), 
    data = Chromatic)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.2160  -0.3728  -0.0805   0.2311   1.2932  

Coefficients:
                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)          3.282e-04  9.965e-05   3.294  0.00106 ** 
AxisDeutan:I(Age^-1) 7.803e-03  3.686e-04  21.172  < 2e-16 ***
AxisProtan:I(Age^-1) 8.271e-03  3.863e-04  21.410  < 2e-16 ***
AxisTritan:I(Age^-1) 1.166e-02  5.284e-04  22.065  < 2e-16 ***
AxisDeutan:Age       1.521e-05  3.418e-06   4.450 1.06e-05 ***
AxisProtan:Age       1.540e-05  3.434e-06   4.484 9.10e-06 ***
AxisTritan:Age       4.812e-05  5.838e-06   8.241 1.48e-15 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for Gamma family taken to be 0.2054848)

    Null deviance: 543.35  on 510  degrees of freedom
Residual deviance: 100.40  on 504  degrees of freedom
AIC: -4777.6

Number of Fisher Scoring iterations: 6

Avant de passer au graphique, un point utile : quand vous utilisez des formules dans des fonctions comme lm(), une conversion standard formule→fonctions se produit. Pour l’illustrer, revenons à l’exemple vu plus haut :

lm.m <- lm(Sepal.Width ~ Petal.Width + log(Petal.Length) + Species, 
           data = iris, 
           subset = Sepal.Length > 4.6)

Bien que l’objectif soit d’ajuster un modèle linéaire, la formule spécifie le modèle symbolique et génère la matrice de conception (design matrix). Cette matrice (ou matrice X) représente les prédicteurs : lignes = observations, colonnes = attributs.

La méthode « formule » définit ainsi les colonnes à inclure dans la matrice de conception.

Concrètement :

# A formula
y ~ x

# A converted formula
y = a_1 + a_2 * x

Exemple simple : y ~ x devient y = a_1 + a_2 * x.

Pour voir ce que fait R, utilisez model_matrix(). Cette fonction crée la matrice de conception en développant notamment les facteurs en variables indicatrices selon les contrastes, ainsi que les interactions.

N’oubliez pas de passer le data frame df et la formule pour obtenir un tibble décrivant l’équation du modèle :

# Load packages
library(tidyverse)
library(modelr)

# A data frame
df <- tribble(
  ~y, ~x1, ~x2,
  4, 2, 5,
  5, 1, 6
)

# Model matrix
model_matrix(df, y ~ x1)
(Intercept) x1
1 2
1 1

Vous voyez apparaître une colonne (Intercept). C’est le comportement par défaut de R : l’intercepte est une colonne de 1. Pour l’ôter, ajoutez explicitement -1 à la formule :

model_matrix(df, y ~ x1-1)
x1
2
1

Remarque : la matrice de conception s’agrandit naturellement quand vous ajoutez des variables.

model_matrix(df, y ~ x1 + x2)
(Intercept) x1 x2
1 2 5
1 1 6

Fonctions graphiques en R

Autre terrain clé des formules : les fonctions graphiques. Il existe de nombreux packages ; concentrons-nous sur graphics, lattice, ggplot2 et ggformula.

graphics

Le package de base graphics permet de définir un nuage de points ou d’ajouter points, lignes ou texte via une formule. Exemple :

# Get data
data(airquality)

# Plot
plot(Ozone ~ Wind, data = airquality, pch = as.character(Month))

formula R tutorial

Pour en savoir plus, consultez cette page.

lattice

lattice repose sur grid graphics. C’est un package graphique généraliste proposant des alternatives aux fonctions de base : nuages de points avec xyplot(), diagrammes en barres avec barchart(), boîtes à moustaches avec bwplot(), etc.

Astuce : pour en savoir plus sur lattice, suivez le cours DataCamp Data Visualization in R with lattice.

Particularité : il utilise la notation par formule des modèles statistiques pour décrire le graphique désiré (variables à tracer). Il ajoute aussi la barre verticale | pour la variable de conditionnement :

# Load package
library(lattice)

# Plot histogram
histogram(~ Ozone | factor(Month), 
          data = airquality, 
          layout = c(2, 3),
          xlab = "Ozone (ppb)")

R formula tutorial

Remarque : comme pour les fonctions de modélisation, celles de lattice proposent un argument formula et un argument data, comme attendu.

Vous pourriez omettre data, mais il faudrait alors attacher les données :

# Load package
library(lattice)

# Attach data
attach(airquality)

# Plot
histogram(~ Ozone | factor(Month), 
          layout = c(2, 3),
          xlab = "Ozone (ppb)")

ggplot2

Vous pouvez utiliser des formules dans différentes fonctions de ggplot2 :

  • geom_smooth() ou stats_smooth() pour spécifier la formule du lissage ; cela influence la forme de l’ajustement.
  • facet_wrap() pour définir les panneaux d’affichage.
  • facet_grid() pour spécifier lignes et colonnes à représenter, avec ou sans facettage.
# Load package
library(ggplot2)

# Plot
ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  geom_smooth(method = "lm", 
              formula = y ~ splines::bs(x, 3), 
              se = FALSE)

R formula tutorial

Notez que, pour créer cette courbe, la formule utilise x et y, et non les noms effectifs des variables. Ce n’est pas le cas avec facet_wrap() :

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  geom_smooth(span = 0.8) +
  facet_wrap(~drv)

formula in R

Envie d’en savoir plus sur ggplot2 ? Découvrez ce cours ou consultez la documentation.

ggformula

Le package ggformula s’appuie sur ggplot2 mais propose une interface basée sur les formules, proche de lattice. Vous y verrez aussi l’opérateur pipe utilisé pour composer des graphiques complexes à partir de briques simples.

Astuce : pour en savoir plus sur l’opérateur pipe en R, consultez ce tutoriel.

La façon basique de créer un graphique avec ggformula est :

gf_plottype(formula, data = mydata)

Remarque : les fonctions gf_plottype() commencent par gf pour rappeler qu’il s’agit d’interfaces basées sur des formules vers ggplot2 ; g pour ggplot2 et f pour « formula ».

Exemple en R :

# Load package
library(ggformula)

# Plot
gf_point(mpg ~ hp, data = mtcars)

R formula tutorial

Ceci n’est qu’un graphique de base ; le package va beaucoup plus loin : types de glyphes, attributs, graphiques univariés/bivariés, positionnements, etc. La leçon principale : ici, les formules sont l’ingrédient clé pour faire des graphiques.

Pour aller plus loin, lisez la vignette ici ou la page RDocumentation.

dplyr

dplyr illustre l’évaluation non standard (NSE). Autres exemples : library(magrittr) vs library("magrittr") fonctionnent tous deux, même si l’un met des guillemets et l’autre non ! Comparez avec install.packages() :

# This will work
install.packages("magrittr")

# This won't work
install.packages(magrittr)

En R, vous devez en général mettre des guillemets autour des noms. Mais certaines fonctions —comme library()— sont conçues pour fonctionner autrement. Certaines n’offrent même pas d’alternative standard !

Dans dplyr, la plupart des fonctions ont une évaluation standard (SE), mais, pour un usage interactif, elles ont aussi une version NSE qui vous évite des frappes.

(Avouons-le : taper tous ces guillemets peut être fastidieux.)

La plupart des fonctions dplyr utilisent donc la NSE : elles ne suivent pas les règles habituelles. Elles capturent l’expression que vous tapez et l’évaluent à leur façon.

Cela ne veut pas dire qu’il n’existe pas de variante standard. Chaque fonction NSE a une version SE qui réalise le calcul et se termine par _ : select(), select_(), mutate(), mutate_(), etc.

En interactif, ces fonctions sont d’abord évaluées avec le package lazyeval avant d’appeler la version SE. Sous le capot, select() est évalué via lazyeval puis envoyé à select_().

Il existe trois façons de « citer » des variables dans les fonctions SE comprises par dplyr et lazyeval :

  • Formules,
  • quote(), et
  • Chaînes de caractères
# Load `dplyr`
library(dplyr)

# NSE evaluation
select(iris, Sepal.Length, Petal.Length)

# standard evaluation 
select_(iris, ~Sepal.Length)
select_(iris, ~Sepal.Length, ~Petal.Length) #works
select_(iris, quote(Sepal.Length), quote(Petal.Length)) # yes!
select_(iris, "Sepal.Length", "Petal.Length", "Species")

Astuce : pour en savoir plus sur la NSE, lisez le chapitre correspondant dans Advanced R de Hadley Wickham.

Packages autour des formules R

Vous avez vu comment créer et inspecter vos formules avec as.formula, update(), all.vars, etc. Ce sont des manipulations simples. Et pour des manipulations avancées ? Les packages suivants pourraient vous intéresser.

Formula Package

Récemment publié sur CRAN, ce package est idéal pour « passer à la vitesse supérieure ». Il étend la classe de base formula.

Plus précisément, les objets Formula étendent les formules de base : vous pouvez définir des formules acceptant un opérateur supplémentaire | séparant plusieurs parties, ou porter tous les opérateurs (y compris |) à gauche pour gérer des réponses multiples.

Exemples de formules possibles :

  • Formules multi-parties : y ~ x1 + x2 | u1 + u2 + u3 | v1 + v2
  • Formules multi-réponses : y1 + y2 ~ x1 + x2 + x3
  • Réponses multi-parties : y1 | y2 + y3 ~ x, et
  • Combinaisons des trois.
# Load package
library(Formula)

# Create formulas
f1 <- y ~ x1 + x2 | z1 + z2 + z3
F1 <- Formula(f1)

# Retrieve the class of `F1`
class(F1)
  1. 'Formula'
  2. 'formula'

Remarque : dans ce package, as.formula() et is.formula() ont leurs équivalents as.Formula() et is.Formula().

Plus d’infos ici.

formula.tools

Ce package fournit des « utilitaires programmatiques pour manipuler formules, expressions, appels, affectations et autres objets R ». Concrètement : il permet d’accéder et modifier la structure des formules, extraire/remplacer noms et symboles. Écrit par Christopher Brown.

Fonctions utiles :

  • get.vars() : alternative à all.vars(), extrait les noms de variables de divers objets R, en interpolant symboles, etc. vers des noms.
  • invert() : inverse les opérateurs d’un objet (p. ex. une formule).
  • is.one.sided() : pratique pour déterminer si une formule est à un ou deux côtés.

À retenir : une formule est unilatérale si elle ressemble à ~x ; bilatérale si x~y.

  • ...

Encore plus à découvrir !

Bravo ! Vous êtes arrivé au bout de ce tutoriel sur les formules R. Pour aller plus loin, lisez le chapitre dédié aux formules et familles de modèles dans le livre de Hadley Wickham, R for Data Science.

Découvrez aussi le tutoriel DataCamp Bien débuter avec le Tidyverse.

Vous pensez à d’autres cas où utiliser les formules ou à d’autres packages pour les manipuler ? Dites-le-moi sur Twitter : @willems_karlijn.

Sujets
R
Science des données
Visualisation des données

Cours R

Cours

Introduction à R

4 h
3.1M
Maîtrisez les bases de l’analyse de données en R et pratiquez les vecteurs, listes et data frames avec des données réelles.
Afficher les détailsRight Arrow
Commencer Le Cours
Voir plusRight Arrow