1 Objectifs de la séance

Cette analyse a pour objectif principal d’estimer l’effet du traitement maternel par AZT, comparativement au placebo, sur la transmission du VIH à l’enfant.

Les participants apprendront à :

  • préparer et décrire une base issue d’un essai clinique randomisé ;
  • étudier les données manquantes et les statuts VIH indéterminés ;
  • produire des tableaux et graphiques prêts à publier ;
  • calculer et comparer le risque relatif (RR) et l’odds ratio (OR) ;
  • réaliser une analyse stratifiée ;
  • estimer des RR ajustés par régression log-binomiale ou par régression de Poisson modifiée ;
  • étudier le délai jusqu’à l’infection et le délai jusqu’au décès ;
  • conduire des analyses de sensibilité.

Question principale : l’administration de l’AZT à la mère réduit-elle le risque d’infection VIH de l’enfant par rapport au placebo ?

Contexte scientifique et méthodologique de l’étude

1.1 Contexte

Au milieu des années 1990, la transmission mère-enfant du VIH constituait une cause importante d’infection pédiatrique en Afrique subsaharienne. La zidovudine, ou AZT, avait déjà montré une efficacité élevée dans des contextes où l’allaitement maternel était peu fréquent, mais les schémas thérapeutiques longs et coûteux étaient difficilement applicables dans de nombreux systèmes de santé africains. L’essai DITRAME ANRS 049a a donc évalué un schéma court de zidovudine administré à la mère dans deux villes d’Afrique de l’Ouest : Abidjan, en Côte d’Ivoire, et Bobo-Dioulasso, au Burkina Faso.

L’essai original était multicentrique, randomisé, en double aveugle et contrôlé par placebo. Le recrutement ne correspondait pas à un tirage aléatoire dans la population générale. Les femmes enceintes fréquentant les consultations prénatales sélectionnées étaient systématiquement informées et se voyaient proposer un conseil prétest et un dépistage du VIH lorsqu’elles avaient au moins 18 ans, se présentaient avant 32 semaines de grossesse, résidaient dans la ville et prévoyaient d’accoucher dans une structure participante. Les femmes ayant une infection VIH-1 confirmée, ayant donné leur consentement écrit et satisfaisant aux critères biologiques étaient ensuite incluses entre 36 et 38 semaines de grossesse.

Les principales causes d’exclusion étaient une anémie sévère, une neutropénie importante, une fonction hépatique anormale ou une drépanocytose de type SS, SC ou CC. La sélection des participantes reposait donc sur l’éligibilité clinique et le consentement, tandis que la randomisation concernait uniquement l’attribution du traitement.

La liste de randomisation était préparée par un statisticien indépendant. Une randomisation par blocs de dix, stratifiée selon le centre, était utilisée. Les traitements étaient conditionnés dans des emballages scellés, numérotés séquentiellement et préparés par une pharmacie centrale indépendante, ce qui permettait de maintenir l’aveugle des participantes et des équipes.

Selon la phase de l’essai, le schéma maternel correspondait à 250 ou 300 mg de zidovudine deux fois par jour avant l’accouchement, une dose de charge de 500 ou 600 mg au début du travail, puis 250 ou 300 mg deux fois par jour pendant sept jours après l’accouchement. Le groupe témoin recevait un placebo d’apparence identique. Aucun traitement antirétroviral n’était administré au nouveau-né dans ce protocole.

Le critère principal était l’infection VIH-1 de l’enfant, déterminée par des tests PCR séquentiels, notamment entre les jours 1 et 8, puis aux jours 45, 90 et 180. Le premier test positif servait à approcher le moment du diagnostic. Les analyses principales étaient conduites selon le principe de l’intention de traiter, c’est-à-dire selon le groupe attribué par la randomisation, indépendamment de l’observance réelle. Les probabilités d’infection étaient estimées par la méthode de Kaplan-Meier, les courbes comparées par le test du log-rank et les analyses multivariées temporelles réalisées par modèle de Cox. Un seul enfant était retenu par grossesse multiple afin de préserver l’indépendance des observations.

La base pédagogique TME_Africa utilisée ici contient 401 couples mère-enfant et ne représente qu’un extrait simplifié des données de DITRAME. Le script conserve les variables disponibles et reproduit une démarche pédagogique proche des publications : description des groupes, estimation du RR, comparaison avec l’OR, analyses stratifiées, RR ajustés, Kaplan-Meier et modèles de Cox. Il ne constitue toutefois pas une reproduction exacte des analyses publiées. En particulier, les publications prolongées ont utilisé des méthodes adaptées aux temps d’infection connus par intervalle et, dans certaines analyses, aux risques concurrents. Le seuil de CD4 de 350 cellules/mm³ retenu dans ce script est conservé pour rester fidèle au code pédagogique ; l’analyse publiée à 24 mois a principalement présenté des résultats selon le seuil de 500 cellules/mm³.

1.2 Objectifs analytiques de la session pratique

L’objectif principal est d’estimer l’efficacité du traitement maternel par AZT sur la transmission du VIH à l’enfant. Les objectifs secondaires sont de :

  1. décrire les caractéristiques initiales des participantes et vérifier l’équilibre descriptif entre les groupes randomisés ;
  2. comparer le risque cumulé d’infection entre les groupes AZT et placebo ;
  3. montrer la différence d’interprétation entre le risque relatif et l’odds ratio ;
  4. examiner la stabilité de l’effet de l’AZT selon le site et le niveau de CD4 maternel ;
  5. estimer des risques relatifs ajustés par une régression de Poisson modifiée avec variance robuste lorsque le modèle log-binomial ne converge pas ;
  6. comparer le délai jusqu’à l’infection et le délai jusqu’au décès entre les groupes ;
  7. évaluer l’influence des statuts VIH indéterminés par des analyses de sensibilité.

1.3 Principes méthodologiques à retenir

  • La randomisation constitue la base de la comparaison causale entre l’AZT et le placebo.
  • Le RR brut est l’estimation principale de l’effet du traitement sur le risque cumulé d’infection.
  • Les variables maternelles mesurées à l’inclusion sont des facteurs pronostiques ; l’ajustement vise principalement à améliorer la précision et à explorer l’hétérogénéité du risque.
  • Le HR apporte une information temporelle : il compare le taux instantané de survenue de l’événement pendant le suivi.
  • Le statut VIH indéterminé ne doit être assimilé ni à une infection ni à une absence d’infection.
  • La date de diagnostic est utilisée comme approximation du moment de l’infection dans cette application pédagogique. Dans les publications originales, des méthodes tenant compte de l’intervalle entre tests et, pour le suivi prolongé, des risques concurrents ont également été utilisées.

Références méthodologiques principales

  • Dabis F, Msellati P, Meda N, et al. 6-month efficacy, tolerance, and acceptability of a short regimen of oral zidovudine to reduce vertical transmission of HIV in breastfed children in Côte d’Ivoire and Burkina Faso: a double-blind placebo-controlled multicentre trial. Lancet. 1999;353:786–792.
  • Dabis F, Elenga N, Meda N, et al. 18-month mortality and perinatal exposure to zidovudine in West Africa. AIDS. 2001;15:771–779.
  • Leroy V, Karon JM, Alioum A, et al. Twenty-four month efficacy of a maternal short-course zidovudine regimen to prevent mother-to-child transmission of HIV-1 in West Africa. AIDS. 2002;16:631–641.

2 Packages utilisés

Le script utilise directement les packages nécessaires. Installez ceux qui manquent avant de compiler le document.

library(tidyverse)
library(readxl)
library(lubridate)
library(questionr)
library(naniar)
library(gtsummary)
library(gt)
library(epiR)
library(epitools)
library(broom)
library(survival)
library(survminer)
library(scales)
library(sandwich)
library(lmtest)
library(GGally)

3 Importation et découverte de la base

tme_raw <- read_excel("TME_Africa.xls")
# Dimensions de la base
nrow(tme_raw)
## [1] 401
ncol(tme_raw)
## [1] 13
# Noms des variables
names(tme_raw)
##  [1] "ID"            "TTTGRP"        "AGEINC"        "CD4VAL"       
##  [5] "NIVINSTRUC"    "PARITY"        "HIVSTATUS"     "DATINF"       
##  [9] "DATBIRTH"      "DTH_CH"        "DATE_DTH"      "DATE_LAST_BIO"
## [13] "SITE"
# Premières observations
tme_raw |> head()
## # A tibble: 6 × 13
##   ID    TTTGRP AGEINC CD4VAL NIVINSTRUC PARITY HIVSTATUS DATINF             
##   <chr>  <dbl>  <dbl>  <dbl>      <dbl>  <dbl>     <dbl> <dttm>             
## 1 B0141      0     28    518          0      1         1 1996-01-07 00:00:00
## 2 A0051      0     21    638          0      1         1 1996-01-29 00:00:00
## 3 B0231      0     27     14          1      1         1 1996-02-17 00:00:00
## 4 A0241      1     21    412          0      0         1 1996-04-02 00:00:00
## 5 B0191      1     30    283          0      5         1 1996-04-18 00:00:00
## 6 B0341      0     37   1817          1      4         1 1996-04-24 00:00:00
## # ℹ 5 more variables: DATBIRTH <dttm>, DTH_CH <dbl>, DATE_DTH <dttm>,
## #   DATE_LAST_BIO <dttm>, SITE <chr>

3.1 Dictionnaire simplifié

Variable Signification
ID Identifiant de la mère
SITE Site de suivi : Abidjan ou Bobo-Dioulasso
TTTGRP Groupe maternel : placebo ou AZT
AGEINC Âge maternel à l’inclusion
CD4VAL Nombre de CD4 maternels à l’inclusion
NIVINSTRUC Nombre d’années d’instruction
PARITY Nombre d’enfants nés vivants
HIVSTATUS Statut VIH de l’enfant
DATINF Date du diagnostic de l’infection
DATBIRTH Date de naissance de l’enfant
DTH_CH Décès de l’enfant
DATE_DTH Date du décès
DATE_LAST_BIO Date du dernier suivi biologique

4 Recodage et préparation des variables

Les variables de base sont recodées sous des intitulés directement interprétables. Le statut VIH codé 9 est considéré comme indéterminé et non comme « non infecté ».

