Tuto@Mate, 21 mai 2024
IRD, Ceped
comptage
Descendance atteinte par des femmes à l’âge de 30 ans
jeu de données fecondite
fourni par le package {questionr}
contient 3 tables : menages
, femmes
et enfants
pos variable label col_type missing values
1 id_enfant Identifiant de l'enfant dbl 0
2 id_femme Identifiant de la mère dbl 0
3 date_naissance Date de naissance date 0
4 sexe Sexe de l'enfant dbl+lbl 0 [1] masculin
[2] féminin
5 survie L'enfant est-il toujours en~ dbl+lbl 0 [0] non
[1] oui
6 age_deces Age au décès (en mois) dbl 1442
Calcul de l’âge exact des mères à la naissance avec lubridate::time_length()
Calcul de l’âge des femmes au moment de l’enquête et recodage du niveau d’éducation
t.test()
) et nombre d’observations (astuce en utilisant length()
) + test de comparaison (one-way ANOVA).library(gtsummary)
theme_gtsummary_language("fr",
decimal.mark = ",", big.mark = " "
)
mean_cil <- function(x, conf.level = 0.95) {
t.test(x, conf.level = conf.level)$conf.int[1]
}
mean_cih <- function(x, conf.level = 0.95) {
t.test(x, conf.level = conf.level)$conf.int[2]
}
femmes30p |>
tbl_continuous(
variable = enfants_avt_30,
include = c(educ2, milieu, region),
statistic = ~ "{mean} [{mean_cil} - {mean_cih}] ({sd}) [n={length}]",
digits = ~ c(2, 2, 2, 2, 0)
) |>
add_p(test = ~ "aov") |>
bold_labels()
Caractéristique | N = 8041 | p-valeur2 |
---|---|---|
Niveau d'éducation | 0,036 | |
aucun | 0,25 [0,20 - 0,30] (0,61) [n=534] | |
primaire | 0,30 [0,20 - 0,39] (0,62) [n=171] | |
secondaire/supérieur | 0,11 [0,05 - 0,17] (0,32) [n=99] | |
Milieu de résidence | 0,017 | |
urbain | 0,18 [0,12 - 0,23] (0,49) [n=307] | |
rural | 0,28 [0,22 - 0,34] (0,63) [n=497] | |
Région de résidence | 0,2 | |
Nord | 0,22 [0,16 - 0,28] (0,51) [n=300] | |
Est | 0,31 [0,20 - 0,43] (0,65) [n=118] | |
Sud | 0,28 [0,17 - 0,39] (0,74) [n=178] | |
Ouest | 0,20 [0,13 - 0,26] (0,49) [n=208] | |
1 enfants_avt_30: Moyenne [mean_cil - mean_cih] (ET) [n=length] | ||
2 Analyse de la variance à un facteur |
stats::glm()
en précisant family = poisson
stats::step()
risque relatif
Start: AIC=1013.81
enfants_avt_30 ~ educ2 + milieu + region
Df Deviance AIC
- region 3 686.46 1010.6
<none> 683.62 1013.8
- milieu 1 686.84 1015.0
- educ2 2 691.10 1017.3
Step: AIC=1010.65
enfants_avt_30 ~ educ2 + milieu
Df Deviance AIC
<none> 686.46 1010.6
- milieu 1 691.30 1013.5
- educ2 2 693.94 1014.1
Caractéristique | IRR1 | 95% IC1 | p-valeur |
---|---|---|---|
Niveau d'éducation | |||
aucun | — | — | |
primaire | 1,25 | 0,90 – 1,72 | 0,2 |
secondaire/supérieur | 0,53 | 0,27 – 0,96 | 0,052 |
Milieu de résidence | |||
urbain | — | — | |
rural | 1,42 | 1,04 – 1,98 | 0,032 |
1 IRR = rapport de taux d’incidence, IC = intervalle de confiance |
Warning: Maximum value of original data is not included in the
replicated data.
Model may not capture the variation of the data.
Similaire au modèle de Poisson
Fonction de lien logarithmique
Plus de souplesse : variance modélisée comme une relation linéaire de la moyenne
glm()
mais en indiquant family = quasipoisson
AIC non disponible => on ne peut pas utiliser step()
Coefficients identiques au modèle de Poisson mais intervalles de confiance plus larges
Caractéristique | IRR1 | 95% IC1 | p-valeur |
---|---|---|---|
Niveau d'éducation | |||
aucun | — | — | |
primaire | 1,25 | 0,85 – 1,81 | 0,2 |
secondaire/supérieur | 0,53 | 0,23 – 1,05 | 0,10 |
Milieu de résidence | |||
urbain | — | — | |
rural | 1,42 | 0,99 – 2,10 | 0,067 |
1 IRR = rapport de taux d’incidence, IC = intervalle de confiance |
# Overdispersion test
dispersion ratio = 1.371
Pearson's Chi-Squared = 1096.575
p-value = < 0.001
Le modèle de quasi-Poisson n’a pas suffi à régler le problème de surdispersion dans le cadre de notre exemple.
Fonction de lien logarithmique
Spécification quadratique de la variance (i.e. selon la moyenne et le carré de la moyenne)
N’est pas disponible via glm()
Recours à la fonction MASS::glm.nb()
(syntaxe similaire)
AIC défini => on peut utiliser step()
Start: AIC=979.1
enfants_avt_30 ~ educ2 + milieu + region
Df Deviance AIC
- region 3 462.89 975.01
<none> 460.98 979.10
- milieu 1 463.29 979.41
- educ2 2 466.11 980.22
Step: AIC=975
enfants_avt_30 ~ educ2 + milieu
Df Deviance AIC
<none> 460.14 975.00
- milieu 1 463.37 976.24
- educ2 2 465.54 976.40
Caractéristique | IRR1 | 95% IC1 | p-valeur |
---|---|---|---|
Niveau d'éducation | |||
aucun | — | — | |
primaire | 1,23 | 0,82 – 1,82 | 0,3 |
secondaire/supérieur | 0,53 | 0,25 – 1,03 | 0,074 |
Milieu de résidence | |||
urbain | — | — | |
rural | 1,41 | 0,97 – 2,06 | 0,076 |
1 IRR = rapport de taux d’incidence, IC = intervalle de confiance |
# Comparison of Model Performance Indices
Name | Model | AIC (weights) | BIC (weights) | Nagelkerke's R2 | RMSE
---------------------------------------------------------------------------------
mod1_poisson | glm | 1010.7 (<.001) | 1029.4 (<.001) | 0.033 | 0.579
mod1_nb | negbin | 977.0 (>.999) | 1000.5 (>.999) | 0.032 | 0.579
une variable binaire peut-être modélisée avec un modèle de comptage, en considérant que la personne a vécu 0 fois ou 1 fois l’évènement d’intérêt
permet de calculer des prevalence ratios (ou risques relatifs) plutôt que des odds ratio
data(hdv2003, package = "questionr")
d <- hdv2003 |>
mutate(
groupe_ages = age |>
cut(
c(18, 25, 45, 65, 99),
right = FALSE, include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans", "45-64 ans", "65 ans et plus")
)
) |>
set_variable_labels(
sport = "Pratique un sport ?",
sexe = "Sexe",
groupe_ages = "Groupe d'âges",
heures.tv = "Heures de télévision / jour"
)
contrasts(d$sexe) <- contr.treatment(2, base = 2)
Régression logistique
nativement avec glm(family = binomial(link = "log"))
mais peut avoir des difficultés à converger
nécessité d’initialiser les coefficients avec ceux d’un modèle de Poisson
lien logarithmique => coefficients interprétables comme des risques relatifs
# Comparison of Model Performance Indices
Name | Model | AIC (weights) | BIC (weights) | RMSE | Nagelkerke's R2 | Tjur's R2
---------------------------------------------------------------------------------------------
mod2_binomial | glm | 2346.3 (0.642) | 2379.8 (0.642) | 0.447 | | 0.132
mod2_poisson | glm | 2748.8 (<.001) | 2782.4 (<.001) | 0.447 | 0.158 |
mod2_log | glm | 2347.4 (0.358) | 2381.0 (0.358) | 0.447 | 0.176 |
Prenons un premier exemple à partir du jeux de données gtsummary::trial
qui contient des informations sur 200 patients atteints d’un cancer. Il contient entre autre les variables suivantes :
death : variable binaire (0/1) indiquant si le patient est décédé
ttdeath : le nombre de mois d’observation jusqu’au décès (si décès) ou jusqu’à la fin de l’étude (si survie)
stage : un facteur indiquant le stade T de la tumeur (plus la valeur est élevée, plus la tumeur est grosse)
trt : le traitement reçu par le patient (A ou B)
response : une variable binaire (0/1) indiquant si le traitement a eu un effet sur la tumeur (diminution)
Nous nous intéressons donc aux facteurs associés au taux de mortalité (death/ttdeath) : nous allons donc réaliser un modèle de Poisson sur la variable death en ajoutant un décalage (offset) correspondant à log(ttdeath).
percent2 <- purrr::partial(style_percent, digits = 1)
trial <- gtsummary::trial |>
set_value_labels(
response = c(no = 0, yes = 1)
) |>
unlabelled()
trial |>
tbl_custom_summary(
include = c(stage, trt, response),
stat_fns = ~ ratio_summary("death", "ttdeath"),
statistic = ~"{ratio}/100pm [{conf.low}; {conf.high}] ({num}/{denom})",
digits = ~ c(percent2, percent2, percent2, 0, 0),
overall_row = TRUE,
overall_row_label = "Overall"
) |>
bold_labels()
Caractéristique | N = 2001 |
---|---|
Overall | 2,85/100pm [2,35; 3,43] (112/3 925) |
T Stage | |
T1 | 2,17/100pm [1,39; 3,23] (24/1 105) |
T2 | 2,48/100pm [1,63; 3,61] (27/1 089) |
T3 | 2,58/100pm [1,62; 3,91] (22/852) |
T4 | 4,43/100pm [3,15; 6,06] (39/879) |
Chemotherapy Treatment | |
Drug A | 2,62/100pm [1,96; 3,44] (52/1 983) |
Drug B | 3,09/100pm [2,36; 3,98] (60/1 942) |
Tumor Response | 1,85/100pm [1,19; 2,76] (24/1 296) |
Manquant | 7 |
1 ratio/100pm [conf.low; conf.high] (num/denom) |
Intervalles de confiance à 95% réalisés avec poisson.test()
.
Pas de méthode add_p()
disponible ici -> nous verrons plus loin la réalisation de modèles univariables.
Pour ajouter un décalage, nous avons deux syntaxes équivalentes : soit en ajoutant offset(log(ttdeath))
directement à l’équation du modèle, soit en passant à glm()
l’argument offset = log(ttdeath)
.
L’exponentielle des coefficients s’interprète comme un incidence risk ratio (IRR).
Caractéristique | N | IRR1 | 95% IC1 | p-valeur |
---|---|---|---|---|
Chemotherapy Treatment | 200 | 0,4 | ||
Drug A | — | — | ||
Drug B | 1,18 | 0,81 – 1,71 | ||
T Stage | 200 | 0,025 | ||
T1 | — | — | ||
T2 | 1,14 | 0,66 – 1,99 | ||
T3 | 1,19 | 0,66 – 2,12 | ||
T4 | 2,04 | 1,24 – 3,44 | ||
Tumor Response | 193 | 0,008 | ||
no | — | — | ||
yes | 0,56 | 0,35 – 0,86 | ||
1 IRR = rapport de taux d’incidence, IC = intervalle de confiance |
Nous allons considérer le jeu de données MASS::Insurance
qui provient d’une compagnie d’assurance américaine et porte sur le troisième trimestre 1973.
Il indique le nombre de demande d’indemnisations (Claims) parmi les assurés pour leur voiture (Holders) en fonction de leur groupe d’âges (Age) et de la taille de la cylindrée de la voiture (Group).
Nous cherchons à identifier les facteurs associés au taux de réclamation.
d <- MASS::Insurance
d$Age <- factor(d$Age, ordered = FALSE)
d$Group <- factor(d$Group, ordered = FALSE)
mod4_poisson <- glm(
Claims ~ Age + Group + offset(log(Holders)),
family = poisson,
data = d
)
mod4_poisson |>
performance::check_overdispersion()
# Overdispersion test
dispersion ratio = 1.140
Pearson's Chi-Squared = 65.003
p-value = 0.218
Le taux de réclamation diminue avec l’âge de l’assuré (il est 40% moindre pour les assurés de plus de 35 ans par rapport à ceux de moins de 25 ans) et augmente avec la cylindrée de la voiture (il est 80% plus élevé pour les véhicules avec une cylindrée de plus de 2 litres par rapport aux véhicules avec une cylindrée de moins d’1 litre).
Nous allons utiliser un jeu de données issu d’un article de Partha Deb et Pravin K. Trivedi. Ce jeu de données porte sur 4406 individus âgés de 66 ans ou plus et couvert par le programme américain Medicare.
L’analyse va porter sur la demande de soins, mesurée ici à travers le nombre de visites médicales (ofp).
Pour les variables explicatives, nous allons considérer le genre du patient (gender), le fait de disposer d’une assurance privée (privins), la santé perçue (health) et le nombre de conditions chroniques de l’assuré.
load(url("https://github.com/larmarange/guide-R/raw/main/analyses_avancees/ressources/DebTrivedi.rda"))
d <- DebTrivedi |>
mutate(
gender = gender |> fct_recode("femme" = "female", "homme" = "male"),
privins = privins |> fct_recode("non" = "no", "oui" = "yes"),
health = health |> fct_recode("pauvre" = "poor", "moyenne" = "average", "excellente" = "excellent")
) |>
set_variable_labels(
ofp = "Nombre de visites médicales",
gender = "Genre de l'assuré",
privins = "Dispose d'une assurance privée ?",
health = "Santé perçue",
numchron = "Nombre de conditions chroniques"
)
contrasts(d$health) <- contr.treatment(3, base = 2)
# Overdispersion test
dispersion ratio = 1.050
p-value = 0.36
sur-représentés dans nos donnéespar rapport à une distribution négative binomiale.
On peut choisir des variables différentes pour chaque sous-modèle (avec |
), voire faire un modèle simple avec seulement un intercept pour la composante logistique.
On peut également utiliser un modèle négatif binomial avec dist = "negbin"
.
mod5_zip_simple <- pscl::zeroinfl(
ofp ~ gender + privins + health + numchron | 1,
data = d
)
mod5_zinb <- pscl::zeroinfl(
ofp ~ gender + privins + health + numchron,
dist = "negbin",
data = d
)
performance::compare_performance(
mod5_nb,
mod5_zip_simple,
mod5_zip,
mod5_zinb,
metrics = "AIC"
)
# Comparison of Model Performance Indices
Name | Model | AIC (weights)
--------------------------------------------
mod5_nb | negbin | 24505.7 (<.001)
mod5_zip_simple | zeroinfl | 33308.5 (<.001)
mod5_zip | zeroinfl | 33014.2 (<.001)
mod5_zinb | zeroinfl | 24380.9 (>.999)
tbl_log <- mod5_zinb |>
tbl_regression(
tidy_fun = broom.helpers::tidy_zeroinfl,
component = "zero_inflated",
exponentiate = TRUE
)
tbl_nb <- mod5_zinb |>
tbl_regression(
tidy_fun = broom.helpers::tidy_zeroinfl,
component = "conditional",
exponentiate = TRUE
)
list(tbl_log, tbl_nb) |>
tbl_merge(
c(
"**OR (régression logistique)**",
"**RR (négatif binomial)**"
)
) |>
bold_labels()
Caractéristique | OR (régression logistique) | RR (négatif binomial) | ||||
---|---|---|---|---|---|---|
exp(Beta) | 95% IC1 | p-valeur | exp(Beta) | 95% IC1 | p-valeur | |
Genre de l'assuré | ||||||
femme | — | — | — | — | ||
homme | 1,82 | 1,21 – 2,72 | 0,004 | 0,93 | 0,88 – 0,99 | 0,031 |
Dispose d'une assurance privée ? | ||||||
non | — | — | — | — | ||
oui | 0,22 | 0,15 – 0,34 | <0,001 | 1,23 | 1,14 – 1,33 | <0,001 |
Santé perçue | ||||||
pauvre | 1,18 | 0,51 – 2,70 | 0,7 | 1,38 | 1,26 – 1,51 | <0,001 |
moyenne | — | — | — | — | ||
excellente | 0,91 | 0,45 – 1,82 | 0,8 | 0,71 | 0,63 – 0,81 | <0,001 |
Nombre de conditions chroniques | 0,29 | 0,20 – 0,41 | <0,001 | 1,16 | 1,13 – 1,19 | <0,001 |
1 IC = intervalle de confiance |
sautqui distingue les valeurs nulles des valeurs positives : les modèles hurdle en anglais.
On utilisera simplement pscl::hurdle()
à la place de pscl::zeroinfl()
.
Sur les modèles de comptage :
Modèles de comptage : https://larmarange.github.io/guide-R/analyses_avancees/modeles-comptage.html
Modèles d’incidence : https://larmarange.github.io/guide-R/analyses_avancees/modeles-incidence.html
Modèles zero-inflated et hurdle : https://larmarange.github.io/guide-R/analyses_avancees/modeles-zero-inflated.html
Autres ressources utiles :
Étiquettes de valeurs : https://larmarange.github.io/guide-R/manipulation/etiquettes-valeurs.html
Sélection pas à pas d’un modèle : https://larmarange.github.io/guide-R/analyses/selection-modele-pas-a-pas.html
Prédictions marginales, contrastes marginaux & effets marginaux : https://larmarange.github.io/guide-R/analyses/estimations-marginales.html
Contrastes (variables catégorielles) : https://larmarange.github.io/guide-R/analyses/contrastes.html
Calcul avec des dates : https://larmarange.github.io/guide-R/manipulation_avancee/dates.html
Prise en compte des poids d’enquêtes et du plan d’échantillonnage : plusieurs chapitres et sous-sections de chapitre
Joseph Larmarange · Modèles de comptage · Tuto@Mate