QQplots : comment sont ils construits ?

Table des matières

Introduction

Les qqplots sont des graphiques dit “quantile- quantile” qui permettent de comparer visuellement la distribution d’un échantillon avec une distribution théorique (généralement la distribution Normale).

Le principe du QQ plot est de représenter les valeurs observées de l’échantillon sur l’axe des ordonnées, et les quantiles correspondants de la distribution théorique sur l’axe des abscisses.

Si les deux distributions sont similaires, les points devraient être alignés sur une droite diagonale allant du coin inférieur gauche au coin supérieur droit.

Si l’échantillon suit exactement la distribution théorique, les points doivent tomber sur cette ligne.

Si les points s’écartent de cette ligne, cela indique que la distribution de l’échantillon diffère de la distribution théorique.

En voici un exemple, avec la longueur des sépales de l’espèce setosa des données iris (automatiquement présentes dans R), et en utilisant la fonction qqPlot() du package car :

library(dplyr)
# preparation des données setosa
setosa <- iris %>% 
    filter(Species=="setosa")

library(car)
qqPlot(setosa$Sepal.Length)
 
qqplot qur les données Sepal.Length des données iris avec la fonction qqPlot du package car

Sur le principe, les QQ plots ont l’air assez simples, mais lorsqu’on les regarde de plus près, les premières interrogations arrivent assez vite. Par exemple : 

  • On nous dit que c’est un quantile quantile plot, alors que seul l’axe des abscisses représente des quantiles
  • les deux axes ne sont pas à la même échelle puisque l’axe des ordonnées portent les données observées
  • comment la droite fait le lien entre ces deux axes ?

Pour essayer de poser tout cela à plat, nous allons réaliser un qqplot en pas à pas

Les étapes du qqplot en pas à pas

Tracer les points du qqplot