tme <- tme_raw |>
  mutate(
    traitement = recode_factor(
      TTTGRP,
      `0` = "Placebo",
      `1` = "AZT"
    ),

    site_suivi = recode_factor(
      SITE,
      CI = "Abidjan, Côte d'Ivoire",
      BF = "Bobo-Dioulasso, Burkina Faso"
    ),

    statut_vih = recode_factor(
      HIVSTATUS,
      `0` = "Non infecté",
      `1` = "Infecté",
      `9` = "Indéterminé"
    ),

    statut_deces = recode_factor(
      DTH_CH,
      `0` = "Vivant",
      `1` = "Décédé"
    ),

    # Variable binaire pour les analyses : 1 = infecté, 0 = non infecté,
    # NA = statut indéterminé
    infection = case_when(
      HIVSTATUS == 1 ~ 1,
      HIVSTATUS == 0 ~ 0,
      TRUE ~ NA_real_
    ),

    deces = as.numeric(DTH_CH),

    niveau_instruction = case_when(
      NIVINSTRUC == 0 ~ "Aucune instruction",
      between(NIVINSTRUC, 1, 6) ~ "Primaire",
      between(NIVINSTRUC, 7, 12) ~ "Secondaire",
      TRUE ~ NA_character_
    ) |>
      factor(levels = c(
        "Aucune instruction", "Primaire", "Secondaire")),

    age_groupe = case_when(
      AGEINC >= 25 ~ "≥ 25 ans",
      AGEINC < 25 ~ "< 25 ans"
    ) |>
      factor(levels = c("≥ 25 ans", "< 25 ans")),

    cd4_groupe = case_when(
      CD4VAL >= 350 ~ "≥ 350 cellules/mm³",
      CD4VAL < 350 ~ "< 350 cellules/mm³"
    ) |>
      factor(levels = c("≥ 350 cellules/mm³", "< 350 cellules/mm³")),

    instruction_groupe = case_when(
      NIVINSTRUC >= 7 ~ "Secondaire ou supérieur",
      NIVINSTRUC < 7 ~ "Aucune ou primaire"
    ) |>
      factor(levels = c("Secondaire ou supérieur", "Aucune ou primaire")),

    parite_groupe = case_when(
      PARITY < 1 ~ "Nullipare",
      PARITY == 1 ~ "Primipare",
      PARITY >= 1 & PARITY <=4 ~ "Paucipare",
      PARITY > 4 ~ "Multipare"
    ) |>
      factor(levels = c("Nullipare", "Primipare","Paucipare","Multipare")),

    # Les dates de la base sont au format année/mois/jour
    DATINF = ymd(DATINF),
    DATBIRTH = ymd(DATBIRTH),
    DATE_DTH = ymd(DATE_DTH),
    DATE_LAST_BIO = ymd(DATE_LAST_BIO)
  )

# Vérification des nouveaux codages
freq(tme$traitement, total = TRUE)
##           n     %  val%
## Placebo 201  50,1  50,1
## AZT     200  49,9  49,9
## Total   401 100,0 100,0
freq(tme$statut_vih, total = TRUE)
##               n     %  val%
## Non infecté 291  72,6  72,6
## Infecté     100  24,9  24,9
## Indéterminé  10   2,5   2,5
## Total       401 100,0 100,0
freq(tme$site_suivi, total = TRUE)
##                                n     %  val%
## Abidjan, Côte d'Ivoire       236  58,9  58,9
## Bobo-Dioulasso, Burkina Faso 165  41,1  41,1
## Total                        401 100,0 100,0

La base pédagogique comprend 401 observations, dont 200 dans le groupe AZT et 201 dans le groupe placebo. Le statut VIH est connu pour 391 enfants : 100 infectés et 291 non infectés. 10 statuts sont indéterminés. Le CD4 maternel à l’inclusion est manquant pour 8 participantes, et 89 décès d’enfants sont enregistrés.

Aide à l’interprétation : infection = 1 signifie que l’enfant est infecté ; infection = 0 signifie qu’il est non infecté. Les enfants au statut indéterminé ont une valeur manquante pour cette variable analytique.

5 Contrôle de la qualité des données

5.1 Identifiants et doublons

tme |>
  count(ID) |>
  filter(n > 1)
## # A tibble: 0 × 2
## # ℹ 2 variables: ID <chr>, n <int>

Une sortie vide indique que chaque identifiant apparaît une seule fois.

5.2 Données manquantes

miss_var_summary(tme) |>
  gt() |>
  cols_label(
    variable = "Variable",
    n_miss = "Valeurs manquantes",
    pct_miss = "Pourcentage manquant"
  ) |>
  fmt_number(columns = pct_miss, decimals = 1) |>
  tab_header(title = "Répartition des données manquantes")
Répartition des données manquantes
Variable Valeurs manquantes Pourcentage manquant
DATE_DTH 312 77.8
DATINF 301 75.1
DATE_LAST_BIO 10 2.49
infection 10 2.49
CD4VAL 8 2.00
cd4_groupe 8 2.00
ID 0 0
TTTGRP 0 0
AGEINC 0 0
NIVINSTRUC 0 0
PARITY 0 0
HIVSTATUS 0 0
DATBIRTH 0 0
DTH_CH 0 0
SITE 0 0
traitement 0 0
site_suivi 0 0
statut_vih 0 0
statut_deces 0 0
deces 0 0
niveau_instruction 0 0
age_groupe 0 0
instruction_groupe 0 0
parite_groupe 0 0
gg_miss_var(tme, show_pct = TRUE) +
  labs(
    title = "Données manquantes par variable",
    x = NULL,
    y = "Nombre de valeurs manquantes"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )

5.3 Contrôle des dates

tme |>
  transmute(
    ID,
    infection_avant_naissance = !is.na(DATINF) & DATINF < DATBIRTH,
    deces_avant_naissance = !is.na(DATE_DTH) & DATE_DTH < DATBIRTH,
    suivi_avant_naissance = !is.na(DATE_LAST_BIO) & DATE_LAST_BIO < DATBIRTH
  ) |>
  summarise(
    infection_avant_naissance = sum(infection_avant_naissance),
    deces_avant_naissance = sum(deces_avant_naissance),
    suivi_avant_naissance = sum(suivi_avant_naissance)
  ) |>
  gt() |>
  tab_header(title = "Contrôle de cohérence chronologique")
Contrôle de cohérence chronologique
infection_avant_naissance deces_avant_naissance suivi_avant_naissance
0 0 0

Les éventuelles incohérences doivent être examinées à partir du protocole ou du dictionnaire original. Elles ne doivent pas être corrigées automatiquement sans justification.

6 Description générale de l’échantillon

6.1 Tableau descriptif

Les variables qualitatives sont présentées par leurs effectifs et pourcentages. Les variables quantitatives sont présentées dans une cellule unique par moyenne ± écart-type ou médiane [Q1–Q3].

tableau_descriptif <- tme |>
  select(
    site_suivi,
    traitement,
    statut_vih,
    statut_deces,
    AGEINC,
    CD4VAL,
    niveau_instruction,
    PARITY
  ) |>
  tbl_summary(
    label = list(
      site_suivi ~ "Site de suivi",
      traitement ~ "Groupe de traitement maternel",
      statut_vih ~ "Statut VIH de l'enfant",
      statut_deces ~ "Décès de l'enfant",
      AGEINC ~ "Âge maternel à l'inclusion, années",
      CD4VAL ~ "CD4 maternel, cellules/mm³",
      niveau_instruction ~ "Niveau d'instruction",
      PARITY ~ "Parité, enfants nés vivants"
    ),
    statistic = list(
      all_categorical() ~ "{n}|{p}",
      AGEINC ~ "{mean} ± {sd}|",
      CD4VAL ~ "{median} [{p25}–{p75}]|",
      PARITY ~ "{median} [{p25}–{p75}]|"
    ),
    digits = list(
      all_categorical() ~ c(0, 1),
      AGEINC ~ 1,
      CD4VAL ~ 0,
      PARITY ~ 0
    ),
    missing = "ifany",
    missing_text = "Données manquantes"
  ) |>
  modify_table_body(
    ~ .x |>
      separate_wider_delim(
        stat_0,
        delim = "|",
        names = c("frequence_absolue", "frequence_relative"),
        too_few = "align_start"
      ) |>
      mutate(
        frequence_relative = case_when(
          row_type == "level" & frequence_relative != "" ~
            frequence_relative,
          TRUE ~ frequence_relative
        )
      )
  ) |>
  modify_header(
    label ~ "**Variables et modalités**",
    frequence_absolue ~ "**Fréquence absolue/statistique**",
    frequence_relative ~ "**Fréquence relative (%)**"
  ) |>
  modify_column_alignment(
    columns = label,
    align = "left"
  ) |>
  modify_column_alignment(
    columns = c(frequence_absolue, frequence_relative),
    align = "center"
  ) |>
  bold_labels() |>
  modify_caption(
    "**Tableau II. Caractéristiques des couples mère-enfant inclus dans l'étude**"
  )

tableau_descriptif
Tableau II. Caractéristiques des couples mère-enfant inclus dans l’étude
Variables et modalités Fréquence absolue/statistique Fréquence relative (%)
Site de suivi

    Abidjan, Côte d'Ivoire 236 58,9
    Bobo-Dioulasso, Burkina Faso 165 41,1
Groupe de traitement maternel

    Placebo 201 50,1
    AZT 200 49,9
Statut VIH de l'enfant

    Non infecté 291 72,6
    Infecté 100 24,9
    Indéterminé 10 2,5
Décès de l'enfant

    Vivant 312 77,8
    Décédé 89 22,2
Âge maternel à l'inclusion, années 25,6 ± 5,4
CD4 maternel, cellules/mm³ 541 [359–741]
    Données manquantes 8
Niveau d'instruction

    Aucune instruction 193 48,1
    Primaire 188 46,9
    Secondaire 20 5,0
Parité, enfants nés vivants 1 [1–3]

6.2 Comparabilité initiale des groupes randomisés

Ici, nous présentons les pourccentages par colonne parceque la variable de croisement est le status vis-à-vis du traitement, qui était connu depuis l’inclusion.

tme |>
  select(
    traitement,
    site_suivi,
    AGEINC,
    CD4VAL,
    niveau_instruction,
    PARITY
  ) |>
  tbl_summary(
    by = traitement,
    label = list(
      site_suivi ~ "Site de suivi",
      AGEINC ~ "Âge maternel, années",
      CD4VAL ~ "CD4 maternel, cellules/mm³",
      niveau_instruction ~ "Niveau d'instruction",
      PARITY ~ "Parité"
    ),
    statistic = list(
      AGEINC ~ "{mean} ({sd})",
      CD4VAL ~ "{median} [{p25}–{p75}]",
      PARITY ~ "{median} [{p25}–{p75}]",
      all_categorical() ~ "{n} ({p} %)"
    ),
    missing = "ifany",
    missing_text = "Données manquantes"
  ) |>
  add_overall(last = TRUE) |>
  add_p() |>
  modify_header(
    label ~ "**Caractéristiques initiales**",
    stat_0 ~ "**{level}**  
n = {n}",
stat_1 ~ "**{level}**  
n~0~ = {n}",
stat_2 ~ "**{level}**  
n~1~ = {n}",
    p.value ~ "**p**"
  ) |>
  bold_labels() |>
  modify_caption(
    "**Tableau II. Comparabilité initiale des groupes AZT et placebo**"
  )
Tableau II. Comparabilité initiale des groupes AZT et placebo
Caractéristiques initiales Placebo
n0 = 201
1
AZT
n1 = 200
1
Overall
n = 401
1
p2
Site de suivi


>0,9
    Abidjan, Côte d'Ivoire 118 (59 %) 118 (59 %) 236 (59 %)
    Bobo-Dioulasso, Burkina Faso 83 (41 %) 82 (41 %) 165 (41 %)
Âge maternel, années 25,9 (5,7) 25,3 (5,0) 25,6 (5,4) 0,6
CD4 maternel, cellules/mm³ 528 [362–729] 568 [357–757] 541 [359–741] 0,7
    Données manquantes 4 4 8
Niveau d'instruction


0,8
    Aucune instruction 99 (49 %) 94 (47 %) 193 (48 %)
    Primaire 93 (46 %) 95 (48 %) 188 (47 %)
    Secondaire 9 (4,5 %) 11 (5,5 %) 20 (5,0 %)
