Cours
Comment créer un tableau
Commençons par récupérer des données. Le package MASS contient des informations sur 93 voitures en vente aux États‑Unis en 1993. Elles sont stockées dans l’objet Cars93 et incluent 27 variables par voiture, dont certaines catégorielles. Chargeons donc le package MASS et regardons le type de véhicules inclus dans cars93 :
library(MASS)
Cars93$Type
## [1] Small Midsize Compact Midsize Midsize Midsize Large Large
## [9] Midsize Large Midsize Compact Compact Sporty Midsize Van
## [17] Van Large Sporty Large Compact Large Small Small
## [25] Compact Van Midsize Sporty Small Large Small Small
## [33] Compact Sporty Sporty Van Midsize Large Small Sporty
## [41] Sporty Small Compact Small Small Sporty Midsize Midsize
## [49] Midsize Midsize Midsize Large Small Small Compact Van
## [57] Sporty Compact Midsize Sporty Midsize Small Midsize Small
## [65] Compact Van Midsize Compact Midsize Van Large Sporty
## [73] Small Compact Sporty Midsize Large Compact Small Small
## [81] Small Compact Small Small Sporty Midsize Van Small
## [89] Van Compact Sporty Compact Midsize
## Levels: Compact Large Midsize Small Sporty Van
On y trouve 6 types de voitures. La fonction table indique combien nous en avons de chaque type :
table(Cars93$Type)
##
## Compact Large Midsize Small Sporty Van
## 16 11 22 21 14 9
prop.table convertit ce tableau en proportions :
prop.table(table(Cars93$Type))
##
## Compact Large Midsize Small Sporty Van
## 0.17204301 0.11827957 0.23655914 0.22580645 0.15053763 0.09677419
Même chose pour l’origine des voitures :
table(Cars93$Origin)
##
## USA non-USA
## 48 45
prop.table(table(Cars93$Origin))
##
## USA non-USA
## 0.516129 0.483871
Comment créer un tableau de contingence
Très bien, nous avons vu que notre jeu de données contient un nombre similaire de voitures américaines et non américaines, et que les types les plus fréquents sont Midsize et Small. Cependant, les voitures US et non‑US diffèrent‑elles par type ?
Observons les types de voitures selon leur origine. Nous pouvons réutiliser table, mais avec deux arguments cette fois. Le premier deviendra la variable en lignes et le second la variable en colonnes :
table(Cars93$Type, Cars93$Origin)
##
## USA non-USA
## Compact 7 9
## Large 11 0
## Midsize 10 12
## Small 7 14
## Sporty 8 6
## Van 5 4
On constate maintenant ce que tout le monde sait : les Américains aiment les gros véhicules ! Le tableau ci‑dessus montre la distribution conjointe de deux variables catégorielles (Type et Origin). De tels tableaux sont appelés tableaux de contingence.
Comment obtenir les marginales à partir d’un tableau de contingence
Les fonctions rowSums et colSums sont explicites :
(tab1<-table(Cars93$Type, Cars93$Origin))
##
## USA non-USA
## Compact 7 9
## Large 11 0
## Midsize 10 12
## Small 7 14
## Sporty 8 6
## Van 5 4
rowSums(tab1)
## Compact Large Midsize Small Sporty Van
## 16 11 22 21 14 9
colSums(tab1)
## USA non-USA
## 48 45
Comment obtenir des pourcentages à partir d’un tableau de contingence
prop.table imbriqué avec table renvoie des fréquences :
prop.table(table(Cars93$Type, Cars93$Origin))
##
## USA non-USA
## Compact 0.07526882 0.09677419
## Large 0.11827957 0.00000000
## Midsize 0.10752688 0.12903226
## Small 0.07526882 0.15053763
## Sporty 0.08602151 0.06451613
## Van 0.05376344 0.04301075
Pour convertir en pourcentages, il suffit de multiplier par 100 :
prop.table(table(Cars93$Type, Cars93$Origin))*100
##
## USA non-USA
## Compact 7.526882 9.677419
## Large 11.827957 0.000000
## Midsize 10.752688 12.903226
## Small 7.526882 15.053763
## Sporty 8.602151 6.451613
## Van 5.376344 4.301075
Remarquez qu’il s’agit d’une distribution de probabilités conjointe, dont on peut déduire par exemple qu’environ 7,5 % des voitures sont petites et d’origine américaine.
Le plus souvent, on s’intéresse à la distribution d’une variable au sein de groupes définis par une autre. Ici, la répartition des types de voitures parmi les voitures US et, séparément, non‑US est parlante. Pour l’obtenir, on utilise l’argument margin de la fonction prop.table. Il indique si la variable de regroupement est en lignes (margin=1) ou en colonnes (margin=2) :
prop.table(table(Cars93$Type, Cars93$Origin), margin=2)*100
##
## USA non-USA
## Compact 14.583333 20.000000
## Large 22.916667 0.000000
## Midsize 20.833333 26.666667
## Small 14.583333 31.111111
## Sporty 16.666667 13.333333
## Van 10.416667 8.888889
On voit clairement maintenant que les petites voitures sont deux fois plus fréquentes dans la partie non‑USA que dans la partie USA de notre jeu de données.
Notez aussi que les pourcentages s’additionnent à 100 par colonne, tandis que dans le tableau de distribution conjointe (celui sans l’argument margin), la somme de tout le tableau donnait 100.
(tab2<-prop.table(table(Cars93$Type, Cars93$Origin), margin=2)*100)
##
## USA non-USA
## Compact 14.583333 20.000000
## Large 22.916667 0.000000
## Midsize 20.833333 26.666667
## Small 14.583333 31.111111
## Sporty 16.666667 13.333333
## Van 10.416667 8.888889
colSums(tab2)
## USA non-USA
## 100 100
Test du khi‑deux
La question la plus fréquente qui se pose avec les tableaux de contingence est l’indépendance des variables en lignes et en colonnes. La façon la plus simple d’y répondre est d’effectuer un test du khi‑deux. Il est détaillé dans ce tutoriel. Vérifions si Type et Origin sont indépendants :
chisq.test(Cars93$Type, Cars93$Origin)
## Warning in chisq.test(Cars93$Type, Cars93$Origin): Chi-squared
## approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: Cars93$Type and Cars93$Origin
## X-squared = 14.08, df = 5, p-value = 0.01511
Apparemment, non, mais nous avons aussi obtenu l’avertissement Chi-squared approximation may be incorrect. Cela vient du fait que la statistique du khi‑deux suit la loi du khi‑deux seulement de manière approximative. Plus on a d’observations, meilleure est l’approximation. La fonction chisq.test émet cet avertissement dès qu’un des effectifs attendus est inférieur à 5 (pour la notion d’« effectif attendu », voir le tutoriel lié ci‑dessus).
Test exact de Fisher
Le test exact de Fisher est une alternative au test du khi‑deux, utilisée principalement lorsque l’approximation du khi‑deux n’est pas satisfaisante. Exécutons‑le :
fisher.test(Cars93$Type, Cars93$Origin)
##
## Fisher's Exact Test for Count Data
##
## data: Cars93$Type and Cars93$Origin
## p-value = 0.007248
## alternative hypothesis: two.sided
Les résultats sont assez proches de ceux du khi‑deux, mais ce n’est pas toujours le cas. Un inconvénient majeur du test exact de Fisher est que, pour de grands tableaux (ou de grands échantillons), il devient coûteux en calcul.
Test G
Autre alternative : le test G. Sa statistique suit elle aussi approximativement une loi du khi‑deux, mais pour les petits échantillons, cette approximation est souvent meilleure que celle du test du khi‑deux classique. Pour le test G, on peut utiliser la fonction GTest du package DescTools. Les résultats sont de nouveau proches des deux tests précédents : Type et Origin ne sont pas indépendants.
library(DescTools)
GTest(Cars93$Type, Cars93$Origin)
##
## Log likelihood ratio (G-test) test of independence without
## correction
##
## data: Cars93$Type and Cars93$Origin
## G = 18.362, X-squared df = 5, p-value = 0.002526
Correction de Yates
Dans les tableaux de contingence 2x2, le test du khi‑deux peut être amélioré par la correction de continuité de Yates. Elle consiste simplement à soustraire 0,5 à chaque terme | Observé − Attendu | de la statistique du khi‑deux. Reportez‑vous à ce tutoriel si nécessaire. De plus, R applique automatiquement la correction de Yates lorsqu’elle est indiquée. Observons la disponibilité d’une version à boîte manuelle selon l’origine (US vs non‑US) :
(tab3<-table(Cars93$Man.trans.avail, Cars93$Origin))
##
## USA non-USA
## No 26 6
## Yes 22 39
chisq.test(tab3)
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tab3
## X-squared = 15.397, df = 1, p-value = 8.712e-05
La correction de Yates a été appliquée automatiquement, et R nous l’indique.
Tableau à 3 (ou plus) dimensions
Observons simultanément Man.trans.avail, Origin et Type. table segmente le jeu de données selon la variable fournie en troisième position :
table(Cars93$Man.trans.avail, Cars93$Origin, Cars93$Type)
## , , = Compact
##
##
## USA non-USA
## No 2 0
## Yes 5 9
##
## , , = Large
##
##
## USA non-USA
## No 11 0
## Yes 0 0
##
## , , = Midsize
##
##
## USA non-USA
## No 9 4
## Yes 1 8
##
## , , = Small
##
##
## USA non-USA
## No 0 0
## Yes 7 14
##
## , , = Sporty
##
##
## USA non-USA
## No 0 0
## Yes 8 6
##
## , , = Van
##
##
## USA non-USA
## No 4 2
## Yes 1 2
ftable offre une vue plus compacte :
ftable(Cars93$Man.trans.avail, Cars93$Origin, Cars93$Type)
## Compact Large Midsize Small Sporty Van
##
## No USA 2 11 9 0 0 4
## non-USA 0 0 4 0 0 2
## Yes USA 5 0 1 7 8 1
## non-USA 9 0 8 14 6 2
Test de Cochran–Mantel–Haenszel
D’après les résultats de table ci‑dessus, il est clair que la relation entre Origin et Man.trans.avail varie selon le Type. Pour les petites et les sportives, par exemple, il n’y a pas d’association : chaque voiture US comme non‑US de ces catégories existe en version manuelle. En revanche, la plupart des berlines américaines (Midsize) n’ont pas de version manuelle, alors que la plupart des non‑US de ce type en ont une. Pour tenir compte de relations potentiellement différentes selon les strates, on peut utiliser le test de Cochran–Mantel–Haenszel :
mantelhaen.test(Cars93$Man.trans.avail, Cars93$Origin, Cars93$Type)
##
## Mantel-Haenszel chi-squared test with continuity correction
##
## data: Cars93$Man.trans.avail and Cars93$Origin and Cars93$Type
## Mantel-Haenszel X-squared = 8.0153, df = 1, p-value = 0.004638
## alternative hypothesis: true common odds ratio is not equal to 1
## 95 percent confidence interval:
## 2.226531 76.891307
## sample estimates:
## common odds ratio
## 13.08438
Le troisième argument passé à mantelhaen.test identifie les strates. Comparez les résultats ci‑dessus à ceux sans stratification (exemple avec la correction de Yates). L’association demeure, mais l’évidence en sa faveur est nettement plus faible.
Mesures d’association
Une fois des associations mises en évidence entre variables, il est temps d’en mesurer l’intensité. Il existe une multitude de mesures possibles. Beaucoup sont décrites ici. Concentrons‑nous sur les deux plus utilisées.
V de Cramér
V est basé sur la statistique du khi‑deux :
$$ V = \sqrt{\frac{\chi^2/N}{\min(C-1, R-1)}}, $$ où :
- N est le total général du tableau de contingence (somme de toutes les cellules),
- C est le nombre de colonnes,
- R est le nombre de lignes.
V ∈ [0 ; 1]. Plus V est grand, plus la relation entre les variables est forte. V = 0 peut s’interpréter comme l’indépendance (puisque V = 0 si et seulement si χ2 = 0). Le principal inconvénient de V est l’absence d’interprétation précise. V = 0,6 correspond‑il à une association forte, moyenne ou faible ?
La fonction CramerV du package DescTools permet de le calculer :
CramerV(Cars93$Type, Cars93$Origin)
## [1] 0.3890967
Encore une fois : s’agit‑il d’une association forte, moyenne ou faible ?
Lambda de Goodman et Kruskal
La lambda de Goodman et Kruskal est un exemple de mesure fondée sur la réduction proportionnelle de la variation. Ces mesures visent à s’approcher de R2 — le coefficient de détermination de la régression linéaire :
- elles prennent des valeurs dans [0 ; 1],
- elles expriment la part de variation expliquée par la variable indépendante.
Utilisons la variable en colonnes comme indépendante. La formule de la lambda de Goodman et Kruskal est alors : $$\lambda = \frac{L - \sum_j L_j}{L},$$ où :
- Lj est la somme des fréquences non modales dans la j-ième colonne,
- L est la somme des fréquences non modales dans la colonne « Total ».
Le mieux est d’illustrer par un exemple. Observons Type et Origin, la seconde étant indépendante :
table(Cars93$Type, Cars93$Origin)
##
## USA non-USA
## Compact 7 9
## Large 11 0
## Midsize 10 12
## Small 7 14
## Sporty 8 6
## Van 5 4
La modalité de la colonne USA est 11, donc L1 = 7 + 10 + 7 + 8 + 5 = 37. La modalité de la colonne non‑USA est 14, donc L2 = 9 + 0 + 12 + 6 + 4 = 31. La colonne « Total » est :
rowSums(table(Cars93$Type, Cars93$Origin))
## Compact Large Midsize Small Sporty Van
## 16 11 22 21 14 9
La modalité est 22, donc L = 16 + 11 + 21 + 14 + 9 = 71 et $$\lambda = \frac{71 - (37+31)}{71}=0.042$$
On peut utiliser la fonction Lambda du package DescTools à la place :
Lambda(Cars93$Type, Cars93$Origin, direction='row')
## [1] 0.04225352
Le paramètre direction indique où se trouve la variable dépendante (row pour les lignes, column pour les colonnes).
Origin n’explique qu’environ 4 % de la variation de Type. Notez, d’après la formule, que lambda définit la variation via une dichotomie entre appartenance et non‑appartenance au groupe le plus nombreux.
Il est utile de rappeler que lambda est nulle dès lors que la catégorie modale de chaque colonne est la même. Considérez ce tableau :
(lambdaTab<-cbind(c(0,100), c(49,51)))
## [,1] [,2]
## [1,] 0 49
## [2,] 100 51
chisq.test(lambdaTab)
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: lambdaTab
## X-squared = 62.279, df = 1, p-value = 2.981e-15
La catégorie modale est identique pour chaque colonne (la deuxième ligne). La lambda doit donc être nulle malgré une association significative et visible :
Lambda(lambdaTab, direction='row')
## [1] 0
Pour aller plus loin en statistiques avec R, suivez le cours Statistical Modeling in R (Part 1) de DataCamp.