Khi-2 d’indépendance avec R
Dans le précédent billet, j’ai utilisé la fonction Oracle STATS_CROSSTAB pour réaliser un test du Khi-2.
Cette fonction ne supportant pas l’emploi d’une table de contingence comme argument, il a fallu passer par une étape (plutôt contre-intuitive!) de « désagrégation » des données.
En utilisant R, l’opération est beaucoup plus aisée.
1) Chargement des données dans deux data-frames
> tgv <- read.csv2("regularite-mensuelle-tgv.csv")
> corail <- read.csv2("regularite-mensuelle-intercites.csv")
>
> dim(tgv)
[1] 4100 10
> dim(corail)
[1] 750 9
>
2) Nettoyage des données
On constitue un second dataframe en ne conservant que les données des années 2014 & 2015 relatives aux départs/arrivées de St Pierre des Corps. De plus, seuls les champs 6 et 8 sont récupérés (trains ayant circulés et trains ayant subi un retard):
> tgv.clean <- tgv[which(substr(tgv$Date,1,4) %in% c("2014","2015") & (tgv[,3]=="ST PIERRE DES CORPS" | tgv[,4]=="ST PIERRE DES CORPS")),c(6,8)]
>
> names(tgv.clean) <- c("Trains.Circules","Trains.Retard")
>
> summary(tgv.clean)
Trains.Circules Trains.Retard
Min. :322.0 Min. : 16.00
1st Qu.:421.0 1st Qu.: 38.25
Median :434.5 Median : 46.50
Mean :430.4 Mean : 50.96
3rd Qu.:448.8 3rd Qu.: 66.75
Max. :476.0 Max. :105.00
>
> head(tgv.clean)
Trains.Circules Trains.Retard
685 418 56
1194 409 48
2258 443 30
2262 420 81
2283 458 49
2400 431 39
>
On réalise une opération similaire pour le second dataframe:
> corail.clean <- corail[which((substr(corail[,3],1,3)=="ORL" | substr(corail[,4],1,3)=="ORL")),c(6,8)]
>
> names(corail.clean) <- c("Trains.Circules","Trains.Retard")
>
> summary(corail.clean)
Trains.Circules Trains.Retard
Min. :154.0 Min. : 10.00
1st Qu.:336.8 1st Qu.: 40.25
Median :354.0 Median : 58.00
Mean :337.7 Mean : 57.83
3rd Qu.:365.5 3rd Qu.: 71.00
Max. :379.0 Max. :109.00
> head(corail.clean)
Trains.Circules Trains.Retard
79 356 91
115 339 57
130 364 59
210 342 63
238 154 10
267 367 33
>
3) Création d’une table de contingence
A l’aide de l’opérateur apply appliquée en colonne sur les dataframes tgv.clean et corail.clean, on réalise la somme des effectifs de trains ayant circulés et en retard. On fusionne ces informations dans un seul dataframe. Enfin on ajoute une colonne « Trains.Ponctuels » dont les effectifs correspondent à la soustraction ligne à ligne Trains.Circules-Trains.Retard:
> cont.tab <- as.data.frame( rbind( apply(corail.clean[,],2,sum), apply(tgv.clean[,],2,sum) ) )
>
> row.names(cont.tab) <- c("Corail - Orleans/Paris", "TGV - SpDC/Paris")
>
> cont.tab$Trains.Ponctuels <- cont.tab$Trains.Circules-cont.tab$Trains.Retard
>
> cont.tab
Trains.Circules Trains.Retard Trains.Ponctuels
Corail - Orleans/Paris 10131 1735 8396
TGV - SpDC/Paris 11190 1325 9865
>
On supprime enfin la colonne Trains.Circules dans la mesure où elle ne servira pas dans le test du Khi-2 (les catégories doivent être mutuellement exclusives):
> cont.tab <- cont.tab[,-1]
> cont.tab
Trains.Retard Trains.Ponctuels
Corail - Orleans/Paris 1735 8396
TGV - SpDC/Paris 1325 9865
>
4) Réalisation du test
> chi2 <- chisq.test(cont.tab, correct=FALSE)
> chi2
Pearson's Chi-squared test
data: cont.tab
X-squared = 120.8061, df = 1, p-value < 2.2e-16
> chi2$expected
Trains.Retard Trains.Ponctuels
Corail - Orleans/Paris 1454.006 8676.994
TGV - SpDC/Paris 1605.994 9584.006
>
La valeur p est là encore très faible et on arrive à la même conclusion que dans le billet précédent! A noter cependant que si la valeur du Khi-2 est identique entre les deux méthodes (120.8), la p-value retenue est différente (mais elle reste proche de zéro).