Parité 1,00 [1,00–3,00] 1,00 [0,00–3,00] 1,00 [1,00–3,00] 0,7
1 n (% %); Mean (SD); Median [Q1–Q3]
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Aide à l’interprétation du tableau descriptif :

  • Pour les variables qualitatives, les pourcentages décrivent la composition de l’échantillon.
  • Pour une variable quantitative approximativement symétrique, la moyenne et l’écart-type décrivent le niveau moyen et la dispersion.
  • Pour une variable asymétrique comme les CD4 ou la parité, la médiane et l’intervalle interquartile sont généralement plus appropriés.
  • Une ligne « données manquantes » doit être lue séparément : elle indique le nombre de participantes non incluses dans les analyses nécessitant cette variable.

Aide à l’interprétation de la comparabilité initiale : dans un essai randomisé, ce tableau sert surtout à vérifier descriptivement que les caractéristiques initiales sont réparties de façon raisonnablement équilibrée. Une différence observée peut résulter du hasard. Les p-values ne doivent pas être utilisées seules pour sélectionner les covariables du modèle ; la pertinence clinique et le DAG restent prioritaires.

7 Figures descriptives

Une même charte graphique est utilisée dans l’ensemble du document : bleu-vert pour l’AZT et gris bleuté pour le placebo.

couleurs_traitement <- c(
  "Placebo" = "#626B78",
  "AZT" = "#007F86"
)

7.1 Répartition des groupes de traitement

tme |>
  count(traitement) |>
  mutate(pourcentage = 100 * n / sum(n)) |>
  ggplot(aes(x = traitement, y = pourcentage, fill = traitement)) +
  geom_col(width = 0.65) +
  geom_text(
    aes(label = paste0(n, " (", number(pourcentage, accuracy = 0.1), " %)")),
    vjust = -0.5,
    fontface = "bold"
  ) +
  scale_fill_manual(values = couleurs_traitement, guide = "none") +
  scale_y_continuous(
    labels = label_percent(scale = 1),
    limits = c(0, 60),
    expand = expansion(mult = c(0, 0.03))
  ) +
  labs(
    title = "Répartition des participantes selon le traitement",
    x = NULL,
    y = "Pourcentage"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_blank()
  )

7.2 Distribution des CD4 selon le traitement

ggplot(tme, aes(x = traitement, y = CD4VAL, fill = traitement)) +
  geom_boxplot(width = 0.55, alpha = 0.85, outlier.alpha = 0.45) +
  scale_fill_manual(values = couleurs_traitement, guide = "none") +
  labs(
    title = "Distribution des CD4 maternels à l'inclusion",
    x = NULL,
    y = "CD4 maternel (cellules/mm³)"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_blank()
  )

8 Statuts VIH indéterminés

tme |>
  mutate(indetermine = if_else(statut_vih == "Indéterminé", "Oui", "Non")) |>
  count(traitement, indetermine) |>
  group_by(traitement) |>
  mutate(pourcentage = 100 * n / sum(n)) |>
  ungroup() |>
  filter(indetermine == "Oui") |>
  gt() |>
  cols_label(
    traitement = "Traitement",
    n = "Statuts indéterminés",
    pourcentage = "Pourcentage (%)"
  ) |>
  fmt_number(columns = pourcentage, decimals = 1) |>
  tab_header(title = "Statuts VIH indéterminés selon le traitement")
Statuts VIH indéterminés selon le traitement
Traitement indetermine Statuts indéterminés Pourcentage (%)
Placebo Oui 3 1.5
AZT Oui 7 3.5

Règle analytique principale : les enfants au statut indéterminé ne sont classés ni comme infectés ni comme non infectés. Ils sont exclus de l’analyse principale de l’infection, puis intégrés dans des analyses de sensibilité.

9 Diagramme causal avant l’analyse des associations

Le traitement maternel constitue l’exposition principale. Puisqu’il a été attribué par randomisation, aucune flèche ne doit entrer dans le nœud du traitement. CD4VAL représente le taux de CD4 à l’inclusion ; il précède donc l’intervention et n’est pas considéré comme une conséquence de l’AZT dans ce DAG.

Diagramme causal proposé pour l’analyse de l’effet de l’AZT sur les événements de l’enfant.

Diagramme causal proposé pour l’analyse de l’effet de l’AZT sur les événements de l’enfant.

Source : OpenAI/ChatGPT

9.1 Lecture analytique du DAG

  • Exposition principale : traitement maternel par AZT versus placebo.
  • Outcome principal : infection VIH de l’enfant.
  • Outcome secondaire : décès de l’enfant.
  • Covariables pronostiques : âge maternel, CD4 à l’inclusion, niveau d’instruction, parité et site.
  • Nœud de sélection/suivi : observation biologique permettant de déterminer le statut VIH.

Pour l’effet causal principal du traitement, le RR brut reste central grâce à la randomisation. L’ajustement sert principalement à améliorer la précision et à explorer les facteurs pronostiques.

10 Analyse bivariée de l’infection

10.1 Rappel : tableau de contingence et calcul des mesures d’association

Pour une exposition binaire et un événement binaire, les données peuvent être résumées dans un tableau \(2 \times 2\).

Événement présent Événement absent Total
Exposés \(a\) \(b\) \(a+b\)
Non exposés \(c\) \(d\) \(c+d\)

Dans cette étude :

  • les exposés correspondent aux enfants dont la mère a reçu l’AZT ;
  • les non exposés correspondent aux enfants dont la mère a reçu le placebo ;
  • l’événement est l’infection VIH de l’enfant.

Le risque chez les exposés est :

\[R_E = \frac{a}{a+b}\]

Le risque chez les non exposés est :

\[R_0 = \frac{c}{c+d}\]

Le risque relatif est :

\[RR = \frac{R_E}{R_0} = \frac{a/(a+b)}{c/(c+d)}\]

L’odds d’infection chez les exposés est \(a/b\), tandis que l’odds chez les non exposés est \(c/d\). L’odds ratio est donc :

\[OR = \frac{a/b}{c/d} = \frac{ad}{bc}\]

La différence absolue des risques est :

\[DR = R_E - R_0\]

Lorsque le traitement est protecteur, la réduction relative du risque est :

\[RRR = 1-RR\]

et le nombre nécessaire à traiter peut être calculé par :

\[NNT = \frac{1}{|DR|}\]

Lecture des mesures

  • \(RR=1\) : risques identiques dans les deux groupes ;
  • \(RR<1\) : exposition associée à une diminution du risque ;
  • \(RR>1\) : exposition associée à une augmentation du risque ;
  • \(OR=1\) : cotes identiques ;
  • le RR et l’OR deviennent proches lorsque l’événement est rare, mais peuvent différer lorsque l’événement est fréquent.
tme_assoc <- tme |>
  filter(HIVSTATUS != 9)

nrow(tme_assoc)
## [1] 391

Portée de cette estimation : le RR calculé ci-dessous compare les proportions d’enfants classés infectés dans l’extrait pédagogique à la fin du suivi disponible. Il ne correspond pas exactement à l’estimation Kaplan-Meier du risque à 6 mois publiée dans l’article principal.

10.2 Tableau 2 × 2 : traitement et infection

La première colonne correspond à l’événement, et la première ligne au groupe exposé à l’AZT.

# Le facteur traitement conserve Placebo comme catégorie de référence
# pour les modèles de régression.
tme_assoc <- tme_assoc |>
  mutate(
    traitement = factor(
      traitement,
      levels = c("Placebo", "AZT")
    ),
    traitement_2x2 = factor(
      traitement,
      levels = c("AZT", "Placebo")
    ),
    infection_2x2 = factor(
      HIVSTATUS,
      levels = c(1, 0),
      labels = c("Infecté", "Non infecté")
    )
  )

# Première ligne : groupe exposé (AZT)
# Première colonne : événement (infection)
tab_azt <- with(
  tme_assoc,
  table(traitement_2x2, infection_2x2)
)

# Matrice numérique explicitement ordonnée pour epiR et epitools
tab_azt_matrix <- matrix(
  c(
    tab_azt["AZT", "Infecté"],
    tab_azt["AZT", "Non infecté"],
    tab_azt["Placebo", "Infecté"],
    tab_azt["Placebo", "Non infecté"]
  ),
  nrow = 2,
  byrow = TRUE,
  dimnames = list(
    Traitement = c("AZT", "Placebo"),
    Statut_VIH = c("Infecté", "Non infecté")
  )
)

tab_azt_matrix
##           Statut_VIH
## Traitement Infecté Non infecté
##    AZT          41         152
##    Placebo      59         139

10.2.1 Mesures fournies par epiR

epiR::epi.2by2(
  dat = tab_azt_matrix,
  method = "cohort.count",
  conf.level = 0.95,
  units = 100,
  outcome = "as.columns"
)
##              Outcome+    Outcome-      Total                 Inc risk *
## Exposure+          41         152        193     21,24 (15,70 to 27,70)
## Exposure-          59         139        198     29,80 (23,52 to 36,69)
## Total             100         291        391     25,58 (21,32 to 30,20)
## 
## Point estimates and 95% CIs:
## -------------------------------------------------------------------
## Inc risk ratio                                 0.71 (0.50, 1.01)
## Inc odds ratio                                 0.64 (0.40, 1.01)
## Attrib risk in the exposed *                   -8.55 (-17.15, 0.04)
## Attrib fraction in the exposed (%)            -40.27 (-98.39, 0.37)
## Attrib risk in the population *                -4.22 (-11.92, 3.48)
## Attrib fraction in the population (%)         -16.51 (-21.48, -10.31)
## E-value                                        2.15 (NA, 1.00)
## -------------------------------------------------------------------
## Uncorrected chi2 test that OR = 1: chi2(1) = 3.757 Pr>chi2 = 0.053
## Fisher exact test that OR = 1: Pr>chi2 = 0.063
## Wald confidence limits
## CI: confidence interval
## * Outcomes per 100 population units

10.2.2 Vérification avec epitools

# epitools attend la catégorie de référence à la première ligne et
# l'absence d'événement dans la première colonne ; on inverse donc
# les lignes et les colonnes pour obtenir Placebo comme référence.
epitools::riskratio(tab_azt_matrix, rev = "both")
## $data
##           Statut_VIH
## Traitement Non infecté Infecté Total
##    Placebo         139      59   198
##    AZT             152      41   193
##    Total           291     100   391
## 
## $measure
##           risk ratio with 95% C.I.
## Traitement  estimate     lower    upper
##    Placebo 1,0000000        NA       NA
##    AZT     0,7129182 0,5045573 1,007323
## 
## $p.value
##           two-sided
## Traitement midp.exact fisher.exact chi.square
##    Placebo         NA           NA         NA
##    AZT     0,05377347    0,0634521 0,05257327
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
epitools::oddsratio(tab_azt_matrix, rev = "both")
## $data
##           Statut_VIH
## Traitement Non infecté Infecté Total
##    Placebo         139      59   198
##    AZT             152      41   193
##    Total           291     100   391
## 
## $measure
##           odds ratio with 95% C.I.
## Traitement  estimate     lower   upper
##    Placebo 1,0000000        NA      NA
##    AZT     0,6368427 0,3996076 1,00732
## 
## $p.value
##           two-sided
## Traitement midp.exact fisher.exact chi.square
##    Placebo         NA           NA         NA
##    AZT     0,05377347    0,0634521 0,05257327
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

10.3 Comparaison du RR et de l’OR

a <- tab_azt_matrix["AZT", "Infecté"]
b <- tab_azt_matrix["AZT", "Non infecté"]
c <- tab_azt_matrix["Placebo", "Infecté"]
d <- tab_azt_matrix["Placebo", "Non infecté"]

risque_azt <- a / (a + b)
risque_placebo <- c / (c + d)

