Moyennes ajustées avec R

Cette page est en fabrication, mais si vous avez des types d'ajustement de moyennes que vous souhaiteriez voir traités, n'hésitez pas à cliquer sur le pieds de page de cette page pour me le signaler par mail.

L'essentiel de cette page

Vaste sujet que l'ajustement de moyennes ! On utilise cette (ces !) technique.s statistiques lorsque les moyennes calculées le sont à partir d'échantillons biaisés ou trop petits/variables.

Certains envisageront de l'ajustement par calage (ajuster les valeurs observées pour qu'elles correspondent aux totaux connus de certaines variables de contrôle).

D'autres envisageront l'ajustement par imputation en remplaçant les données manquantes ou erronées par des valeurs estimées à partir d'autres sources.

Le mieux est de partir d'exemples.

1- Ajuster les moyennes en compensant l'effet d'une covariable

Imaginons que je compare la croissance de deux types de plantes durant 3 mois (mars, avril, mai) pour voir laquelle grandit la plus vite.

En réalité, je compare les tailles des plantes.

Simulons des données pour cet exemple :

set.seed(123)

n = 9

plantes <- rep(c(rep("A",n),rep("B",n)),3)

mois <- c(rep(3,n*2),rep(4,n*2),rep(5,n*2))

tailles <- c(rnorm(n,5,3),rnorm(n,6,3),rnorm(n,12,3),rnorm(n,15,3),rnorm(n,20,4),rnorm(n,23,4))

tablo <- data.frame(tailles, plantes, mois)

Si je compare de façon brutes les plantes A et B, je n'observe aucune différence. Forcément, je mélange les tailles de plantes mesurées en mars, en avril et en mai !

boxplot(tailles~plantes,col=rainbow(2))

t.test(tailles~plantes) # p-value de 0.12


Pas de différence observée entre les plantes, mais parce que mes données sont perturbées par la covariable temps (le mois).

Le bon sens voudrait alors que je compare uniquement la taille des plantes en avril, mais cela réduit la taille de mes échantillons à 9. Trop petit pour que je vois un effet significatif.

boxplot(tailles[mois==5]~plantes[mois==5],col=rainbow(2))

t.test(tailles[mois==5]~plantes[mois==5]) # p-value 0.138


A l'oeil, on a envie de dire que il y a une différence, mais comment l'affirmer, la p-value n'est pas significative, certainement car l'échantillon est trop petit du fait que j'ai ignoré les mesures faites en mars et avril pour ne garder que celle de mai.