Lorsque le qqplot est employé pour comparer la distribution d’un échantillon à une distribution Normale (Gaussienne), voici les étapes qui sont réalisées :

  1. les données observées sont ordonnées de la plus petite à la plus grande

  2. calcul des rangs de chaque valeur (puisque les données sont ordonnées, le rang vont de 1 à n (nombre total d’observations). Le rang est nécessaire pour l’étape suivante.

  3. calcul de la probabilité cumulée pour chaque valeur observée dans l’échantillon. Il s’agit de la probabilité d’observer une valeur inférieure ou égale à la valeur observée. Ces probabilités renseignent sur la position de chaque valeur dans l’échantillon. Par ex si p=0.5, la valeur considérée est la médiane. Ces probabilités sont nécessaires pour faire le lien avec une distribution Normale. Il existe plusieurs formules pour le faire, les plus courantes sont :

    • La formule originale de Fréchet et Kolmogorov : Pi = (i-0.5)/n, où Pi est la probabilité cumulée associée au i-ème quantile empirique, i est le rang de l’observation et n est le nombre total d’observations. Cette formule a l’avantage d’être symétrique par rapport à la médiane et de donner des résultats similaires à la méthode des moments pour les distributions normales.
    • La formule de Weibull : Pi = i/(n+1), où Pi est la probabilité cumulée associée au i-ème quantile empirique, i est le rang de l’observation et n est le nombre total d’observations. Cette formule est souvent utilisée en fiabilité et en sciences de l’ingénieur.
  4. calcul des quantiles normaux correspondant aux probabilités empiriques. Il s’agit de calculer les valeurs qui seraient observées si l’échantillon suivait une loi normale
  5. en réalité ce sont les quantiles normaux standardisés qui sont calculés, c’est-à-dire les valeurs qui seraient observées si l’échantillon suivait une loi normale de moyenne =0 et d’écart type = 1.

# simulation de données
set.seed(123) # Pour reproduire les mêmes résultats
valeurs <- round(rgamma(20, shape = 3, rate = 0.5),2)
valeurs
##  [1]  3.38  9.47  1.08  5.42 11.89  6.56  1.80  1.03  9.62  6.20  6.35  5.36
## [13]  3.40  9.93  7.95  4.83  3.62  4.34  2.28  4.73

# étape 1 : ordonner
valeurs <- sort(valeurs)
valeurs
##  [1]  1.03  1.08  1.80  2.28  3.38  3.40  3.62  4.34  4.73  4.83  5.36  5.42
## [13]  6.20  6.35  6.56  7.95  9.47  9.62  9.93 11.89

# étape 2: calcul des rangs
r <- rank(valeurs)
r
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20

# étape 3 : calcul des proba cumulées empiriques
p = (r-0.5)/length(valeurs)
p
##  [1] 0.025 0.075 0.125 0.175 0.225 0.275 0.325 0.375 0.425 0.475 0.525 0.575
## [13] 0.625 0.675 0.725 0.775 0.825 0.875 0.925 0.975

#étape 4 : calcul des quantiles normaux correspondant aux proba empiriques : valeurs qui seraient observées 
# si les données suivaient une loi normales
quantiles_normaux = round(qnorm(p, mean=mean(valeurs), sd=sd(valeurs)),1)
quantiles_normaux
##  [1] -0.6  1.0  1.9  2.6  3.1  3.6  4.1  4.5  4.9  5.3  5.7  6.0  6.4  6.9  7.3
## [16]  7.8  8.3  9.0  9.9 11.5

#étape 5 : calcule des quantiles normaux centrés réduits correspondant aux proba empiriques
quantiles_normaux_Std = round(qnorm(p, mean=0, sd=1),1)
quantiles_normaux_Std
##  [1] -2.0 -1.4 -1.2 -0.9 -0.8 -0.6 -0.5 -0.3 -0.2 -0.1  0.1  0.2  0.3  0.5  0.6
## [16]  0.8  0.9  1.2  1.4  2.0
 

Remarque : les valeurs observées sont  aussi être appelé des quantiles empiriques (et nous avons cherché à quelle probabilité ils correspondent). C’est de là que vient le terme “quantile quantile plot“, car nous avons d’un côté les quantiles empiriques (en y), et de l’autre, les quantiles standardisés si les données suivaient une loi Normale.

Nous avons à présent toutes les variables nécessaires pour tracer le qqplot : 

# assemblage dans un data frame
mydata <- data.frame(valeurs,r, p, quantiles_normaux, quantiles_normaux_Std)

library(ggplot2)
ggplot(mydata, aes(x=quantiles_normaux_Std, y=valeurs))+
    geom_point() 
Tracé des points du qqplot

Vérifions avec la fonction qqPlot()

qqPlot(mydata$valeurs) 
qqplot obtenu avec la fonction qqPlot du package car

Nos points semblent bien placés ! Jusque là, tout va bien  ! 😎

 

Tracer la droite du qqplot

C’est là que les chosent se compliquent pour de vrai 😵‍💫.

En première approche, et parce que les quantiles normaux sont standardisés (c’est-à-dire centrés-réduits) on pourrait penser que :

  • l’intercept est estimé par la moyenne des valeurs 
  • la pente est estimée par l’écart type des valeurs

Faisons un essai :

ggplot(mydata, aes(x=quantiles_normaux_Std, y=valeurs))+
    geom_point()+
    geom_abline(intercept=mean(mydata$valeurs), slope=sd(mydata$valeurs))+
        ggtitle ("1ere test de tracé de la droite") 
Mauvaise approximation de la droite

La droite obtenue ne correspond pas à celle du qqplot réalisé avec la fonction qqPlot du package car.😰 

En lisant un post de Tristan Mahr (https://www.tjmahr.com/quantile-quantile-plots-from-scratch/) j’ai appris que c’est une approche robuste qui est employée pour tracer la droite. Et que l’on peut : 

  • approximer l’intercept par la médiane des valeurs, c’est-à-dire ici 5.095
  • approximer la pente par l’intervalle interquartile des valeurs /1.349, c’est-à-dire, ici, 2.66
my.intercept <- median(mydata$valeurs)
my.intercept
## [1] 5.095
my.slope <- IQR(mydata$valeurs)/1.349
my.slope 
## [1] 2.603781
ggplot(mydata, aes(x=quantiles_normaux_Std, y=valeurs))+
    geom_point()+
    geom_abline(intercept=5.095, slope=2.66)+
    ggtitle ("Tracé robuste de la droite") 

C’est effectivement beaucoup mieux ! 🤩

Pour aller plus loin

Si vous souhaitez en savoir plus sur le tracé de la droite et de son enveloppe, je vous recommande de lire l’article Q-Q Plots and Worm Plots from Scratch, de Tristan Mahr.

Conclusion

Que pensez-vous de cet article ? Est-ce qu’il vous permet de mieux comprendre comment sont construits les qqplots et comment les interpréter  ?

🙏 Dites-le-moi en commentaire 👇👇👇

 

20 réponses

  1. Merci pour cet article clair et utile. J’ai trois questions complémentaires :
    1 – existe-t-il une différence fondamentale entre ce QQ plot et la droite de Henry ?
    2 – existe-t-il une quantité calculable pour déterminer si les points s’ajustent “assez bien” à la droite ? (par exemple en utilisant les pentes et les ordonnées à l’origine des deux droites ?)
    3 – d’où provient la valeur de 1.349 ?

    Merci d’avance !

    1. Bonjour,

      je ne connais pas bien la droite de Henry, je ne l’ai jamais étudié, mais j’ai l’impression que les concepts sont très proches.
      Pour calculer si les points sont ajustés à une droite, on utilise généralement le R2.
      Je ne sais pas d’où vient la valeur 1.349, je n’ai pas creusé davantage le sujet.

      Bonne continuation

  2. Par feignantise, on ne regarde pas souvent le contenu des fonctions… Ce développement est une belle incitation à le faire. J’ignorais l’usage de l’approximation robuste plutôt qu’avec “mean” et “sd”.
    Merci beaucoup donc !

  3. Bonjour,
    Merci comme toujours pour ce tutoriel. Ce site reste comme toujours une véritable mine d’info.

    Par contre dans la dernière partie de code ne doit-on pas plutot avoir (modif sur les valeurs d’argument de geom_abline) :
    ggplot(mydata, aes(x=quantiles_normaux_Std, y=valeurs))+
    geom_point()+
    geom_abline(intercept=5.095, slope=2.603781)+
    ggtitle (“Tracé robuste de la droite”)

    Ce qui semble être le cas du graphique.

Laisser un commentaire

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

Vous souhaitez soutenir mon travail ?​​

Poursuivez votre lecture

Bonjour !

vous venez souvent ?

Identifiez-vous pour avoir accès à toutes les fontionnalités !

Aide mémoire off'R ;)

Enregistrez vous pour recevoir gratuitement mes fiches “aide mémoire” (ou cheat sheets) qui vous permettront de réaliser facilement les principales analyses biostatistiques avec le logiciel R et pour être informés des mises à jour du site.