rr <- risque_azt / risque_placebo
se_log_rr <- sqrt((1 / a) - (1 / (a + b)) + (1 / c) - (1 / (c + d)))
rr_inf <- exp(log(rr) - 1.96 * se_log_rr)
rr_sup <- exp(log(rr) + 1.96 * se_log_rr)

or <- (a * d) / (b * c)
se_log_or <- sqrt(1 / a + 1 / b + 1 / c + 1 / d)
or_inf <- exp(log(or) - 1.96 * se_log_or)
or_sup <- exp(log(or) + 1.96 * se_log_or)

comparaison_mesures <- tibble(
  mesure = c("Risque relatif (RR)", "Odds ratio (OR)"),
  estimation = c(rr, or),
  borne_inferieure = c(rr_inf, or_inf),
  borne_superieure = c(rr_sup, or_sup)
)

comparaison_mesures |>
  mutate(
    `Estimation [IC à 95 %]` = paste0(
      number(estimation, accuracy = 0.01),
      " [", number(borne_inferieure, accuracy = 0.01),
      "–", number(borne_superieure, accuracy = 0.01), "]"
    )
  ) |>
  select(Mesure = mesure, `Estimation [IC à 95 %]`) |>
  gt() |>
  tab_header(
    title = "Comparaison du RR et de l'OR pour l'effet de l'AZT"
  )
Comparaison du RR et de l'OR pour l'effet de l'AZT
Mesure Estimation [IC à 95 %]
Risque relatif (RR) 0.71 [0.50–1.01]
Odds ratio (OR) 0.64 [0.40–1.01]
ggplot(
  comparaison_mesures,
  aes(x = estimation, y = reorder(mesure, estimation))
) +
  geom_vline(xintercept = 1, linetype = 2, linewidth = 0.6) +
  geom_errorbarh(
    aes(xmin = borne_inferieure, xmax = borne_superieure),
    height = 0.18,
    linewidth = 0.8
  ) +
  geom_point(size = 3.2) +
  labs(
    title = "RR et OR : deux mesures différentes",
    subtitle = "L'OR s'éloigne davantage de 1 lorsque l'événement n'est pas rare",
    x = "Mesure d'association et IC à 95 %",
    y = NULL
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank(),
    panel.grid.major.y = element_blank()
  )

Interprétation : le RR compare directement les risques. L’OR compare les cotes. Pour cette étude longitudinale randomisée, le RR est la mesure principale à communiquer. L’OR est présenté uniquement pour montrer qu’il peut surestimer ou sousestimer visuellement l’ampleur d’une association lorsqu’il est interprété à tort comme un RR.

10.4 Tableau bivarié au format épidémiologique

Les modèles log-binomiaux ci-dessous fournissent directement les RR bruts et leurs intervalles de confiance.

mod_traitement <- glm(
  HIVSTATUS ~ traitement,
  family = binomial(link = "log"),
  data = tme_assoc
)

mod_site <- glm(
  HIVSTATUS ~ site_suivi,
  family = binomial(link = "log"),
  data = tme_assoc
)

mod_age <- glm(
  HIVSTATUS ~ age_groupe,
  family = binomial(link = "log"),
  data = tme_assoc
)

mod_cd4 <- glm(
  HIVSTATUS ~ cd4_groupe,
  family = binomial(link = "log"),
  data = tme_assoc[!is.na(tme_assoc$CD4VAL),]
)

mod_instruction <- glm(
  HIVSTATUS ~ niveau_instruction,
  family = binomial(link = "log"),
  data = tme_assoc
)

mod_parite <- glm(
  HIVSTATUS ~ parite_groupe,
  family = binomial(link = "log"),
  data = tme_assoc
)
resultats_bivaries |>
  select(
    variables_modalites,
    n,
    evenements,
    evenement_pct,
    rr_ic,
    p_affichee
  ) |>
  gt() |>
  fmt_markdown(columns = variables_modalites) |>
  cols_label(
    variables_modalites = "Variables et modalités",
    n = "n",
    evenements = "n1",
    evenement_pct = "%",
    rr_ic = "RR [IC95 %]",
    p_affichee = "p"
  ) |>
  cols_align(
    align = "center",
    columns = c(n, evenements, evenement_pct, rr_ic, p_affichee)
  ) |>
  tab_header(
    title = "Tableau III. Facteurs associés à l'infection VIH de l'enfant"
  ) |>
  tab_source_note(
    source_note = "RR : risque relatif ; IC : intervalle de confiance. La première modalité de chaque variable est la référence."
  )
Tableau III. Facteurs associés à l'infection VIH de l'enfant
Variables et modalités n n1 % RR [IC95 %] p
Traitement maternel
Placebo
198 59 29.8 1,00
  AZT 193 41 21.2 0.71 [0.50–1.00] 0.055
Site de suivi
Abidjan, Côte d’Ivoire
233 53 22.7 1,00
  Bobo-Dioulasso, Burkina Faso 158 47 29.7 1.31 [0.93–1.83] 0.118
Âge maternel
≥ 25 ans
195 61 31.3 1,00
  < 25 ans 196 39 19.9 0.64 [0.44–0.90] 0.011
CD4 maternel à l’inclusion
≥ 350 cellules/mm³
295 51 17.3 1,00
  < 350 cellules/mm³ 89 47 52.8 3.05 [2.22–4.21] < 0,001
Niveau d’instruction
Aucune instruction
189 48 25.4 1,00
  Primaire 184 45 24.5 0.96 [0.67–1.37] 0.834
  Secondaire 18 7 38.9 1.53 [0.72–2.63] 0.184
Parité
Nullipare
92 18 19.6 1,00
  Primipare 124 31 25.0 1.28 [0.77–2.19] 0.350
  Paucipare 136 39 28.7 1.47 [0.91–2.47] 0.128
  Multipare 39 12 30.8 1.57 [0.81–2.92] 0.157
RR : risque relatif ; IC : intervalle de confiance. La première modalité de chaque variable est la référence.

Aide à l’interprétation de l’analyse bivariée

Pour chaque variable, la première modalité constitue la référence. Le pourcentage d’événements est calculé en ligne : il répond à la question « parmi les participantes de cette modalité, quelle proportion d’enfants a été infectée ? ». Un RR inférieur à 1 indique un risque plus faible que dans la référence ; un RR supérieur à 1 indique un risque plus élevé. Si l’IC à 95 % contient 1, les données restent compatibles avec une absence d’association au seuil de 5 %. La p-value renseigne sur la compatibilité avec l’hypothèse nulle, mais l’ampleur du RR et la précision de son intervalle doivent rester prioritaires.

11 Analyse stratifiée de l’effet de l’AZT

11.1 Stratification selon le site

Le tableau de contingence par strate du site s’affiche alors ainsi :

with(
  tme_assoc,
  ftable(site_suivi, traitement, statut_vih)
) 
##                                         statut_vih Non infecté Infecté Indéterminé
## site_suivi                   traitement                                           
## Abidjan, Côte d'Ivoire       Placebo                        87      30           0
##                              AZT                            93      23           0
## Bobo-Dioulasso, Burkina Faso Placebo                        52      29           0
##                              AZT                            59      18           0

Nous allons alors calculer les RR par strate

strat_site <- tme_assoc |>
  group_by(site_suivi, traitement) |>
  summarise(
    n = n(),
    evenements = sum(HIVSTATUS),
    risque = mean(HIVSTATUS)
  ) |>
  pivot_wider(
    names_from = traitement,
    values_from = c(n, evenements, risque)
  ) |>
  mutate(
    non_evenements_AZT = n_AZT - evenements_AZT,
    non_evenements_Placebo = n_Placebo - evenements_Placebo,
    RR = risque_AZT / risque_Placebo,
    se_log_rr = sqrt(
      1 / evenements_AZT - 1 / n_AZT +
        1 / evenements_Placebo - 1 / n_Placebo
    ),
    borne_inferieure = exp(log(RR) - 1.96 * se_log_rr),
    borne_superieure = exp(log(RR) + 1.96 * se_log_rr),
    placebo = paste0(
      evenements_Placebo, "/", n_Placebo,
      " (", number(100 * risque_Placebo, accuracy = 0.1), " %)"
    ),
    azt = paste0(
      evenements_AZT, "/", n_AZT,
      " (", number(100 * risque_AZT, accuracy = 0.1), " %)"
    ),
    rr_ic = paste0(
      number(RR, accuracy = 0.01),
      " [", number(borne_inferieure, accuracy = 0.01),
      "–", number(borne_superieure, accuracy = 0.01), "]"
    )
  )
strat_site |>
  select(
    `Site de suivi` = site_suivi,
    `Placebo : n0/n (%)` = placebo,
    `AZT : n1/n (%)` = azt,
    `RR [IC à 95 %]` = rr_ic
  ) |>
  gt() |>
  tab_header(
    title = "Effet estimé de l'AZT selon le site"
  )
Effet estimé de l'AZT selon le site
Placebo : n0/n (%) AZT : n1/n (%) RR [IC à 95 %]
Abidjan, Côte d'Ivoire
30/117 (25.6 %) 23/116 (19.8 %) 0.77 [0.48–1.25]
Bobo-Dioulasso, Burkina Faso
29/81 (35.8 %) 18/77 (23.4 %) 0.65 [0.40–1.07]

11.2 Stratification selon le niveau de CD4

strat_cd4 <- tme_assoc|>
  filter(!is.na(cd4_groupe)) |>
  group_by(cd4_groupe, traitement) |>
  summarise(
    n = n(),
    evenements = sum(HIVSTATUS),
    risque = mean(HIVSTATUS)
  ) |>
  pivot_wider(
    names_from = traitement,
    values_from = c(n, evenements, risque)
  ) |>
  mutate(
    RR = risque_AZT / risque_Placebo,
    se_log_rr = sqrt(
      1 / evenements_AZT - 1 / n_AZT +
        1 / evenements_Placebo - 1 / n_Placebo
    ),
    borne_inferieure = exp(log(RR) - 1.96 * se_log_rr),
    borne_superieure = exp(log(RR) + 1.96 * se_log_rr),
    placebo = paste0(
      evenements_Placebo, "/", n_Placebo,
      " (", number(100 * risque_Placebo, accuracy = 0.1), " %)"
    ),
    azt = paste0(
      evenements_AZT, "/", n_AZT,
      " (", number(100 * risque_AZT, accuracy = 0.1), " %)"
    ),
    rr_ic = paste0(
      number(RR, accuracy = 0.01),
      " [", number(borne_inferieure, accuracy = 0.01),
      "–", number(borne_superieure, accuracy = 0.01), "]"
    )
  )
with(
  tme_assoc,
  ftable(cd4_groupe, traitement, infection_2x2)
) 
##                               infection_2x2 Infecté Non infecté
## cd4_groupe         traitement                                  
## ≥ 350 cellules/mm³ Placebo                       33         117
##                    AZT                           18         127
## < 350 cellules/mm³ Placebo                       25          20
##                    AZT                           22          22
strat_cd4 |>
  select(
    `CD4 maternel` = cd4_groupe,
    `Placebo : n0/n (%)` = placebo,
    `AZT : n1/n (%)` = azt,
    `RR [IC à 95 %]` = rr_ic
  ) |>
  gt() |>
  tab_header(
    title = "Effet estimé de l'AZT selon le niveau de CD4 à l'inclusion"
  )
