Code
qi = 92:109
ni = c(1, 4, 9, 28, 23, 37, 51, 63, 65, 60, 48, 38, 32, 23, 12, 3, 1, 2)Dans ce TP, nous allons utiliser les outils de la normalité et de l’indépendance dans deux cadres :
Objectifs pédagogiques :
qqnorm)Le QQ-plot (Quantile-Quantile plot) est un outil graphique qui permet de visualiser rapidement si une série de données suit une distribution théorique donnée (gaussienne, Poisson, etc.).
Principe :
Soit \(x_1, \ldots, x_n\) une série statistique et \(F_0\) la fonction de répartition de la loi de probabilité de référence. On trace :
Interprétation : Plus les points sont alignés sur la diagonale, plus l’adéquation de la loi théorique avec la loi observée est forte.
Pour des données regroupées par modalités \(m_1, \ldots, m_J\) avec des fréquences cumulées \(F_1, \ldots, F_J\), les quantiles théoriques d’une loi normale sont : \(q_J^* = F_0^{-1}(F_J)\), accessibles via qnorm(F_J, m, σ).
Contexte : Xantane a relevé 500 fois les tensions (\(x_i\)) de sa pile. Les données sont regroupées dans le tableau suivant :
| \(x_i\) | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| \(n_i\) | 1 | 4 | 9 | 28 | 23 | 37 | 51 | 63 | 65 | 60 | 48 | 38 | 32 | 23 | 12 | 3 | 1 | 2 |
qi = 92:109
ni = c(1, 4, 9, 28, 23, 37, 51, 63, 65, 60, 48, 38, 32, 23, 12, 3, 1, 2)La moyenne pondérée se calcule comme : \(m = \frac{\sum q_i \cdot n_i}{\sum n_i}\)
m = sum(qi * ni) / sum(ni)
cat("Moyenne pondérée m =", m)Moyenne pondérée m = 100.068
\(\sigma = \sqrt{\frac{\sum n_i (q_i - m)^2}{\sum n_i - 1}}\)
sigma = sqrt(sum(ni * (qi - m)^2) / (sum(ni) - 1))
cat("Écart-type pondéré sigma =", round(sigma, 2))Écart-type pondéré sigma = 3.08
Fi = cumsum(ni) / sum(ni)
qietoile = qnorm(Fi, m, sigma)plot(qi, qietoile,
main = "QQ-Plot : Tensions de pile",
xlab = "Quantiles observés (qi)",
ylab = "Quantiles théoriques (qi*)",
pch = 19, col = "blue")
lines(c(90, 110), c(90, 110), col = "red", lwd = 2)
legend("topleft", legend = "Diagonale y = x", col = "red", lwd = 2)Conclusion : Les points sont bien alignés sur la diagonale. On observe une bonne adéquation avec une loi Normale \(\mathcal{N}(m, \sigma)\).
Puisque nous ne disposons pas des données brutes, nous ne pouvons pas faire un test de Shapiro-Wilk. Nous allons donc utiliser le test du χ² pour vérifier l’adéquation à la loi normale.
Pour que le test du χ² soit valide, il faut que les effectifs théoriques soient supérieurs à 5. On fusionne donc les 2 premiers et les 3 derniers effectifs :
ni2 = c(ni[1] + ni[2], ni[3:15], ni[16] + ni[17] + ni[18])
cat("Effectifs regroupés :", ni2)Effectifs regroupés : 5 9 28 23 37 51 63 65 60 48 38 32 23 12 6
On calcule les probabilités théoriques \(p_i\) en faisant la correction de continuité (bornes à ±0.5) :
k = c(91, 93:106) + 0.5
K = c(93:106.5, 109) + 0.5
pi_theo = pnorm(K, 100, 3.1) - pnorm(k, 100, 3.1)
ti = 500 * pi_theodchi = sum((ni2 - ti)^2 / ti)
cat("Statistique du chi-deux :", round(dchi, 4))Statistique du chi-deux : 12.0494
On peut aussi utiliser la fonction chisq.test :
chisq.test(ni2, p = pi_theo, rescale.p = TRUE)
Chi-squared test for given probabilities
data: ni2
X-squared = 11.991, df = 14, p-value = 0.607
Attention ! Les degrés de liberté valent \(15 - 1 - 2 = 12\) (car nous avons estimé 2 paramètres : \(m\) et \(\sigma\)). Or chisq.test() n’utilise pas les bons d.d.l. et donne une p-value erronée.
Calculons la p-value correcte :
cat("Quantile théorique χ²(0.95, 12) =", qchisq(0.95, 12))
cat("\nStatistique observée =", round(dchi, 4))
cat("\np-value correcte =", 1 - pchisq(dchi, 12))Quantile théorique χ²(0.95, 12) = 21.02607
Statistique observée = 12.0494
p-value correcte = 0.4417218
Conclusion : La p-value est supérieure à 0.05 → on ne rejette pas l’hypothèse de normalité au seuil 5%.
Le fichier titanic.csv contient le registre des passagers du Titanic. L’objectif est d’étudier la relation entre survie et classe à l’aide du test d’indépendance de Chi-deux.
titanic = read.csv("titanic.csv")
head(titanic)| PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| <int> | <int> | <int> | <chr> | <chr> | <dbl> | <int> | <int> | <chr> | <dbl> | <chr> | <chr> | |
| 1 | 1 | 0 | 3 | Braund. Mr. Owen Harris | male | 22 | 1 | 0 | A/5 21171 | 7.2500 | S | |
| 2 | 2 | 1 | 1 | Cumings. Mrs. John Bradley (Florence Briggs Thayer) | female | 38 | 1 | 0 | PC 17599 | 71.2833 | C85 | C |
| 3 | 3 | 1 | 3 | Heikkinen. Miss. Laina | female | 26 | 0 | 0 | STON/O2. 3101282 | 7.9250 | S | |
| 4 | 4 | 1 | 1 | Futrelle. Mrs. Jacques Heath (Lily May Peel) | female | 35 | 1 | 0 | 113803 | 53.1000 | C123 | S |
| 5 | 5 | 0 | 3 | Allen. Mr. William Henry | male | 35 | 0 | 0 | 373450 | 8.0500 | S | |
| 6 | 6 | 0 | 3 | Moran. Mr. James | male | NA | 0 | 0 | 330877 | 8.4583 | Q |
Stockons les variables d’intérêt :
survived = titanic$Survived
class = titanic$Pclass
head(survived)
head(class)Construisons le tableau de contingence :
contingence1 = table(survived, class)
contingence1 class
survived 1 2 3
0 80 97 372
1 136 87 119
Effectuons le test du χ² d’indépendance :
chisq.test(contingence1)
Pearson's Chi-squared test
data: contingence1
X-squared = 102.89, df = 2, p-value < 2.2e-16
Interprétation : La p-value est inférieure à 0.05 (pratiquement égale à 0) → on rejette significativement l’hypothèse d’indépendance. La classe et la survie sont dépendantes. Malheureusement, on le savait…
contingence_sex = table(survived, titanic$Sex)
contingence_sex
chisq.test(contingence_sex)
survived female male
0 81 468
1 233 109
Pearson's Chi-squared test with Yates' continuity correction
data: contingence_sex
X-squared = 260.72, df = 1, p-value < 2.2e-16
contingence2 = table(class, titanic$Embarked)
contingence2
class C Q S
1 2 85 2 127
2 0 17 3 164
3 0 66 72 353
On remarque une colonne vide (port inconnu). Supprimons-la :
contingence2 = contingence2[, -1]
contingence2
chisq.test(contingence2)
class C Q S
1 85 2 127
2 17 3 164
3 66 72 353
Pearson's Chi-squared test
data: contingence2
X-squared = 123.75, df = 4, p-value < 2.2e-16
contingence3 = table(survived, titanic$Embarked)
contingence3 = contingence3[, -1]
chisq.test(contingence3)
Pearson's Chi-squared test
data: contingence3
X-squared = 26.489, df = 2, p-value = 1.77e-06
ageage = titanic$Age
head(age)Certains âges sont manquants (NA). Gardons seulement les âges connus :
age = age[!is.na(age)]
class2 = class[!is.na(titanic$Age)]
cat("Nombre d'âges valides :", length(age))Nombre d'âges valides : 714
ageplot(density(age),
main = "Densité de la variable Age",
xlab = "Âge", ylab = "Densité",
col = "blue", lwd = 2)qqnorm(age, main = "QQ-plot de Age")
qqline(age, col = "red")shapiro.test(age)
Shapiro-Wilk normality test
data: age
W = 0.98146, p-value = 7.337e-08
Conclusion : La densité n’a pas l’allure d’une gaussienne, le QQ-plot dévie, et le test de Shapiro-Wilk rejette la normalité (p-value < 0.05). La variable age n’est pas normale.
age par classeLa fonction tapply permet d’appliquer une fonction à une variable divisée par sous-groupes :
tapply(age, class2, shapiro.test)$`1`
Shapiro-Wilk normality test
data: X[[i]]
W = 0.99169, p-value = 0.3643
$`2`
Shapiro-Wilk normality test
data: X[[i]]
W = 0.97695, p-value = 0.005648
$`3`
Shapiro-Wilk normality test
data: X[[i]]
W = 0.97344, p-value = 4.186e-06
Conclusion : Seul en première classe, l’âge peut être considéré comme normal. Reste à savoir si cette information est vraiment intéressante…
| Outil | Utilisation | Fonction R |
|---|---|---|
| QQ-plot | Visualiser l’adéquation à une loi | qqnorm(), plot() |
| Test χ² d’adéquation | Tester si les données suivent une loi | chisq.test() |
| Test χ² d’indépendance | Tester l’indépendance de 2 variables | chisq.test(table()) |
| Test de Shapiro-Wilk | Tester la normalité (données brutes) | shapiro.test() |
tapply |
Appliquer une fonction par sous-groupe | tapply(var, groupe, fun) |