Module 3

Analyse descriptive des données

Visualisation et exploration des données biomédicales

3h Débutant Prérequis : Modules 1-2

1 Objectifs du TP

  • Créer des graphiques adaptés aux types de données
  • Réaliser une analyse exploratoire complète
  • Détecter les valeurs aberrantes
  • Tester la normalité des distributions

2 Partie 1 : Graphiques pour variables qualitatives

2.1 Exercice 1.1 : Diagrammes en barres

library(tidyverse)

patients <- read_csv("data/patients_diabete.csv")

# a) Diagramme en barres du niveau d'activité physique
ggplot(patients, aes(x = niveau_activite, fill = niveau_activite)) +
  geom_bar() +
  labs(title = "Répartition par niveau d'activité",
       x = "Niveau d'activité", y = "Effectif") +
  theme_minimal() +
  scale_fill_brewer(palette = "Set2") +
  theme(legend.position = "none")

# b) Barres groupées : niveau d'activité par sexe
ggplot(patients, aes(x = niveau_activite, fill = sexe)) +
  geom_bar(position = "dodge") +
  labs(title = "Activité physique selon le sexe",
       x = "Niveau d'activité", y = "Effectif", fill = "Sexe") +
  theme_minimal()

# c) Barres empilées en pourcentage
ggplot(patients, aes(x = type_diabete, fill = niveau_activite)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Activité physique par type de diabète",
       x = "Type", y = "Proportion", fill = "Activité") +
  theme_minimal()
Avec SPSS
GRAPH /BAR(GROUPED)=COUNT BY niveau_activite BY sexe.

Questions :

  1. Quel niveau d’activité est le plus fréquent ?
  2. Y a-t-il une différence visible entre hommes et femmes ?
  3. Les patients diabétiques de type 1 et 2 ont-ils le même profil d’activité ?

3 Partie 2 : Graphiques pour variables quantitatives

3.1 Exercice 2.1 : Histogrammes et densités

# a) Histogramme de l'âge avec différents nombres de classes
p1 <- ggplot(patients, aes(x = age)) +
  geom_histogram(bins = 5, fill = "steelblue", color = "white") +
  labs(title = "5 classes") + theme_minimal()

p2 <- ggplot(patients, aes(x = age)) +
  geom_histogram(bins = 10, fill = "steelblue", color = "white") +
  labs(title = "10 classes") + theme_minimal()

p3 <- ggplot(patients, aes(x = age)) +
  geom_histogram(bins = 20, fill = "steelblue", color = "white") +
  labs(title = "20 classes") + theme_minimal()

library(patchwork)
p1 + p2 + p3

# b) Histogramme + courbe de densité
ggplot(patients, aes(x = glycemie)) +
  geom_histogram(aes(y = after_stat(density)),
                 bins = 15, fill = "steelblue", color = "white") +
  geom_density(color = "red", linewidth = 1) +
  geom_vline(xintercept = mean(patients$glycemie, na.rm = TRUE),
             color = "darkred", linetype = "dashed") +
  labs(title = "Distribution de la glycémie",
       x = "Glycémie (g/L)", y = "Densité") +
  theme_minimal()

Question : Quel nombre de classes vous semble le plus informatif ? Pourquoi ?

3.2 Exercice 2.2 : Boxplots comparatifs

# a) Boxplot de la glycémie par sexe
ggplot(patients, aes(x = sexe, y = glycemie, fill = sexe)) +
  geom_boxplot(alpha = 0.7) +
  geom_jitter(width = 0.1, alpha = 0.3) +
  labs(title = "Glycémie par sexe",
       x = "Sexe", y = "Glycémie (g/L)") +
  theme_minimal() +
  theme(legend.position = "none")

# b) Boxplot de l'HbA1c par type de diabète et niveau d'activité
ggplot(patients, aes(x = interaction(type_diabete, niveau_activite),
                      y = hba1c, fill = niveau_activite)) +
  geom_boxplot() +
  labs(title = "HbA1c par type de diabète et activité physique",
       x = "Type.Activité", y = "HbA1c (%)", fill = "Activité") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

3.3 Exercice 2.3 : Nuages de points et corrélations

# a) Relation entre poids et glycémie
ggplot(patients, aes(x = poids, y = glycemie)) +
  geom_point(aes(color = type_diabete), alpha = 0.7) +
  geom_smooth(method = "lm", se = TRUE, color = "black") +
  labs(title = "Relation poids - glycémie",
       x = "Poids (kg)", y = "Glycémie (g/L)") +
  theme_minimal()

# b) Matrice de nuages de points
library(GGally)
patients %>%
  select(age, poids, glycemie, hba1c) %>%
  ggpairs(
    upper = list(continuous = wrap("cor", size = 4)),
    lower = list(continuous = wrap("points", alpha = 0.5)),
    diag = list(continuous = wrap("densityDiag", fill = "steelblue"))
  ) +
  theme_minimal()

4 Partie 3 : Détection des valeurs aberrantes