Effet estimé de l'AZT selon le niveau de CD4 à l'inclusion
Placebo : n0/n (%) AZT : n1/n (%) RR [IC à 95 %]
≥ 350 cellules/mm³
33/150 (22.0 %) 18/145 (12.4 %) 0.56 [0.33–0.96]
< 350 cellules/mm³
25/45 (55.6 %) 22/44 (50.0 %) 0.90 [0.61–1.34]

11.3 RR commun ajusté de Mantel-Haenszel

tab_site_3d <- xtabs(
  ~ traitement_2x2 + infection_2x2 + site_suivi,
  data = tme_assoc
)

epiR::epi.2by2(
  dat = tab_site_3d,
  method = "cohort.count",
  conf.level = 0.95,
  outcome = "as.columns"
)
##              Outcome+    Outcome-      Total                 Inc risk *
## Exposure+          41         152        193     21,24 (15,70 to 27,70)
## Exposure-          59         139        198     29,80 (23,52 to 36,69)
## Total             100         291        391     25,58 (21,32 to 30,20)
## 
## 
## Point estimates and 95% CIs:
## -------------------------------------------------------------------
## Inc risk ratio (crude)                         0.71 (0.50, 1.01)
## Inc risk ratio (M-H)                           0.71 (0.51, 1.01)
## Inc risk ratio (crude:M-H)                     1.00
## Inc odds ratio (crude)                         0.64 (0.40, 1.01)
## Inc odds ratio (M-H)                           0.64 (0.40, 1.01)
## Inc odds ratio (crude:M-H)                     1.00
## Attrib risk in the exposed (crude) *           -8.55 (-17.15, 0.04)
## Attrib risk in the exposed (M-H) *             -8.48 (-17.15, 0.18)
## Attrib risk (crude:M-H)                        1.01
## E-value (crude)                                2.15 (NA, 1.00)
## E-value (M-H)                                  2.15 (NA, 1.00)
## -------------------------------------------------------------------
## M-H test of homogeneity of IRRs: chi2(1) = 0.230 Pr>chi2 = 0.631
## M-H test of homogeneity of ORs: chi2(1) = 0.317 Pr>chi2 = 0.574
## Test that M-H adjusted OR = 1:  chi2(1) = 3.700 Pr>chi2 = 0.054
## Wald confidence limits
## M-H: Mantel-Haenszel; CI: confidence interval
## * Outcomes per 100 population units

11.4 Test d’interaction traitement × site

modele_interaction_site <- glm(
  infection ~ traitement * site_suivi,
  family = binomial(link = "log"),
  data = tme_assoc
)

broom::tidy(
  modele_interaction_site,
  exponentiate = TRUE,
  conf.int = TRUE
) |>
  gt() |>
  fmt_number(
    columns = c(estimate, conf.low, conf.high, p.value),
    decimals = 3
  ) |>
  cols_label(
    term = "Terme",
    estimate = "RR",
    conf.low = "Borne inférieure",
    conf.high = "Borne supérieure",
    p.value = "Valeur p"
  ) |>
  tab_header(
    title = "Interaction entre le traitement et le site"
  )
Interaction entre le traitement et le site
Terme RR std.error statistic Valeur p Borne inférieure Borne supérieure
(Intercept) 0.256 0,1574367 -8,6445941 0.000 0.183 0.340
traitementAZT 0.773 0,2442210 -1,0528148 0.292 0.473 1.244
site_suiviBobo-Dioulasso, Burkina Faso 1.396 0,2166181 1,5410680 0.123 0.909 2.145
traitementAZT:site_suiviBobo-Dioulasso, Burkina Faso 0.844 0,3526322 -0,4797092 0.631 0.419 1.683

Une différence numérique entre les RR des deux sites ne prouve pas automatiquement une modification d’effet. Le terme d’interaction indique si les données apportent suffisamment d’arguments en faveur d’un effet différent selon le site.

11.5 Test d’interaction traitement × cd4

modele_interaction_cd4 <- glm(
  infection ~ traitement * cd4_groupe,
  family = binomial(link = "log"),
  data = tme_assoc
)

broom::tidy(
  modele_interaction_cd4,
  exponentiate = TRUE,
  conf.int = TRUE
) |>
  gt() |>
  fmt_number(
    columns = c(estimate, conf.low, conf.high, p.value),
    decimals = 3
  ) |>
  cols_label(
    term = "Terme",
    estimate = "RR",
    conf.low = "Borne inférieure",
    conf.high = "Borne supérieure",
    p.value = "Valeur p"
  ) |>
  tab_header(
    title = "Interaction entre le traitement et le taux de CD4"
  )
Interaction entre le traitement et le taux de CD4
Terme RR std.error statistic Valeur p Borne inférieure Borne supérieure
(Intercept) 0.220 0,1537412 -9,848549 0.000 0.159 0.291
traitementAZT 0.564 0,2688776 -2,128233 0.033 0.325 0.942
cd4_groupe< 350 cellules/mm³ 2.525 0,2035046 4,551941 0.000 1.678 3.770
traitementAZT:cd4_groupe< 350 cellules/mm³ 1.595 0,3358574 1,390095 0.165 0.830 3.127

Aide à l’interprétation de l’analyse stratifiée

Les RR propres à chaque strate permettent de vérifier si l’effet du traitement est semblable dans les sous-groupes. Des RR proches suggèrent un effet relativement homogène. Des RR nettement différents peuvent traduire une modification d’effet, mais celle-ci doit être confirmée par un test d’interaction et interprétée en tenant compte des effectifs et de la largeur des intervalles de confiance. Un RR commun de Mantel-Haenszel résume l’association après contrôle de la variable de stratification, sous l’hypothèse d’un effet suffisamment homogène entre les strates.

12 Analyse multivariée : estimation des RR ajustés

Le modèle log-binomial estime directement des risques relatifs, mais il présente fréquemment des difficultés de convergence. Les observations dont le CD4 est manquant ne sont pas supprimées du calcul du RR brut du traitement ; elles sont exclues uniquement des analyses stratifiées ou multivariées qui nécessitent cette covariable. Dans ce script, une régression de Poisson modifiée avec variance robuste est utilisée. Avec une issue binaire et des erreurs-types robustes, les coefficients exponentiés sont interprétés comme des RR ajustés. Les catégories utilisées dans le tableau bivarié sont conservées afin de faciliter la comparaison.

modele1 <- glm(
  HIVSTATUS ~ traitement + site_suivi + age_groupe + cd4_groupe +
    instruction_groupe + parite_groupe,
  family = poisson(link = "log"),
  data = tme_assoc[!is.na(tme_assoc$CD4VAL), ]
)
modele_rr_ajuste <- step(modele1, direction = "both",trace=FALSE)
# Erreurs-types robustes (sandwich) pour corriger la sur-dispersion inhérente
vcov_robuste <- vcovHC(modele_rr_ajuste, type = "HC1")

resultats_rr <- coeftest(modele_rr_ajuste, vcov = vcov_robuste)
resultats_rr
## 
## z test of coefficients:
## 
##                                        Estimate Std. Error z value
## (Intercept)                            -1,57746    0,18937 -8,3300
## traitementAZT                          -0,33745    0,16870 -2,0004
## site_suiviBobo-Dioulasso, Burkina Faso  0,34831    0,16362  2,1287
## age_groupe< 25 ans                     -0,37998    0,17093 -2,2231
## cd4_groupe< 350 cellules/mm³            1,10910    0,16489  6,7262
##                                                     Pr(>|z|)    
## (Intercept)                            < 0,00000000000000022 ***
## traitementAZT                                        0,04546 *  
## site_suiviBobo-Dioulasso, Burkina Faso               0,03328 *  
## age_groupe< 25 ans                                   0,02621 *  
## cd4_groupe< 350 cellules/mm³                0,00000000001742 ***
## ---
## Signif. codes:  0 '***' 0,001 '**' 0,01 '*' 0,05 '.' 0,1 ' ' 1
# IC à 95% robustes
ic_robustes <- coefci(modele_rr_ajuste, vcov. = vcov_robuste)

modele_rr_ajuste$converged
## [1] TRUE

Si le résultat ci-dessus est TRUE, l’algorithme du modèle de Poisson a convergé. La variance robuste corrige les erreurs-types afin que les intervalles de confiance soient adaptés à une issue binaire.

table_modele <- tibble(
  term      = rownames(resultats_rr),
  estimate  = resultats_rr[, "Estimate"],
  std.error = resultats_rr[, "Std. Error"],
  p.value   = resultats_rr[, "Pr(>|z|)"],
  conf.low  = ic_robustes[, 1],
  conf.high = ic_robustes[, 2]
) |>
  filter(term != "(Intercept)") |>
  mutate(
    rr_ajuste     = exp(estimate),
    rr_ajuste_inf = exp(conf.low),
    rr_ajuste_sup = exp(conf.high)
  ) |>
  select(
    terme = term,
    rr_ajuste,
    rr_ajuste_inf,
    rr_ajuste_sup,
    p_ajustee = p.value
  )

# --- Fusion avec le tableau bivarié ---
resultats_multivaries <- resultats_bivaries |>
  left_join(table_modele, by = "terme") |>
  mutate(
    rra_ic = case_when(
      is.na(terme) ~ "1,00",
      is.na(rr_ajuste) ~ "",
      TRUE ~ paste0(
        number(rr_ajuste, accuracy = 0.01),
        " [", number(rr_ajuste_inf, accuracy = 0.01),
        "–", number(rr_ajuste_sup, accuracy = 0.01), "]"
      )
    ),
    p_ajustee_affichee = case_when(
      is.na(p_ajustee) ~ "",
      p_ajustee < 0.001 ~ "< 0,001",
      TRUE ~ number(p_ajustee, accuracy = 0.001)
    )
  )

# --- Tableau final ---
resultats_multivaries |>
  select(
    variables_modalites,
    n,
    evenements,
    evenement_pct,
    rr_ic,
    p_affichee,
    rra_ic,
    p_ajustee_affichee
  ) |>
  gt() |>
  fmt_markdown(columns = variables_modalites) |>
  cols_label(
    variables_modalites = "Variables et modalités",
    n = "n",
    evenements = "n1",
    evenement_pct = "%",
    rr_ic = "RRb [IC à 95 %]",
    p_affichee = "p",
    rra_ic = "RRa [IC à 95 %]",
    p_ajustee_affichee = "p ajustée"
  ) |>
  cols_align(
    align = "center",
    columns = c(n, evenements, evenement_pct, rr_ic, p_affichee, rra_ic, p_ajustee_affichee)
  ) |>
  tab_header(
    title = "Tableau IV. Facteurs associés à l'infection : RR bruts et ajustés"
  ) |>
  tab_source_note(
    source_note = "RRb : risque relatif brut ; RRa : risque relatif ajusté, estimé par régression de Poisson modifiée avec erreurs-types robustes (sandwich). IC : intervalle de confiance à 95 %."
  )
Tableau IV. Facteurs associés à l'infection : RR bruts et ajustés
Variables et modalités n n1 % RRb [IC à 95 %] p RRa [IC à 95 %] p ajustée
Traitement maternel
Placebo
198 59 29.8 1,00 1,00
  AZT 193 41 21.2 0.71 [0.50–1.00] 0.055 0.71 [0.51–0.99] 0.045
Site de suivi
Abidjan, Côte d’Ivoire
233 53 22.7 1,00 1,00
  Bobo-Dioulasso, Burkina Faso 158 47 29.7 1.31 [0.93–1.83] 0.118 1.42 [1.03–1.95] 0.033
Âge maternel
≥ 25 ans
195 61 31.3 1,00 1,00
  < 25 ans 196 39 19.9 0.64 [0.44–0.90] 0.011 0.68 [0.49–0.96] 0.026
