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()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
GRAPH /BAR(GROUPED)=COUNT BY niveau_activite BY sexe.
Questions :
- Quel niveau d’activité est le plus fréquent ?
- Y a-t-il une différence visible entre hommes et femmes ?
- 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 :
- Quelles variables présentent des outliers ?
- Ces valeurs sont-elles cliniquement plausibles ?
- 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))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.