4.1 Exercice 3.1 : Méthode de l’IQR

# Fonction de détection et visualisation des outliers
analyser_outliers <- function(data, variable, nom_var) {
  x <- data[[variable]]
  q1 <- quantile(x, 0.25, na.rm = TRUE)
  q3 <- quantile(x, 0.75, na.rm = TRUE)
  iqr <- q3 - q1

  borne_inf <- q1 - 1.5 * iqr
  borne_sup <- q3 + 1.5 * iqr

  outliers <- which(x < borne_inf | x > borne_sup)

  cat("=== Analyse des outliers pour", nom_var, "===\n")
  cat("Q1 =", q1, "| Q3 =", q3, "| IQR =", iqr, "\n")
  cat("Bornes : [", round(borne_inf, 2), ",", round(borne_sup, 2), "]\n")
  cat("Nombre d'outliers :", length(outliers), "\n")

  if (length(outliers) > 0) {
    cat("Valeurs :", x[outliers], "\n")
  }

  return(outliers)
}

out_glycemie <- analyser_outliers(patients, "glycemie", "Glycémie")
out_poids <- analyser_outliers(patients, "poids", "Poids")
out_hba1c <- analyser_outliers(patients, "hba1c", "HbA1c")

Questions :

  1. Quelles variables présentent des outliers ?
  2. Ces valeurs sont-elles cliniquement plausibles ?
  3. Quelle décision prendriez-vous pour chaque outlier identifié ?

5 Partie 4 : Test de normalité

5.1 Exercice 4.1 : Évaluation visuelle et test

# Pour chaque variable quantitative
variables <- c("age", "poids", "glycemie", "hba1c")

for (var in variables) {
  cat("\n===", var, "===\n")

  # Test de Shapiro-Wilk
  test <- shapiro.test(patients[[var]])
  cat("Shapiro-Wilk : W =", round(test$statistic, 4),
      ", p =", round(test$p.value, 4), "\n")
  cat("Normalité :", ifelse(test$p.value > 0.05, "OUI", "NON"), "\n")
}

# QQ-plots pour toutes les variables
par(mfrow = c(2, 2))
for (var in variables) {
  qqnorm(patients[[var]], main = paste("QQ-plot :", var))
  qqline(patients[[var]], col = "red")
}
par(mfrow = c(1, 1))
Avec SPSS
EXAMINE VARIABLES=age poids glycemie hba1c
  /PLOT NPPLOT HISTOGRAM
  /STATISTICS DESCRIPTIVES
  /CINTERVAL 95.

6 Partie 5 : Analyse exploratoire complète

6.1 Exercice 5.1 : EDA d’une étude clinique

Chargez le fichier etude_clinique.csv et réalisez une analyse exploratoire complète.

etude <- read_csv("data/etude_clinique.csv")

# 1. Vue d'ensemble
glimpse(etude)
summary(etude)

# 2. Valeurs manquantes
library(naniar)
vis_miss(etude) +
  labs(title = "Visualisation des données manquantes")

# 3. Statistiques descriptives par groupe de traitement
etude %>%
  group_by(groupe_traitement) %>%
  summarise(
    n = n(),
    across(where(is.numeric),
           list(moy = ~mean(.x, na.rm = TRUE),
                et = ~sd(.x, na.rm = TRUE)),
           .names = "{.col}_{.fn}")
  )

# 4. Visualisations clés
# Distribution de la variable principale par groupe
ggplot(etude, aes(x = groupe_traitement, y = score_amelioration,
                   fill = groupe_traitement)) +
  geom_boxplot(alpha = 0.7) +
  geom_jitter(width = 0.2, alpha = 0.3) +
  labs(title = "Score d'amélioration par groupe",
       x = "Groupe", y = "Score") +
  theme_minimal() +
  theme(legend.position = "none")

6.2 Exercice 5.2 : Rapport d’analyse descriptive

Rédigez un paragraphe de type “Caractéristiques de l’échantillon” en vous basant sur vos résultats. Incluez :

  • Description de l’échantillon (taille, répartition par groupe)
  • Variables quantitatives : moyenne ± écart-type
  • Variables qualitatives : n (%)
  • Signaler les données manquantes et outliers identifiés

7 Corrigé des questions

Exercice 2.1 : Un nombre intermédiaire de classes (10-15) est souvent optimal. Trop peu de classes masque les détails, trop de classes crée du bruit. La règle de Sturges (\(k = 1 + 3.3 \log_{10}(n)\)) donne une bonne indication.

Exercice 3.1 : Les outliers de glycémie élevée (> 3 g/L) sont cliniquement plausibles chez des patients diabétiques déséquilibrés. Un poids > 150 kg mérite vérification. On conserve les valeurs plausibles mais on les documente.

Exercice 4.1 : La glycémie et l’HbA1c sont souvent non normales (distribution asymétrique à droite). L’âge et le poids sont plus souvent proches de la normalité. Cela orientera le choix entre tests paramétriques et non paramétriques.