CD4 maternel à l’inclusion
≥ 350 cellules/mm³
295 51 17.3 1,00 1,00
  < 350 cellules/mm³ 89 47 52.8 3.05 [2.22–4.21] < 0,001 3.03 [2.19–4.19] < 0,001
Niveau d’instruction
Aucune instruction
189 48 25.4 1,00 1,00
  Primaire 184 45 24.5 0.96 [0.67–1.37] 0.834
  Secondaire 18 7 38.9 1.53 [0.72–2.63] 0.184
Parité
Nullipare
92 18 19.6 1,00 1,00
  Primipare 124 31 25.0 1.28 [0.77–2.19] 0.350
  Paucipare 136 39 28.7 1.47 [0.91–2.47] 0.128
  Multipare 39 12 30.8 1.57 [0.81–2.92] 0.157
RRb : risque relatif brut ; RRa : risque relatif ajusté, estimé par régression de Poisson modifiée avec erreurs-types robustes (sandwich). IC : intervalle de confiance à 95 %.

12.1 Forest plot des RR ajustés

forest_rra <- table_modele |>
  mutate(
    libelle = recode(
      terme,
      "traitementAZT" = "AZT vs placebo",
      "site_suiviBobo-Dioulasso, Burkina Faso" = "Bobo-Dioulasso vs Abidjan",
      "age_groupe< 25 ans" = "Âge < 25 ans",
      "cd4_groupe< 350 cellules/mm³" = "CD4 < 350 cellules/mm³",
      "instruction_groupeAucune ou primaire" = "Instruction : aucune ou primaire",
      "parite_groupePrimipare" = "Primipare vs nullipare",
      "parite_groupePaucipare" = "Paucipare vs nullipare",
      "parite_groupeMultipare" = "Multipare vs nullipare"
    )
  )

ggplot(
  forest_rra,
  aes(x = rr_ajuste, y = reorder(libelle, rr_ajuste))
) +
  geom_vline(xintercept = 1, linetype = 2, linewidth = 0.6) +
  geom_errorbarh(
    aes(xmin = rr_ajuste_inf, xmax = rr_ajuste_sup),
    height = 0.18,
    linewidth = 0.8
  ) +
  geom_point(size = 3) +
  scale_x_log10() +
  labs(
    title = "Facteurs associés à l'infection VIH de l'enfant",
    subtitle = "Risques relatifs ajustés et intervalles de confiance à 95 %",
    x = "RRa",
    y = NULL
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank(),
    panel.grid.major.y = element_blank()
  )

Aide à l’interprétation du modèle multivarié

Le RRa du traitement compare le risque d’infection sous AZT au risque sous placebo, après prise en compte simultanée des autres variables du modèle. Dans un essai randomisé, cette estimation ajustée complète le RR brut mais ne le remplace pas. Une modification importante entre RR brut et RRa peut résulter d’un déséquilibre fortuit, de données manquantes ou du changement de population analysée. Les variables continues ou catégorisées doivent être interprétées selon l’unité ou la référence affichée. Les résultats du modèle ne doivent pas être interprétés automatiquement comme causaux pour les covariables non randomisées.

13 Analyse du temps jusqu’à l’infection

13.1 Construction de la durée et de la censure

Pour un enfant infecté, le temps est calculé entre la naissance et la date du diagnostic. Pour un enfant non infecté, le temps est calculé entre la naissance et la dernière date biologique disponible.

Écart par rapport aux publications : dans la base, DATINF correspond à une date de diagnostic et non nécessairement à la date biologique exacte de contamination. Cette séance utilise donc une approximation ponctuelle compatible avec Kaplan-Meier et Cox standards. Les analyses publiées de suivi prolongé ont tenu compte du fait que l’infection pouvait être connue seulement entre deux tests successifs.

tme_survie_infection <- tme |>
  filter(statut_vih %in% c("Infecté", "Non infecté")) |>
  mutate(
    evenement_infection = if_else(statut_vih == "Infecté", 1, 0),
    date_fin_infection = if_else(
      evenement_infection == 1,
      DATINF,
      DATE_LAST_BIO
    ),
    temps_infection_jours = as.numeric(date_fin_infection - DATBIRTH),
    temps_infection_mois = temps_infection_jours / 30.44
  ) |>
  filter(
    !is.na(temps_infection_mois),
    temps_infection_mois >= 0
  )

nrow(tme_survie_infection)
## [1] 391

13.2 Description du suivi

tme_survie_infection |>
  group_by(traitement) |>
  summarise(
    n = n(),
    infections = sum(evenement_infection),
    censures = sum(evenement_infection == 0),
    suivi_median = median(temps_infection_mois),
    q1 = quantile(temps_infection_mois, 0.25),
    q3 = quantile(temps_infection_mois, 0.75),
    personnes_mois = sum(temps_infection_mois),
    incidence_100_pm = 100 * infections / personnes_mois
  ) |>
  mutate(
    `Suivi médian [Q1–Q3], mois` = paste0(
      number(suivi_median, accuracy = 0.1),
      " [", number(q1, accuracy = 0.1),
      "–", number(q3, accuracy = 0.1), "]"
    )
  ) |>
  select(
    Traitement = traitement,
    n,
    Infections = infections,
    Censures = censures,
    `Suivi médian [Q1–Q3], mois`,
    `Incidence pour 100 personnes-mois` = incidence_100_pm
  ) |>
  gt() |>
  fmt_number(
    columns = `Incidence pour 100 personnes-mois`,
    decimals = 2
  ) |>
  tab_header(
    title = "Description du suivi jusqu'à l'infection"
  )
Description du suivi jusqu'à l'infection
Traitement n Infections Censures Suivi médian [Q1–Q3], mois Incidence pour 100 personnes-mois
Placebo 198 59 139 15.2 [1.5–18.6] 2.45
AZT 193 41 152 18.0 [7.1–20.6] 1.47

13.3 Courbes de Kaplan-Meier

Temps d’infection globale dans l’échantillon

km_globale <- survfit(
  Surv(temps_infection_mois, evenement_infection) ~ 1,
  data = tme_survie_infection
)
summary(km_globale)
## Call: survfit(formula = Surv(temps_infection_mois, evenement_infection) ~ 
##     1, data = tme_survie_infection)
## 
##     time n.risk n.event survival std.err lower 95% CI upper 95% CI
##   0,0329    390       9    0,977 0,00760        0,962        0,992
##   0,0657    378       4    0,967 0,00911        0,949        0,985
##   0,0986    371       3    0,959 0,01009        0,939        0,979
##   0,2300    368       3    0,951 0,01097        0,930        0,973
##   0,2628    365       2    0,946 0,01152        0,923        0,969
##   0,2957    362       7    0,927 0,01321        0,902        0,954
##   0,3285    354       4    0,917 0,01406        0,890        0,945
##   0,3614    349       3    0,909 0,01465        0,881        0,938
##   0,3942    346       2    0,904 0,01503        0,875        0,934
##   0,8213    343       1    0,901 0,01522        0,872        0,932
##   1,2812    342       1    0,899 0,01540        0,869        0,929
##   1,3798    341       2    0,893 0,01576        0,863        0,925
##   1,4126    338       1    0,891 0,01593        0,860        0,922
##   1,4455    337       5    0,877 0,01675        0,845        0,911
##   1,4783    331      11    0,848 0,01836        0,813        0,885
##   1,5112    318       3    0,840 0,01876        0,804        0,878
##   1,5440    314       5    0,827 0,01939        0,790        0,866
##   1,5769    309       4    0,816 0,01986        0,778        0,856
##   2,7595    302       1    0,813 0,01998        0,775        0,854
##   2,8909    300       1    0,811 0,02010        0,772        0,851
##   2,9566    296       2    0,805 0,02033        0,766        0,846
##   3,0223    292       1    0,803 0,02045        0,763        0,844
##   3,0552    291       1    0,800 0,02056        0,760        0,841
##   3,0880    290       2    0,794 0,02079        0,755        0,836
##   3,3509    287       1    0,792 0,02090        0,752        0,834
##   5,8804    284       1    0,789 0,02101        0,749        0,831
##   5,9461    283       2    0,783 0,02123        0,743        0,826
##   5,9790    281       1    0,780 0,02134        0,740        0,823
##   6,0775    273       2    0,775 0,02156        0,734        0,818
##   9,0013    262       3    0,766 0,02191        0,724        0,810
##   9,0670    256       1    0,763 0,02203        0,721        0,807
##  10,0854    252       1    0,760 0,02215        0,718        0,804
##  12,0237    245       1    0,757 0,02227        0,714        0,802
##  12,7135    236       1    0,753 0,02241        0,711        0,799
##  14,9146    230       1    0,750 0,02255        0,707        0,796
##  14,9803    227       2    0,744 0,02283        0,700        0,790
##  17,9369    194       1    0,740 0,02303        0,696        0,786
##  17,9698    187       1    0,736 0,02325        0,692        0,783
##  18,0683    159       1    0,731 0,02356        0,686        0,779
##  18,6597    116       1    0,725 0,02418        0,679        0,774
##  21,0578     74       1    0,715 0,02576        0,666        0,767
ggsurvplot(
  km_globale,
  data = tme_survie_infection,
  color ="blue",
  risk.table = TRUE,
  conf.int = TRUE,
  xlab = "Temps depuis la naissance (mois)",
  ylab = "Probabilité de rester non infecté",
  ggtheme = theme_survminer(base_size = 12),
  risk.table.height = 0.25
)

km_infection <- survfit(
  Surv(temps_infection_mois, evenement_infection) ~ traitement,
  data = tme_survie_infection
)

ggsurvplot(
  km_infection,
  data = tme_survie_infection,
  risk.table = TRUE,
  pval = TRUE,
  conf.int = FALSE,
  palette = unname(couleurs_traitement),
  xlab = "Temps depuis la naissance (mois)",
  ylab = "Probabilité de rester non infecté",
  legend.title = "Traitement",
  legend.labs = c("Placebo", "AZT"),
  ggtheme = theme_minimal(base_size = 12),
  risk.table.height = 0.25
)

Une courbe plus élevée indique une probabilité plus importante de rester non infecté. La p-value affichée correspond au test du log-rank.

13.4 Modèle de Cox

modele2 <- coxph(
  Surv(temps_infection_mois, evenement_infection) ~
    traitement + site_suivi + AGEINC + cd4_groupe +
    niveau_instruction + parite_groupe,
  data = tme_survie_infection[!is.na(tme_survie_infection$CD4VAL),]
)
cox_infection <- step(modele2, direction = "backward",trace=FALSE)
cox_infection |>
  tbl_regression(
    exponentiate = TRUE,
    label = list(
      traitement ~ "Traitement maternel",
      site_suivi ~ "Site de suivi",
      AGEINC ~ "Âge maternel",
      cd4_groupe ~ "CD4 maternel"
    )
  ) |>
  modify_header(
    label ~ "**Variables et modalités**",
    estimate ~ "**HR [IC à 95 %]**",
    p.value ~ "**Valeur p**"
  ) |>
  bold_labels() |>
  modify_caption(
    "**Tableau 5. Modèle de Cox du délai jusqu'à l'infection VIH**"
  )
Tableau 5. Modèle de Cox du délai jusqu’à l’infection VIH
Variables et modalités HR [IC à 95 %] 95% CI Valeur p
Traitement maternel


    Placebo
    AZT 0,66 0,44, 0,99 0,044
