Ce rapport présente le travail réalisé pour le TD1 du cours STI812 (Statistique et analyse de données). Ce TD sert à apprendre à utiliser R et RStudio pour importer, décrire et visualiser des données, et à savoir interpréter correctement des résultats statistiques — des compétences utiles ensuite pour analyser des données de génie civil
Le TD s’appuie sur trois jeux de données : airquality
(mesures de qualité de l’air, fourni avec R), HairEyeColor
(croisement qualitatif couleur des cheveux / couleur des yeux) et un jeu
de données propre au génie civil (TD_genie_civil.xlsx,
feuille beton) portant sur des essais de résistance sur
éprouvettes de béton. L’ensemble du travail est reproductible : chaque
résultat numérique présenté dans ce document est calculé directement par
R au moment de la compilation (knit) du fichier.
• Se familiariser avec l’environnement RStudio, notamment la mise en place d’un projet, l’écriture d’un script, l’installation et le chargement des packages nécessaires, ainsi que l’importation des jeux de données. • Déterminer et analyser les principaux indicateurs statistiques descriptifs, qu’il s’agisse de tendance centrale, de dispersion ou de la forme d’une distribution. • Construire des visualisations graphiques appropriées grâce au package ggplot2, telles que l’histogramme, la boîte à moustaches ou le nuage de points. • Évaluer et interpréter les liens statistiques existant entre deux variables, en s’appuyant sur les coefficients de corrélation (Pearson, Spearman), le test d’indépendance du khi-deux, ainsi que l’analyse de la variance (ANOVA) à un facteur. • Appliquer l’ensemble de cette méthodologie statistique à un cas concret tiré du génie civil, à partir de données issues d’essais sur béton
| Jeu de données | Origine | Description |
|---|---|---|
| airquality | Fourni avec R (base R) | Mesures quotidiennes de qualité de l’air à New York (Ozone, Solar.R, Wind, Temp, Month, Day) |
| HairEyeColor | Fourni avec R (base R) | Tableau croisé qualitatif : couleur des cheveux x couleur des yeux x sexe |
| beton (TD_genie_civil.xlsx) | Fichier fourni par l’enseignant | Essais sur éprouvettes de béton : dosage en ciment, rapport E/C, âge, granulat, affaissement, porosité, résistance, pathologie |
Logiciels : R (version 4.6.1) et RStudio, packages
tidyverse (dont ggplot2 et
dplyr), readxl pour l’importation du fichier
Excel, knitr et kableExtra pour la mise en
forme des tableaux.
Le chemin du fichier Excel est paramétré dans l’objet ci-dessous ; si le fichier n’est pas présent au moment de la compilation, le code reste fonctionnel et affichera un message informatif au lieu d’échouer.
# Chemin vers le fichier de données de génie civil
# A adapter si le fichier n'est pas dans le même dossier que ce document .Rmd
chemin_excel <- "TD_genie_civil.xlsx"
fichier_disponible <- file.exists(chemin_excel)
airqualityCet exercice met en place le projet de travail (projet RStudio
TD1_STI812, script td1.R) puis charge le jeu
de données airquality, intégré à R, qui rassemble des
mesures quotidiennes de qualité de l’air (concentration d’ozone,
rayonnement solaire, vent, température) relevées à New York entre mai et
septembre 1973.
data(airquality)
# Structure et types de variables
str(airquality)
## 'data.frame': 153 obs. of 6 variables:
## $ Ozone : int 41 36 12 18 NA 28 23 19 8 NA ...
## $ Solar.R: int 190 118 149 313 NA NA 299 99 19 194 ...
## $ Wind : num 7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
## $ Temp : int 67 72 74 62 56 66 65 59 61 69 ...
## $ Month : int 5 5 5 5 5 5 5 5 5 5 ...
## $ Day : int 1 2 3 4 5 6 7 8 9 10 ...
dplyr::glimpse(airquality)
## Rows: 153
## Columns: 6
## $ Ozone <int> 41, 36, 12, 18, NA, 28, 23, 19, 8, NA, 7, 16, 11, 14, 18, 14, …
## $ Solar.R <int> 190, 118, 149, 313, NA, NA, 299, 99, 19, 194, NA, 256, 290, 27…
## $ Wind <dbl> 7.4, 8.0, 12.6, 11.5, 14.3, 14.9, 8.6, 13.8, 20.1, 8.6, 6.9, 9…
## $ Temp <int> 67, 72, 74, 62, 56, 66, 65, 59, 61, 69, 74, 69, 66, 68, 58, 64…
## $ Month <int> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,…
## $ Day <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,…
knitr::kable(
as.data.frame(unclass(summary(airquality)), stringsAsFactors = FALSE),
caption = "Résumé statistique des variables de airquality"
) |>
kableExtra::kable_styling(full_width = TRUE)
| Ozone | Solar.R | Wind | Temp | Month | Day | |
|---|---|---|---|---|---|---|
| X | Min. : 1.00 | Min. : 7.0 | Min. : 1.700 | Min. :56.00 | Min. :5.000 | Min. : 1.0 |
| X.1 | 1st Qu.: 18.00 | 1st Qu.:115.8 | 1st Qu.: 7.400 | 1st Qu.:72.00 | 1st Qu.:6.000 | 1st Qu.: 8.0 |
| X.2 | Median : 31.50 | Median :205.0 | Median : 9.700 | Median :79.00 | Median :7.000 | Median :16.0 |
| X.3 | Mean : 42.13 | Mean :185.9 | Mean : 9.958 | Mean :77.88 | Mean :6.993 | Mean :15.8 |
| X.4 | 3rd Qu.: 63.25 | 3rd Qu.:258.8 | 3rd Qu.:11.500 | 3rd Qu.:85.00 | 3rd Qu.:8.000 | 3rd Qu.:23.0 |
| X.5 | Max. :168.00 | Max. :334.0 | Max. :20.700 | Max. :97.00 | Max. :9.000 | Max. :31.0 |
| X.6 | NAs :37 | NAs :7 | NA | NA | NA | NA |
na_par_variable <- colSums(is.na(airquality))
knitr::kable(
data.frame(Variable = names(na_par_variable), Valeurs_manquantes = na_par_variable),
row.names = FALSE,
caption = "Nombre de valeurs manquantes par variable"
)
| Variable | Valeurs_manquantes |
|---|---|
| Ozone | 37 |
| Solar.R | 7 |
| Wind | 0 |
| Temp | 0 |
| Month | 0 |
| Day | 0 |
n_individus <- nrow(airquality)
n_variables <- ncol(airquality)
Le jeu airquality comporte 153 individus (observations
quotidiennes) et 6 variables. Les variables Ozone,
Solar.R, Wind et Temp sont
quantitatives continues (mesures physiques), tandis que
Month et Day sont des variables quantitatives
discrètes servant ici d’index temporel. Le tableau des valeurs
manquantes montre que la variable Ozone concentre
l’essentiel des données manquantes, ce qui devra être pris en compte
(option na.rm = TRUE ou na.omit()) dans les
analyses suivantes portant sur cette variable.
Aucune hypothèse distributionnelle n’est requise pour le calcul des indicateurs de position et de dispersion eux-mêmes. En revanche, l’interprétation du couple moyenne/écart-type suppose implicitement une distribution proche de la symétrie : en cas de forte asymétrie, la médiane et l’écart interquartile (IQR), robustes aux valeurs extrêmes, sont préférés.
indicateurs_ozone <- airquality |>
dplyr::summarise(
Moyenne = mean(Ozone, na.rm = TRUE),
Mediane = median(Ozone, na.rm = TRUE),
Ecart_type = sd(Ozone, na.rm = TRUE),
Q1 = quantile(Ozone, 0.25, na.rm = TRUE),
Q3 = quantile(Ozone, 0.75, na.rm = TRUE),
Coefficient_variation = Ecart_type / Moyenne
)
knitr::kable(indicateurs_ozone, digits = 2,
caption = "Indicateurs de position et de dispersion — Ozone") |>
kableExtra::kable_styling(full_width = FALSE)
| Moyenne | Mediane | Ecart_type | Q1 | Q3 | Coefficient_variation |
|---|---|---|---|---|---|
| 42.13 | 31.5 | 32.99 | 18 | 63.25 | 0.78 |
ggplot(airquality, aes(x = Ozone)) +
geom_histogram(bins = 15, fill = "#1E7A3D", colour = "white", na.rm = TRUE) +
labs(title = "Distribution de la concentration d'ozone",
x = "Ozone (ppb)", y = "Effectif") +
theme_minimal()
ggplot(airquality, aes(y = Ozone)) +
geom_boxplot(fill = "#DEEAF1", na.rm = TRUE) +
labs(title = "Boîte à moustaches de la concentration d'ozone", y = "Ozone (ppb)") +
theme_minimal() +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())
La comparaison entre la moyenne et la médiane calculées ci-dessus renseigne sur la symétrie de la distribution : lorsque la moyenne est sensiblement supérieure à la médiane, la distribution est étalée vers la droite (asymétrie positive), ce que confirme visuellement l’histogramme. La boîte à moustaches met en évidence, le cas échéant, des valeurs atypiques au-delà de la moustache supérieure, correspondant à des épisodes de pollution photochimique intense (fortes chaleurs, faible ventilation). Dans ce contexte de distribution asymétrique, la médiane et l’IQR décrivent mieux le centre et la dispersion de la variable que la moyenne et l’écart-type, qui sont sensibles aux valeurs extrêmes.
Le coefficient de corrélation de Pearson mesure une liaison linéaire entre deux variables quantitatives et suppose l’absence de valeurs aberrantes influentes ; le coefficient de Spearman, fondé sur les rangs, mesure une liaison monotone plus générale et est plus robuste aux valeurs extrêmes et aux relations non strictement linéaires. Il convient de rappeler ici qu’une corrélation, aussi forte soit-elle, ne démontre pas de lien de causalité entre les deux variables.
ggplot(airquality, aes(Temp, Ozone)) +
geom_point(colour = "#1F4E79", na.rm = TRUE) +
geom_smooth(method = "lm", na.rm = TRUE, se = TRUE) +
labs(title = "Ozone en fonction de la température",
x = "Température (°F)", y = "Ozone (ppb)") +
theme_minimal()
cor_pearson <- cor(airquality$Temp, airquality$Ozone, use = "complete.obs", method = "pearson")
cor_spearman <- cor(airquality$Temp, airquality$Ozone, use = "complete.obs", method = "spearman")
knitr::kable(
data.frame(Methode = c("Pearson", "Spearman"),
Coefficient = round(c(cor_pearson, cor_spearman), 3)),
caption = "Corrélation entre Temp et Ozone"
)
| Methode | Coefficient |
|---|---|
| Pearson | 0.698 |
| Spearman | 0.774 |
matrice_cor <- round(cor(airquality[, 1:4], use = "complete.obs"), 2)
knitr::kable(matrice_cor, caption = "Matrice de corrélation des variables quantitatives") |>
kableExtra::kable_styling(full_width = FALSE)
| Ozone | Solar.R | Wind | Temp | |
|---|---|---|---|---|
| Ozone | 1.00 | 0.35 | -0.61 | 0.70 |
| Solar.R | 0.35 | 1.00 | -0.13 | 0.29 |
| Wind | -0.61 | -0.13 | 1.00 | -0.50 |
| Temp | 0.70 | 0.29 | -0.50 | 1.00 |
Le coefficient de Pearson calculé indique une association positive entre la température et la concentration d’ozone, cohérente avec la chimie atmosphérique (la formation d’ozone troposphérique est favorisée par le rayonnement solaire et les fortes températures). L’écart entre le coefficient de Pearson et celui de Spearman, s’il est faible, suggère une relation globalement linéaire ; un écart plus marqué indiquerait une relation monotone mais non linéaire, ou l’influence de quelques observations atypiques. La matrice de corrélation permet de situer cette liaison Temp–Ozone par rapport aux autres couples de variables (par exemple Wind–Ozone, généralement négative). Il est rappelé qu’une corrélation, même élevée, ne prouve pas de lien de causalité : elle peut résulter d’un facteur commun (ici, les conditions météorologiques d’ensemble).
HairEyeColorLe test du khi-deux d’indépendance compare les effectifs observés d’un tableau de contingence aux effectifs théoriques attendus sous l’hypothèse nulle d’indépendance entre les deux variables qualitatives. Sa validité repose sur une condition d’effectifs théoriques suffisants (généralement, au moins 80 % des cases avec un effectif théorique ≥ 5).
tab_cheveux_yeux <- margin.table(HairEyeColor, c(1, 2))
knitr::kable(as.data.frame.matrix(tab_cheveux_yeux),
caption = "Tableau de contingence : couleur des cheveux x couleur des yeux")
| Brown | Blue | Hazel | Green | |
|---|---|---|---|---|
| Black | 68 | 20 | 15 | 5 |
| Brown | 119 | 84 | 54 | 29 |
| Red | 26 | 17 | 14 | 14 |
| Blond | 7 | 94 | 10 | 16 |
test_khideux <- chisq.test(tab_cheveux_yeux)
test_khideux
##
## Pearson's Chi-squared test
##
## data: tab_cheveux_yeux
## X-squared = 138.29, df = 9, p-value < 2.2e-16
knitr::kable(round(test_khideux$expected, 1),
caption = "Effectifs théoriques sous l'hypothèse d'indépendance")
| Brown | Blue | Hazel | Green | |
|---|---|---|---|---|
| Black | 40.1 | 39.2 | 17.0 | 11.7 |
| Brown | 106.3 | 103.9 | 44.9 | 30.9 |
| Red | 26.4 | 25.8 | 11.2 | 7.7 |
| Blond | 47.2 | 46.1 | 20.0 | 13.7 |
La statistique du khi-deux (138.29), les degrés de liberté (9) et la p-valeur (2.33^{-25}) permettent de conclure : une p-valeur inférieure à 0,05 conduit au rejet de l’hypothèse d’indépendance entre la couleur des cheveux et la couleur des yeux au risque de 5 %, ce qui traduit une association statistique entre les deux caractères. Le tableau des effectifs théoriques ci-dessus permet de vérifier la condition de validité du test (effectifs théoriques suffisamment élevés) ; dans le cas contraire, un test exact de Fisher serait préférable.
L’ANOVA à un facteur teste l’égalité des moyennes de la variable
quantitative (Temp) entre les groupes définis par la
variable qualitative (Month). Ses hypothèses sont :
indépendance des observations, normalité des résidus au sein de chaque
groupe, et homogénéité des variances (homoscédasticité) entre
groupes.
aq_anova <- airquality
aq_anova$Month <- factor(aq_anova$Month)
ggplot(aq_anova, aes(Month, Temp)) +
geom_boxplot(fill = "#E2EFDA") +
labs(title = "Température par mois", x = "Mois", y = "Température (°F)") +
theme_minimal()
mod_anova <- aov(Temp ~ Month, data = aq_anova)
summary(mod_anova)
## Df Sum Sq Mean Sq F value Pr(>F)
## Month 4 7061 1765.3 39.85 <2e-16 ***
## Residuals 148 6557 44.3
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
resume_anova <- summary(mod_anova)[[1]]
p_valeur_anova <- resume_anova["Month", "Pr(>F)"]
La p-valeur du test de Fisher associée au facteur Month
(1.28^{-22}) permet de conclure sur l’existence, ou non, d’une
différence significative des températures moyennes selon les mois au
risque de 5 %. Les boîtes à moustaches confirment visuellement une
tendance saisonnière (températures croissantes de mai à juillet-août
puis décroissantes). Cette conclusion reste conditionnée par la
vérification des hypothèses de l’ANOVA (normalité des résidus,
homogénéité des variances), qui pourrait être approfondie par un test de
Shapiro-Wilk sur les résidus et un test de Levene sur les variances.
L’exercice consiste à transposer la démarche mise en œuvre dans ce TD (statistique univariée, mesure de liaison bivariée) à un extrait des données du projet personnel de l’étudiant(e).
# Remplacer 'donnees_projet' par le jeu de données du projet et 'variable_1', 'variable_2'
# par les variables réellement étudiées.
# donnees_projet <- read_excel("mon_fichier_projet.xlsx")
# summary(donnees_projet$variable_1)
# cor(donnees_projet$variable_1, donnees_projet$variable_2, use = "complete.obs")
Pour chaque variable retenue, il convient d’identifier son type (quantitative continue, quantitative discrète, qualitative nominale ou ordinale), de calculer un ou deux indicateurs univariés pertinents (moyenne/médiane pour une variable quantitative, effectifs/fréquences pour une variable qualitative), puis une mesure de liaison bivariée adaptée aux types de variables en présence (corrélation si les deux variables sont quantitatives, test du khi-deux si les deux variables sont qualitatives, ANOVA si l’une est quantitative et l’autre qualitative). La section « Exercice 7 » ci-dessous illustre concrètement cette transposition sur les données de génie civil.
Cette section applique la démarche statistique du TD1 à un jeu de
données de génie civil issu d’essais sur éprouvettes de béton (fichier
TD_genie_civil.xlsx, feuille beton),
comportant notamment le dosage en ciment, le rapport eau/ciment (E/C),
l’âge de l’éprouvette, le type de granulat, l’affaissement au cône
d’Abrams, la porosité et la résistance mécanique en compression, ainsi
que la présence éventuelle d’une pathologie.
if (fichier_disponible) {
donnees_beton <- readxl::read_excel(chemin_excel, sheet = "beton")
} else {
message("Fichier TD_genie_civil.xlsx introuvable : placez-le dans le dossier du projet ",
"pour que ce chunk produise des résultats lors de la compilation.")
donnees_beton <- NULL
}
if (!is.null(donnees_beton)) {
dplyr::glimpse(donnees_beton)
knitr::kable(
as.data.frame(unclass(summary(
donnees_beton |> dplyr::select(resistance_MPa, rapport_eau_ciment)
)), stringsAsFactors = FALSE),
caption = "Résumé statistique — résistance et rapport E/C"
)
}
if (!is.null(donnees_beton)) {
ggplot(donnees_beton, aes(y = resistance_MPa)) +
geom_boxplot(fill = "#DEEAF1") +
labs(title = "Résistance en compression des éprouvettes", y = "Résistance (MPa)") +
theme_minimal() +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())
ggplot(donnees_beton, aes(y = rapport_eau_ciment)) +
geom_boxplot(fill = "#E2EFDA") +
labs(title = "Rapport eau/ciment (E/C) des formulations", y = "E/C") +
theme_minimal() +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())
}
if (!is.null(donnees_beton)) {
test_cor_beton <- cor.test(donnees_beton$resistance_MPa, donnees_beton$rapport_eau_ciment)
test_cor_beton
ggplot(donnees_beton, aes(rapport_eau_ciment, resistance_MPa)) +
geom_point(colour = "#1F4E79") +
geom_smooth(method = "lm", se = TRUE) +
labs(title = "Résistance en fonction du rapport E/C",
x = "Rapport E/C", y = "Résistance (MPa)") +
theme_minimal()
}
if (!is.null(donnees_beton)) {
tab_pathologie_granulat <- table(donnees_beton$pathologie, donnees_beton$granulat)
knitr::kable(as.data.frame.matrix(tab_pathologie_granulat),
caption = "Tableau de contingence : pathologie x granulat")
test_khideux_beton <- chisq.test(tab_pathologie_granulat)
test_khideux_beton
}
Le coefficient de corrélation entre la résistance en compression et le rapport E/C est attendu négatif : la loi de Feret/Abrams établit qu’une augmentation du rapport eau/ciment accroît la porosité de la pâte de ciment durcie et réduit donc la résistance mécanique du béton — ce que le test de corrélation et le nuage de points ci-dessus doivent permettre de vérifier empiriquement sur cet échantillon d’éprouvettes. Le test du khi-deux entre la pathologie observée et le type de granulat renseigne sur une éventuelle association entre la nature du granulat utilisé et l’apparition de désordres (fissuration, écaillage, etc.) ; une p-valeur significative inviterait à examiner plus finement les formulations à risque (granulat, dosage, E/C) afin d’améliorer la durabilité des ouvrages. Comme précédemment, seule une analyse causale contrôlée (plan d’expérience) permettrait d’établir un lien de cause à effet ; la statistique descriptive et les tests réalisés ici mettent en évidence des associations.
L’ensemble des analyses conduites dans ce TD illustre la
complémentarité des outils de statistique descriptive et exploratoire :
les indicateurs de position et de dispersion résument une variable
isolée, les représentations graphiques (histogramme, boîte à moustaches,
nuage de points) permettent une lecture visuelle rapide de la
distribution et des liaisons, tandis que les tests statistiques
(corrélation, khi-deux, ANOVA) apportent un cadre inférentiel pour juger
du caractère significatif d’une association observée sur l’échantillon.
L’application aux données de génie civil (essais sur béton) montre que
cette même démarche, initialement mise en œuvre sur des données
environnementales (airquality), se transpose directement à
des problématiques de formulation et de durabilité des matériaux de
construction, ce qui répond à l’objectif de transposition visé par
l’exercice 6.
airquality et
HairEyeColor sont des jeux pédagogiques standards, dont la
représentativité et le contexte de collecte (période, protocole de
mesure) ne sont que partiellement documentés.TD_genie_civil.xlsx
au moment de la compilation ; en son absence, seuls le code et sa
logique sont présentés.Ce TD1 a permis de mettre en pratique l’ensemble de la chaîne de
statistique descriptive et exploratoire sous R : importation de données,
calcul d’indicateurs univariés et bivariés, représentations graphiques
avec ggplot2, tests d’indépendance et d’analyse de la
variance, ainsi qu’un calcul manuel du test du khi-deux permettant d’en
comprendre les fondements mathématiques. La transposition de cette
démarche aux données de génie civil (essais sur béton) confirme la
pertinence de ces outils pour l’analyse de données expérimentales de
laboratoire et ouvre la voie aux méthodes multivariées (analyse
factorielle, classification, régression) qui seront abordées dans les TD
suivants du cours STI812.