En réalité, la variété de la plante joue (je sais bien puisque j'ai fait les données moi-même) mais aussi le mois.

Si on analyse les deux conjointement, on voit bien que B est plus grand que A.

barplot(by(tablo$taille,tablo[,2:3],mean),beside=T, col=rainbow(3))

Un des moyens de tenir compte de la covariable est de faire un test d'ancova. cf. l'aide sur les ancova.

summary(aov(tailles~plantes+mois))

            Df Sum Sq Mean Sq F value   Pr(>F)    

plantes      1  132.3   132.3   13.46 0.000582 ***

mois         1 2260.4  2260.4  229.99  < 2e-16 ***

On voit ici, que les deux on bien un effet significatif.

Bien, alors si on veut comparer les tailles moyennes des plantes.

Dans cet exemple, serait-ce bien raisonnable d'ajuster les moyennes,mais admetteons que l'on veut comparer les variétés à partir de 2 variables.

On peut ajuster ici avec une régression ou en calculant les moyennes marginales avec la fonction emmeans() de {emmean} comme présenté dans cette rubrique.

Ce raisonnement peut être généralisé à différents cas :

Si l'on a pas mesuré  le même nombre de plantes A et B (il faudra calculer la moyenne de chaque groupe puis établir ue moyenne global des 2 groupes).

Si l'on n'a pas un covariant (ANCOVA est impossible ou marchera très mal si l'effet mois fluctue tantôt vers le haut tantôt vers le bas). Selon la variable X, tantôt ça monte, tantôt ça descend. On fera alors une moyenne avec interaction.

Dans tous les  cas, ces situations doivent nous amener vers une anova à deux facteur.

Un cas toutefois, lorsque l'on souhaite comparer deux moyennes de deux catégories (facteur 1, ex, le type de Lycée) mais que pour chaque moyenne l'on a pas les mêmes proportions d'individus pour un deuxième facteur (ex : le sexe), il faut alors faire un test de Student stratifié (on traite chaque catégorie à part, on calcule la moyenne de chaque catégorie à part et on pondère les moyennes globales selon les proportions respectives de  chaque catégorie).

2- Ajuster les moyennes en compensant l'effet d'une variable non covariable

Pondérer les systemes oscillaires divisé par la moyennes de moyennes dz chaque groupe

En gros, il faut calculer la moyenne de chaque variété pour chaque condition, puis calculer la moyenne des 3 variétés pour chaque conditions et utiliser cette moyenne pour diviser l'ensemble. On ajoutera enfin à la fin une moyenne général des moyennes.

set.seed(123)


plantes <- c(rep("A",9),rep("B",6),rep("C",3),

rep("A",12),rep("B",12),rep("C",10),

rep("A",5),rep("B",4),rep("C",5),

rep("A",9),rep("B",6),rep("C",7))

conditions <- c(rep(1,9),rep(1,6),rep(1,3),

rep(2,12),rep(2,12),rep(2,10),

  rep(3,5),rep(3,4),rep(3,5),

  rep(4,9),rep(4,6),rep(4,7))

tailles <- c(rnorm(9,6,1),rnorm(6,6.5,1),rnorm(3,6.5,1.5),

    rnorm(12,8,2),rnorm(12,10,2),rnorm(10,10,3),

    rnorm(5,2,1),rnorm(4,2.5,1),rnorm(5,2.5,1.5),

    rnorm(9,10,2),rnorm(6,12,2),rnorm(7,12,3))

tablo <- data.frame(tailles, plantes, conditions)




barplot(by(tablo$taille,tablo[,2:3],mean),beside=T, col=terrain.colors(3),legend=T)




summary(aov(tailles~conditions+plantes,data=tablo))

            Df Sum Sq Mean Sq F value  Pr(>F)   

conditions   1   90.7   90.71   7.329 0.00822 **

plantes      2   67.6   33.81   2.732 0.07091 . 

Residuals   84 1039.6   12.38                   

---

Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


moyenne_par_condition <- by(tablo$taille,tablo$conditions,mean)

moyenne_par_condition <- rep(moyenne_par_condition,each=3)

moyenne_par_barres <- by(tablo$taille,tablo[,2:3],mean)

moyenne_par_barres <- moyenne_par_barres / moyenne_par_condition

moyenne_par_barres <- moyenne_par_barres + mean(by(tablo$taille,tablo[,2:3],mean))


barplot(moyenne_par_barres,beside=T, col=terrain.colors(3),legend=T)



# Traiter les données brutes pour faire un travail sur ajustement de moyennes

moy_global <- moyenne_par_barres + mean(by(tablo$taille,tablo[,2:3],mean))

tailles_transfo <- tailles

for (i in unique(plantes)) {

for (j in unique(conditions)) {

tailles_transfo[plantes==i&conditions==j] <- tailles_transfo[plantes==i&conditions==j]/mean(by(tailles[conditions==j],plantes[conditions==j],mean))* moy_global 

}

}


summary(aov(tailles_transfo~tablo$conditions+tablo$plantes))



                 Df Sum Sq Mean Sq F value  Pr(>F)   

tablo$conditions  1    0.1    0.07   0.004 0.94975   

tablo$plantes     2  205.1  102.57   6.292 0.00284 **

Residuals        84 1369.3   16.30                   

---

Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Maintenant que les moyennes ont été ajustées, on voit maintenant un effet net de la variété de plantes sur la taille. Correction faite ! C'est ce que fera une anova avec interaction.

3- Effet sur les proportions en tenant compte d'une troisième variable - test de Khi² sur données stratifiées - test de Cochrane-Mantel-Haenszel

Le test de Cochran-Mantel-Haenszel permet de faire un chi2 sur des données stratifiées.

Exemple : je souhaite comparer les proportions de malades chez des sportifs et non sportifs. Sauf que j'ai des proportions variables de fumeurs dans ces groupes, je dois donc équilibrer (ajuster mes échantillons) pour que l'effet tabac ne masque l'effet sport.

Cas n°1 - pas d'effet significatif global alors qu'un effet sur les strates

Le traitement semble ne pas avoir d'effet au niveau global alors qu'il y aurait des différences si on analysait séparément les individus au diagnostic positif ou non. Prenons cet exemple bien détaillé sur ce site d'une analyse clinique.

pronostic <- c(rep("Bon",400),rep("Mauvais",40))

traitement <- c(rep("Traité",200),rep("Non-traité",200),rep("Traité",20),rep("Non-traité",20))

survie  <- c(rep("Décès",5),rep("Survie",195),rep("Décès",10),rep("Survie",190),

rep("Décès",6),rep("Survie",14),rep("Décès",12),rep("Survie",8))

ftable(pronostic,traitement,survie)


chisq.test(survie,traitement)

# p-value de 0.07 =  pas d'effet du traitement sur la survie.


On va conclure que le traitement ne marche pas et pourtant, à l'œil, à l'échelle de chaque groupe diagnostiqué, le traitement double pourtant la survie des individus. On passe d'une mortalité de 10/200 à 5/200 pour la diagnostic "Bon" contre 12/20 pour 6/20 lorsque le diagnostic est "Mauvais".

                     survie Décès Survie

pronostic traitement                    

Bon       Non-traité           10    190

          Traité                5    195

Mauvais   Non-traité           12      8

          Traité                6     14

Certains argumenteraient qu'il faut traiter les deux groupes pronostiquées différemment, mais cela ici ne va rien donner.

Faire des analyse de khi2 (ou mieux encore, test G) séparément pour chaque diagnosti risque de réduire la taille des échantillons et de passer à côté des résultats !

chisq.test(survie[pronostic=="Bon"],traitement[pronostic=="Bon"]) # p-value de 0,29

chisq.test(survie[pronostic=="Mauvais"],traitement[pronostic=="Mauvais"]) # p-value de 0,11

Et pourtant, si je fais un test de de Cochran-Mantel-Haenszel, je ne vais pas tirer ces conclusions.

mantelhaen.test(survie, traitement, pronostic) # p-value, 0.04

Clairement, le traitement semble avoir un effet si on tient compte de la strate que représente le pronostic.

Attention l'ordre des variables avec ce test mantelhaen.test() !

mantelhaen.test(survie,  pronostic, traitement)  # Lien entre survie et pronostic en tenant compte du traitement 

# p-value très faible, quel que soit le traitement, le pronostic influence fortement la survie.

mantelhaen.test(traitement,  pronostic, survie)  # Lien entre traitement et pronostic selon la survie

# p-value de 0,4 , pas de lien entre traitement et pronostic quel que soit la survie - les scientifiques n'ont pas changer les modalités de traitement en fonction du pronostic.

Mais comment penser à faire ce test de Cochran-Mantel-Haenszel ici ? Eh bien tout simplement en vérifiant que le pronostic a un effet sur la survie. Si le pronostic a un effet sur la survie, alors on doit tenir compte de cette strate lorsque l'on souhaite voir un effet du traitement sur la survie.

chisq.test(survie, pronostic) # Lien très significatif entre survie et pronostic

Cas n°2 - un effet serait perçu au niveau global alors qu'il n'y a pas d'effet sur les strates

L'échantillon 1 semble différent de l'échantillon 2 tout simplement parce que les proportions des filles et garçons changent d'un échantillon à l'autre.

Prenons un exemple, on simule 2 échantillons tirés d'une même population où les filles font moins de sport que les garçons (on va caricaturer un peu pour avoir des résultats explosifs). En réalité, 60% des étudiantes à mon travail se déclarent étudiantes contre 72% pour les garçons.

Problème, mes échantillons n'ont pas les mêmes proportions de filles.

n1 <- 30 ; n2 <- 30

echantillon <- c(rep("Echantillon 1",n1),rep("Echantillon 2",n2))

# l'échantillon 1 a environ 20% de Filles - l'échantillon 2 a 80% de filles.

sexe <- c(sample(c("F","M"),n1,replace=T,prob=c(.2,.8)),sample(c("F","M"),n1,replace=T,prob=c(.8,.2)))

# Simulons le sport où 20% environ des filles font du sport et 80% des hommes

sport <- sexe

sport[sexe=="F"] <- sample(c("O","N"),length(sport[sexe=="F"]),replace=T,prob=c(.2,.8))

sport[sexe=="M"] <- sample(c("O","N"),length(sport[sexe=="M"]),replace=T,prob=c(.8,.2))

table(sport,echantillon)

Ce tableau montre autant de sportifs que de non sportifs dans les 2 échantillons. Sans surpris un Khi2 va détecter une très grande différence entre les échantillons 1 et 2.

chisq.test(sport,echantillon)$p.value

# p-value très faible : échantillons 1 et 2 différents.

echantillon

sport Echantillon 1 Echantillon 2

    N             9            21

    O            21             9

table(sport,echantillon)

Ce tableau montre autant de sportifs que de non sportifs dans les 2 échantillons. Sans surpris un Khi2 va détecter une très grande différence entre les échantillons 1 et 2.

chisq.test(sport,echantillon)$p.value

# p-value très faible : échantillons 1 et 2 différents.

echantillon

sport Echantillon 1 Echantillon 2

    N             9            21

    O            21             9

Si je dois en tirer une conclusion, je dirais aussitôt que les échantillons 1 et 2 ont des proportions de sportifs/non sportifs différentes comme si on avait prélevé les individus d'une collège lambda ou d'un collège section sportive.

En réalité, ces échantillons viennent de la même population ! C'est juste la proportions des deux sexes qui change, peut-être parce que s'il s'agit de classe, l'option a eu un effet sur cette répartition.

Si je faisais des tests de Khi2 sur chaque sexe, je ne verrais pas de répartition différente du sport d'un échantillon à l'autre.

chisq.test(sport[sexe=="F"],echantillon[sexe=="F"])

table(sport[sexe=="F"],echantillon[sexe=="F"])

chisq.test(sport[sexe=="M"],echantillon[sexe=="M"])

table(sport[sexe=="M"],echantillon[sexe=="M"])

Sauf, que ce faisant, je réduis la taille de mes échantillons ! De sorte que je peux passer à côté des bonnes conclusions.

Le test de Cochran-Mantel-Haenszel permet justement de tenir comptes des strates (filles et garçons) pour ne pas tirer des conclusions attives.

Sans surprise, pas de répartition différentielle des activités selon les échantillons.

mantelhaen.test(sport,echantillon,sexe)

Mais comment j'aurais pu deviner qu'il fallait faire ce test ? En vérifiant s'il y a une répartition différentielle du sexe entre les échantillons.

chisq.test(sport,sexe)

chisq.test(echantillon,sexe)

Ma fonction corrigraph() sous {KefiR} l'aurait fait directement.

tablo <- data.frame(sport,echantillon,sexe)

library(KefiR)

corrigraph(tablo,prop=T)

Cette figure montre directement des liens statistiques entre les variables catégorielles sexe, sport et echantillon.

A développer

test du logrank stratifié pour les données de survie, test t stratifié pour les variables continues.  

 Source impérative sur les données cliniques : http://www.txrating.org/spc/polycop/Ajustement%20statistique.htm#:~:text=L'ajustement%20permet%20de%20prendre,variabilit%C3%A9%20du%20crit%C3%A8re%20de%20jugement