Site de suivi


    Abidjan, Côte d'Ivoire
    Bobo-Dioulasso, Burkina Faso 1,50 1,00, 2,24 0,048
Âge maternel 1,03 0,99, 1,07 0,11
CD4 maternel


    ≥ 350 cellules/mm³
    < 350 cellules/mm³ 3,81 2,54, 5,69 <0,001
Abbreviations: CI = Confidence Interval, HR = Hazard Ratio

Le hazard ratio (HR) compare le taux instantané d’infection entre les groupes. Il ne doit pas être interprété comme un risque relatif cumulé.

Aide à l’interprétation de l’analyse de survie

  • La courbe de Kaplan-Meier représente ici la probabilité de rester non infecté.
  • Une courbe AZT située au-dessus de la courbe placebo suggère une meilleure survie sans infection.
  • Le test du log-rank compare globalement les courbes sur toute la durée du suivi.
  • Le HR du traitement compare le taux instantané d’infection sous AZT à celui du placebo. Un HR inférieur à 1 indique une survenue moins rapide de l’infection sous AZT.
  • Le HR n’est pas un RR : il ne compare pas directement les proportions cumulées infectées.
  • L’hypothèse de proportionnalité doit être examinée avant de résumer l’effet par un HR unique.

13.5 Hypothèse des risques proportionnels

test_ph_infection <- cox.zph(cox_infection)
test_ph_infection
##             chisq df    p
## traitement 0,1424  1 0,71
## site_suivi 0,0406  1 0,84
## AGEINC     0,0858  1 0,77
## cd4_groupe 6,5634  1 0,01
## GLOBAL     6,9439  4 0,14
plot(test_ph_infection)

Une p-value élevée ne met pas en évidence de violation de l’hypothèse des risques proportionnels. Il faut toutefois examiner séparément chaque covariable et ne pas se limiter au test global. Une p-value inférieure à 0,05 pour une variable suggère que son effet pourrait varier au cours du temps ; une stratification, une interaction avec le temps ou une présentation temporelle de l’effet peut alors être envisagée. L’inspection des graphiques reste indispensable.

14 Analyse de la mortalité de l’enfant

Qu’en est-il du temps jusqu’au décès ?

tme_survie_deces <- tme |>
  mutate(
    evenement_deces = deces,
    date_fin_deces = if_else(
      evenement_deces == 1,
      DATE_DTH,
      DATE_LAST_BIO
    ),
    temps_deces_jours = as.numeric(date_fin_deces - DATBIRTH),
    temps_deces_mois = temps_deces_jours / 30.45
  ) |>
  filter(
    !is.na(temps_deces_mois),
    temps_deces_mois >= 0
  )

14.1 Kaplan-Meier pour la survie globale

km_globale <- survfit(
  Surv(temps_deces_mois, evenement_deces) ~ 1,
  data = tme_survie_deces
)
summary(tme_survie_deces)
##          ID          TTTGRP           AGEINC          CD4VAL      
##  Length   :397   Min.   :0,0000   Min.   :18,00   Min.   :  11,0  
##  N.unique :397   1st Qu.:0,0000   1st Qu.:21,00   1st Qu.: 359,0  
##  N.blank  :  0   Median :0,0000   Median :24,00   Median : 543,0  
##  Min.nchar:  5   Mean   :0,4962   Mean   :25,58   Mean   : 576,5  
##  Max.nchar:  5   3rd Qu.:1,0000   3rd Qu.:29,00   3rd Qu.: 741,0  
##                  Max.   :1,0000   Max.   :43,00   Max.   :1870,0  
##                                                   NAs    :8       
##    NIVINSTRUC         PARITY        HIVSTATUS          DATINF          
##  Min.   : 0,000   Min.   :0,000   Min.   :0,0000   Min.   :1996-01-07  
##  1st Qu.: 0,000   1st Qu.:1,000   1st Qu.:0,0000   1st Qu.:1996-09-20  
##  Median : 1,000   Median :1,000   Median :0,0000   Median :1997-10-03  
##  Mean   : 1,552   Mean   :1,907   Mean   :0,3879   Mean   :1997-07-21  
##  3rd Qu.: 2,000   3rd Qu.:3,000   3rd Qu.:1,0000   3rd Qu.:1998-01-15  
##  Max.   :12,000   Max.   :9,000   Max.   :9,0000   Max.   :1999-08-12  
##                                                    NAs    :297         
##     DATBIRTH              DTH_CH          DATE_DTH         
##  Min.   :1995-10-01   Min.   :0,0000   Min.   :1995-10-18  
##  1st Qu.:1996-06-21   1st Qu.:0,0000   1st Qu.:1997-05-27  
##  Median :1997-07-01   Median :0,0000   Median :1998-02-25  
##  Mean   :1997-03-16   Mean   :0,2242   Mean   :1998-01-17  
##  3rd Qu.:1997-10-31   3rd Qu.:0,0000   3rd Qu.:1998-08-03  
##  Max.   :1998-03-23   Max.   :1,0000   Max.   :2000-02-20  
##                                        NAs    :308         
##  DATE_LAST_BIO               SITE       traitement 
##  Min.   :1996-02-17   Length   :397   Placebo:200  
##  1st Qu.:1997-11-27   N.unique :  2   AZT    :197  
##  Median :1998-06-02   N.blank  :  0                
##  Mean   :1998-06-21   Min.nchar:  2                
##  3rd Qu.:1999-03-12   Max.nchar:  2                
##  Max.   :2000-04-04                                
##  NAs    :6                                         
##                         site_suivi        statut_vih  statut_deces
##  Abidjan, Côte d'Ivoire      :235   Non infecté:291   Vivant:308  
##  Bobo-Dioulasso, Burkina Faso:162   Infecté    :100   Décédé: 89  
##                                     Indéterminé:  6               
##                                                                   
##                                                                   
##                                                                   
##                                                                   
##    infection          deces                 niveau_instruction    age_groupe 
##  Min.   :0,0000   Min.   :0,0000   Aucune instruction:192      ≥ 25 ans:197  
##  1st Qu.:0,0000   1st Qu.:0,0000   Primaire          :187      < 25 ans:200  
##  Median :0,0000   Median :0,0000   Secondaire        : 18                    
##  Mean   :0,2558   Mean   :0,2242                                             
##  3rd Qu.:1,0000   3rd Qu.:0,0000                                             
##  Max.   :1,0000   Max.   :1,0000                                             
##  NAs    :6                                                                   
##               cd4_groupe                instruction_groupe   parite_groupe
##  ≥ 350 cellules/mm³:299   Secondaire ou supérieur: 18      Nullipare: 95  
##  < 350 cellules/mm³: 90   Aucune ou primaire     :379      Primipare:126  
##  NAs               :  8                                    Paucipare:136  
##                                                            Multipare: 40  
##                                                                           
##                                                                           
##                                                                           
##  evenement_deces  date_fin_deces       temps_deces_jours temps_deces_mois
##  Min.   :0,0000   Min.   :1995-10-18   Min.   :  0,0     Min.   : 0,000  
##  1st Qu.:0,0000   1st Qu.:1997-12-01   1st Qu.:303,0     1st Qu.: 9,951  
##  Median :0,0000   Median :1998-06-22   Median :549,0     Median :18,030  
##  Mean   :0,2242   Mean   :1998-07-01   Mean   :471,7     Mean   :15,492  
##  3rd Qu.:0,0000   3rd Qu.:1999-03-12   3rd Qu.:618,0     3rd Qu.:20,296  
##  Max.   :1,0000   Max.   :2000-04-04   Max.   :971,0     Max.   :31,888  
## 
ggsurvplot(
  km_globale,
  data = tme_survie_deces,
  color ="red",
  risk.table = TRUE,
  conf.int = TRUE,
  xlab = "Temps depuis la naissance (mois)",
  ylab = "Probabilité de rester non infecté",
  ggtheme = theme_survminer(base_size = 12),
  risk.table.height = 0.25
)

km_deces <- survfit(
  Surv(temps_deces_mois, evenement_deces) ~ traitement,
  data = tme_survie_deces
)

ggsurvplot(
  km_deces,
  data = tme_survie_deces,
  risk.table = TRUE,
  pval = TRUE,
  conf.int = TRUE,
  palette = unname(couleurs_traitement),
  xlab = "Âge de l'enfant (mois)",
  ylab = "Probabilité de survie",
  legend.title = "Traitement",
  legend.labs = c("Placebo", "AZT"),
  ggtheme = theme_minimal(base_size = 12),
  risk.table.height = 0.25
)

14.2 Modèle de Cox pour le décès

Dans le modèle principal de mortalité, le statut VIH de l’enfant n’est pas ajouté comme covariable, car il peut se situer sur le chemin causal entre le traitement et le décès. Pour les enfants vivants, DATE_LAST_BIO est utilisée comme date de dernière observation, faute de date clinique de dernière nouvelle distincte dans la base pédagogique.

modele3 <- coxph(
  Surv(temps_deces_mois, evenement_deces) ~
    traitement + site_suivi + age_groupe + cd4_groupe +
    niveau_instruction + parite_groupe,
  data = tme_survie_deces[!is.na(tme_survie_deces$CD4VAL),]
)
cox_deces <- step(modele3, direction = "backward",trace=FALSE)
cox_deces |>
  tbl_regression(
    exponentiate = TRUE,
    label = list(
      traitement ~ "Traitement maternel",
      age_groupe ~ "Âge maternel",
      cd4_groupe ~ "CD4 maternel"
    )
  ) |>
  modify_header(
    label ~ "**Variables et modalités**",
    estimate ~ "**HR [IC à 95 %]**",
    p.value ~ "**Valeur p**"
  ) |>
  bold_labels() |>
  modify_caption(
    "**Tableau 6. Modèle de Cox du délai jusqu'au décès de l'enfant**"
  )
Tableau 6. Modèle de Cox du délai jusqu’au décès de l’enfant
Variables et modalités HR [IC à 95 %] 95% CI Valeur p
Traitement maternel


    Placebo
    AZT 0,65 0,43, 1,00 0,051
Âge maternel


    ≥ 25 ans
    < 25 ans 0,65 0,42, 1,00 0,050
CD4 maternel


    ≥ 350 cellules/mm³
    < 350 cellules/mm³ 2,92 1,87, 4,54 <0,001
Abbreviations: CI = Confidence Interval, HR = Hazard Ratio
ggcoef_model(cox_deces, exponentiate = TRUE)

Aide à l’interprétation de la mortalité

La courbe de survie globale décrit la probabilité de rester vivant au cours du suivi. Dans le modèle de Cox, un HR de décès inférieur à 1 pour l’AZT suggère un taux instantané de décès plus faible que sous placebo. L’absence de significativité ne prouve pas l’absence d’effet : elle peut refléter un effet modéré, un nombre d’événements insuffisant ou une incertitude élevée. Le statut VIH de l’enfant n’est pas ajusté dans le modèle principal de mortalité, car il peut constituer un mécanisme intermédiaire par lequel l’AZT influence le décès.

15 Analyses de sensibilité des statuts indéterminés

Quatre scénarios sont comparés :

  1. analyse principale limitée aux statuts connus ;
  2. tous les indéterminés considérés infectés ;
  3. tous les indéterminés considérés non infectés ;
  4. scénario défavorable à l’AZT : indéterminés sous AZT considérés infectés et indéterminés sous placebo considérés non infectés.
Analyses de sensibilité des statuts VIH indéterminés
Scénario RR de l'AZT versus placebo
Statuts connus uniquement 0.71
Tous les indéterminés infectés 0.78
Tous les indéterminés non infectés 0.70
Scénario défavorable à l'AZT 0.82
ggplot(
  resultats_sensibilite,
  aes(x = RR, y = reorder(scenario, RR))
) +
  geom_vline(xintercept = 1, linetype = 2) +
  geom_point(size = 3) +
  labs(
    title = "Robustesse de l'effet estimé de l'AZT",
    x = "Risque relatif",
    y = NULL
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank(),
    panel.grid.major.y = element_blank()
  )

Si les conclusions restent similaires dans les différents scénarios, elles sont moins sensibles au traitement des statuts indéterminés.

16 Synthèse pour la prise de décision

La synthèse doit distinguer les différentes mesures :

  • le RR décrit l’effet du traitement sur le risque cumulé d’infection ;
  • la différence de risques renseigne sur l’effet absolu ;
  • le HR décrit le rythme de survenue de l’événement au cours du suivi ;
  • l’analyse stratifiée examine la stabilité de l’effet dans des sous-groupes ;
  • les analyses de sensibilité évaluent l’influence des statuts indéterminés.
difference_risque <- risque_azt - risque_placebo
reduction_relative <- 1 - rr
nnt <- 1 / abs(difference_risque)

synthese <- tibble(
  indicateur = c(
    "Risque d'infection sous placebo",
    "Risque d'infection sous AZT",
    "Risque relatif",
    "Réduction relative du risque",
    "Différence de risques",
    "Nombre nécessaire à traiter"
  ),
  valeur = c(
    percent(risque_placebo, accuracy = 0.1),
    percent(risque_azt, accuracy = 0.1),
    number(rr, accuracy = 0.01),
    percent(reduction_relative, accuracy = 0.1),
    percent(difference_risque, accuracy = 0.1),
    number(nnt, accuracy = 0.1)
  )
)

synthese |>
  gt() |>
  cols_label(
    indicateur = "Indicateur",
    valeur = "Estimation"
  ) |>
  tab_header(
    title = "Synthèse de l'efficacité estimée de l'AZT"
  )
Synthèse de l'efficacité estimée de l'AZT
Indicateur Estimation
Risque d'infection sous placebo 29.8%
Risque d'infection sous AZT 21.2%
Risque relatif 0.71
Réduction relative du risque 28.7%
Différence de risques -8.6%
Nombre nécessaire à traiter 11.7

16.1 Interprétation intégrée des résultats

16.1.1 Effet de l’AZT sur le risque cumulé d’infection

Parmi les enfants dont le statut VIH était connu, le risque d’infection était de 29.8% dans le groupe placebo contre 21.2% dans le groupe AZT. Le RR brut de l’AZT par rapport au placebo était de 0.71 [IC à 95 % : 0.50–1.01]. L’estimation correspond à une réduction relative du risque de 28.7% et à une différence absolue de -8.6%. Il faudrait traiter environ 11.7 femmes par ce schéma pour éviter une infection supplémentaire, si l’association observée reflète l’effet causal et si les conditions de l’étude sont transposables.

L’estimation brute est donc orientée vers un effet protecteur, mais avec un intervalle de confiance incluant 1. L’intervalle de confiance est particulièrement important : il indique les valeurs de l’effet encore compatibles avec les données et empêche de réduire la conclusion à la seule p-value.

16.1.2 Comparaison du RR et de l’OR

L’OR était de 0.64, contre un RR de 0.71. L’OR est plus éloigné de 1 que le RR et suggère visuellement un effet plus fort. Dans cet essai longitudinal, le RR doit être privilégié, car il compare directement les probabilités d’infection dans les deux groupes. L’OR ne doit pas être interprété comme une réduction du risque.

16.1.3 Analyses stratifiées

L’effet estimé de l’AZT était orienté dans le sens protecteur dans les deux sites : RR = 0.77 à Abidjan et RR = 0.65 à Bobo-Dioulasso. Les intervalles de confiance propres aux sites étaient larges, ce qui traduit une précision limitée dans les sous-groupes. L’absence d’interaction statistiquement mise en évidence signifie que les données ne démontrent pas formellement une différence d’efficacité entre les deux sites.

La stratification selon les CD4 suggère un effet plus marqué chez les femmes ayant un taux de CD4 d’au moins 350 cellules/mm³, avec un RR de 0.56, que chez celles présentant moins de 350 cellules/mm³, avec un RR de 0.90. Cette observation est cohérente avec les publications de suivi de DITRAME, qui rapportaient une efficacité plus faible chez les femmes présentant une immunodépression plus avancée. Elle doit néanmoins rester prudente : les analyses de sous-groupes comportent moins d’observations et peuvent être instables.

16.1.4 Analyse multivariée

Après ajustement sur le site, l’âge maternel, le niveau de CD4, l’instruction et la parité, le RR ajusté de l’AZT était de 0.71 [IC à 95 % : 0.51–0.99 ; p = 0.045]. Le modèle ajusté doit être interprété comme une analyse complémentaire au RR brut randomisé. Il porte sur les observations complètes pour les covariables, notamment les CD4, et peut donc concerner une population légèrement différente de celle du calcul brut.

16.1.5 Délai jusqu’à l’infection

Dans le modèle de Cox, le HR de l’AZT pour l’infection était de 0.66 [IC à 95 % : 0.44–0.99 ; p = 0.044]. Cette estimation est statistiquement compatible avec une réduction du taux instantané d’infection. Ainsi, le RR et le HR vont dans la même direction : l’AZT est associé à moins d’infections cumulées et à une survenue plus lente de l’infection pendant le suivi.

Le RR et le HR ne répondent toutefois pas à la même question :

  • le RR compare la proportion cumulée d’enfants infectés ;
  • le HR compare le rythme instantané d’apparition des infections au cours du suivi.

16.1.6 Effet de l’AZT sur le décès

Le HR de décès associé à l’AZT était de 0.65 [IC à 95 % : 0.43–1.00 ; p = 0.051]. L’estimation est orientée vers une réduction du taux instantané de décès, mais sans preuve statistique formelle au seuil de 5 %. Les données suggèrent donc un bénéfice possible sur la survie, mais la précision de l’estimation doit être examinée avant de conclure à un effet démontré sur la mortalité.

L’infection VIH est susceptible de se situer sur le chemin causal entre l’AZT et le décès. Pour cette raison, elle n’a pas été introduite comme covariable dans le modèle principal de mortalité : l’objectif était d’estimer l’effet total du traitement, direct et indirect.

16.1.7 Réponse aux objectifs de l’étude

Dans l’ensemble, les estimations vont majoritairement dans le sens d’un bénéfice de l’AZT :

  1. le risque d’infection est plus faible sous AZT, mais l’IC à 95 % du RR brut atteint ou inclut la valeur 1 ;
  2. le HR d’infection est inférieur à 1 et indique une survenue plus lente, mais sa significativité doit être appréciée à partir de l’IC à 95 % et de la p-value ;
  3. l’orientation protectrice est observée dans les deux sites, sans preuve formelle d’hétérogénéité ;
  4. le bénéfice paraît plus marqué chez les mères ayant un meilleur statut immunitaire à l’inclusion ;
  5. le HR de décès suggère une réduction possible de la mortalité, sans preuve statistique suffisamment précise pour conclure à un effet démontré dans cette analyse simplifiée.

Les analyses de sensibilité permettent enfin de vérifier si la conclusion principale reste stable lorsque différentes hypothèses sont appliquées aux statuts VIH indéterminés. La conclusion la plus fiable doit reposer sur la convergence entre le RR brut, le RR ajusté, le HR d’infection, les analyses stratifiées et les scénarios de sensibilité, plutôt que sur une seule p-value.

16.1.8 Mise en perspective avec les publications DITRAME

Dans l’article principal, la probabilité d’infection à 6 mois estimée par Kaplan-Meier était de 18,0 % dans le groupe zidovudine et de 27,5 % dans le groupe placebo, soit une efficacité relative publiée de 38 %. L’extrait pédagogique donne une estimation de même direction, mais moins marquée et moins précise, ce qui peut s’expliquer par la définition simplifiée de l’issue, la durée de suivi disponible et le fait que la base ne contient pas l’ensemble des informations du protocole original.

Pour la mortalité, la publication à 18 mois rapportait un effet du traitement qui variait au cours du temps, avec un hazard relatif inférieur à 1 au début du suivi. Le HR unique estimé dans le présent script est donc une synthèse pédagogique et doit être interprété après vérification de l’hypothèse des risques proportionnels. De même, l’analyse publiée à 24 mois utilisait des méthodes adaptées à l’infection connue par intervalle et montrait que l’efficacité à long terme dépendait fortement du niveau de CD4 maternel.

16.2 Ce qu’il faut retenir

  • RR d’infection : mesure principale de l’efficacité cumulée ; un RR inférieur à 1 favorise l’AZT.
  • OR : mesure des cotes, utile pour la comparaison pédagogique, mais moins directement interprétable ici.
  • HR d’infection : mesure de la vitesse de survenue de l’infection ; un HR inférieur à 1 indique une infection plus lente sous AZT.
  • HR de décès : mesure de la vitesse de survenue du décès ; une estimation inférieure à 1 suggère un bénéfice, mais l’IC à 95 % détermine la solidité de la conclusion.
  • CD4 maternels : facteur pronostique majeur et possible modificateur de l’efficacité ; les CD4 sont mesurés avant le traitement.
  • Randomisation : elle justifie de considérer le RR brut AZT versus placebo comme l’analyse causale principale.

17 Points de prudence

  • La base ne contient qu’une partie des données de l’essai original.
  • Le statut VIH indéterminé peut dépendre du suivi ou du décès.
  • Le modèle ajusté ne remplace pas l’analyse principale fondée sur la randomisation.
  • Le CD4 utilisé ici est mesuré à l’inclusion et ne doit pas être considéré comme une conséquence du traitement.
  • Les résultats historiques doivent être interprétés dans le contexte thérapeutique et éthique des années 1990.

Références scientifiques

  1. Dabis F, Msellati P, Meda N, et al. 6-month efficacy, tolerance, and acceptability of a short regimen of oral zidovudine to reduce vertical transmission of HIV in breastfed children in Côte d’Ivoire and Burkina Faso: a double-blind placebo-controlled multicentre trial. Lancet. 1999;353(9155):786–792. doi:10.1016/S0140-6736(98)11046-2.

  2. DITRAME ANRS 049 Study Group. 15-month efficacy of maternal oral zidovudine to decrease vertical transmission of HIV-1 in breastfed African children. Lancet. 1999;354:2050–2051.

  3. Dabis F, Elenga N, Meda N, et al. 18-month mortality and perinatal exposure to zidovudine in West Africa. AIDS. 2001;15(6):771–779.

  4. Leroy V, Montcho C, Manigart O, et al. Maternal plasma viral load, zidovudine and mother-to-child transmission of HIV-1 in Africa: DITRAME ANRS 049a trial. AIDS. 2001;15(4):517–522.

  5. Leroy V, Karon JM, Alioum A, et al. Twenty-four month efficacy of a maternal short-course zidovudine regimen to prevent mother-to-child transmission of HIV-1 in West Africa. AIDS. 2002;16(4):631–641.

  6. Leroy V, Karon JM, Alioum A, et al. Postnatal transmission of HIV-1 after a maternal short-course zidovudine peripartum regimen in West Africa. AIDS. 2003;17(10):1493–1501.