
Créer ADSL en R avec admiral : le jeu de données d’analyse au niveau sujet
Dérivez un ADSL conforme CDISC — variables de traitement, populations, disposition et tranches d’âge — à partir de SDTM avec admiral, l’ossature à une ligne par sujet sur laquelle repose tout autre jeu de données ADaM
Un tutoriel complet et exécutable pour ADSL, le jeu de données d’analyse au niveau sujet. Découvrez ce qu’est ADSL (une ligne par sujet — la source des variables de traitement, des indicateurs de population, de la disposition et des données démographiques pour chaque ADaM et TLF en aval), puis construisez un ADSL conforme en R à partir des domaines sources SDTM (DM, EX, DS) avec admiral : derive_vars_merged() pour les dates de traitement, derive_var_trtdurd() pour la durée de traitement, derive_vars_cat() pour les tranches d’âge, et des indicateurs de population tels que SAFFL et RANDFL — sur des données pharmaverse publiques, pour que chaque ligne s’exécute.
- ADSL est l’ossature de toute analyse. Il contient une ligne par sujet et constitue l’unique source des variables de traitement, des indicateurs de population, de la disposition et des données démographiques que tout autre jeu de données ADaM et chaque tableau, listing et figure rappellent.
- Vous le construisez à partir de SDTM, pas de zéro. Les attributs du sujet proviennent de DM, les dates de début/fin de traitement de EX, et la disposition (fin d’étude, randomisation) de DS — admiral les fusionne sur une trame unique au niveau sujet.
- admiral le dérive de façon déclarative.
derive_vars_merged()apporte le bon enregistrement d’un domaine source sur chaque sujet,derive_var_trtdurd()calcule la durée de traitement, etderive_vars_cat()construit des regroupements d’analyse tels queAGEGR1à partir d’une petite table de correspondance — sans logique de datescase_when()écrite à la main. - Les indicateurs de population décident qui est analysé.
SAFFL(sécurité : ayant reçu au moins une dose) etRANDFL(randomisé) sont des colonnes"Y"/"N"sur lesquelles les analyses en aval filtrent — réussissez-les dans ADSL et chaque décompte en aval est correct. - Une ligne par sujet est le contrat. La vérification finale de cohérence est que le nombre de lignes égale le nombre de
USUBJIDdistincts. Si c’est le cas, ADSL est prêt à être fusionné dans ADAE, ADTTE, ADLB et le tableau démographique.
Introduction
Avant qu’un seul tableau démographique, résumé d’événements indésirables ou courbe de Kaplan-Meier puisse être produit, quelqu’un doit construire ADSL — le jeu de données d’analyse au niveau sujet. ADSL est le premier jeu de données ADaM (Analysis Data Model) que vous créez et celui dont dépend tout autre jeu de données : il porte, pour chaque sujet exactement une fois, son traitement, ses populations d’analyse, sa disposition et les regroupements démographiques selon lesquels chaque tableau en aval sera ventilé.
Réussissez ADSL et le reste du livrable se met en place, car tout autre jeu de données ADaM rappelle ses variables clés depuis ADSL au lieu de les redériver. Ratez-le — un sujet dupliqué, un indicateur de sécurité mal positionné — et l’erreur se propage dans chaque décompte de la soumission. Cette leçon construit un ADSL conforme en R avec admiral, le package pharmaverse pour la dérivation ADaM, en travaillant sur des données d’exemple publiques pharmaverse pour que chaque ligne s’exécute telle quelle. La construction suit la vignette officielle ADSL d’admiral, réécrite en un seul parcours guidé.
Voici où nous allons — la disposition par bras de traitement, calculée directement à partir de l’ADSL que nous dérivons :
Cette figure se lit sur quatre colonnes d’ADSL — TRT01A, EOSSTT, SAFFL, et une ligne par sujet. À la fin de cette leçon, vous les aurez toutes dérivées. Si « ADaM », « BDS » ou « SDTM » vous sont nouveaux, commencez par les standards CDISC, qui situent la place d’ADSL. Vous venez de SAS ? La carte SAS vers R explique pourquoi admiral joue le rôle d’une bibliothèque de macros de dérivation validée.
Ce qu’est ADSL
ADSL est le jeu de données d’analyse au niveau sujet défini par le standard CDISC ADaM. Sa structure est la plus simple de tout ADaM et la raison pour laquelle tout le reste en découle : exactement une ligne par sujet, identifiée par USUBJID. Il n’y a pas de PARAMCD, pas de visite, pas de répétition — un sujet, une ligne, de nombreuses colonnes.
Tout autre jeu de données ADaM (ADAE, ADTTE, ADLB, ADVS) est construit en fusionnant les variables d’ADSL sur ses propres enregistrements : ADSL est donc l’endroit où le traitement, les populations et les dates clés sont définis une seule fois puis hérités partout. C’est aussi pourquoi un sujet dupliqué dans ADSL est une erreur grave — il dupliquerait chaque fusion en aval.
Les colonnes se répartissent en quelques groupes. Voici les colonnes porteuses que cette leçon dérive :
| Groupe | Variables | Ce qu’elles contiennent |
|---|---|---|
| Sujet et démographie | STUDYID, USUBJID, AGE, SEX, RACE, ETHNIC, COUNTRY |
Identité et caractéristiques de référence, majoritairement reprises de DM. |
| Traitement | TRT01P, TRT01A, TRTSDT, TRTEDT, TRTDURD |
Traitement prévu et réel, dates de première/dernière dose, et durée de traitement en jours. |
| Disposition | RANDDT, EOSDT, EOSSTT, DCSREAS |
Date de randomisation, date de fin d’étude, statut de fin d’étude et motif d’arrêt. |
| Regroupements | AGEGR1, REGION1 |
Catégories d’analyse (tranches d’âge, région géographique) selon lesquelles les tableaux sont ventilés. |
| Indicateurs de population | SAFFL, RANDFL, ITTFL |
Indicateurs "Y"/"N" marquant quels sujets appartiennent aux populations de sécurité, randomisée et en intention de traiter. |
Deux conventions méritent d’être fixées d’emblée :
- Les variables de traitement sont numérotées par période.
TRT01Pest le traitement prévu pour la période 01,TRT01Ale traitement réel pour la période 01. Un essai parallèle simple n’a que la période 01 ; les plans en cross-over ajoutentTRT02P,TRT02A, et ainsi de suite. La distinctionP/A(prévu vs réel) importe parce que les sujets ne reçoivent pas toujours ce qui leur a été assigné. - Les indicateurs de population sont
"Y"/"N", jamaisTRUE/FALSE. ADaM les stocke comme des indicateurs à un seul caractère pour que le code en aval filtre avecSAFFL == "Y". Un sujet randomisé mais jamais dosé estRANDFL == "Y"maisSAFFL == "N"— exactement la distinction qui garantit l’exactitude de vos décomptes de sécurité.
L’essai que nous utilisons est l’étude pilote CDISC livrée dans pharmaversesdtm — une étude synthétique, libre de licence, à bras parallèles comparant un placebo à deux doses de Xanomeline.
Les données sources
admiral construit ADSL en partant de DM (déjà une ligne par sujet — l’ossature ADSL naturelle) et en fusionnant ce dont il a besoin depuis les autres domaines SDTM. Nous en utilisons trois :
- DM — démographie : la liste des sujets plus
AGE,SEX,RACE,COUNTRY, et le bras prévu/réel (ARM/ACTARM). - EX — exposition : les enregistrements de dosage, source des dates de première et de dernière dose.
- DS — disposition : les enregistrements d’événements d’étude, source des informations de randomisation et de fin d’étude.
library(admiral)
library(dplyr, warn.conflicts = FALSE)
library(pharmaversesdtm)
library(lubridate)
library(stringr)
# convert_blanks_to_na() turns SDTM's empty strings "" into proper NA
dm <- pharmaversesdtm::dm %>% convert_blanks_to_na()
ex <- pharmaversesdtm::ex %>% convert_blanks_to_na()
ds <- pharmaversesdtm::ds %>% convert_blanks_to_na()
dm %>%
select(USUBJID, ARM, ACTARM, AGE, SEX, RACE, COUNTRY) %>%
head(5)# A tibble: 5 × 7
USUBJID ARM ACTARM AGE SEX RACE COUNTRY
<chr> <chr> <chr> <dbl> <chr> <chr> <chr>
1 01-701-1015 Placebo Placebo 63 F WHITE USA
2 01-701-1023 Placebo Placebo 64 M WHITE USA
3 01-701-1028 Xanomeline High Dose Xanomeline High Do… 71 M WHITE USA
4 01-701-1033 Xanomeline Low Dose Xanomeline Low Dose 74 M WHITE USA
5 01-701-1034 Xanomeline High Dose Xanomeline High Do… 77 F WHITE USA
DM a déjà une ligne par sujet : c’est donc la trame à laquelle nous ajoutons. convert_blanks_to_na() est une première étape modeste mais essentielle : les variables caractères SDTM utilisent des chaînes vides pour les données manquantes, et les fonctions de dates et de fusion d’admiral attendent un vrai NA.
Démarrer ADSL depuis DM et définir le traitement
Le premier geste consiste à prendre DM comme ossature d’ADSL et à définir les variables de traitement. Dans le pilote CDISC, le traitement prévu est le bras randomisé ARM et le traitement réel est ACTARM : cette étape est donc une affectation directe. Nous retirons DOMAIN (une colonne de gestion technique SDTM qui n’a pas sa place dans ADaM).
adsl <- dm %>%
select(-DOMAIN) %>%
mutate(
TRT01P = ARM, # planned treatment, period 01
TRT01A = ACTARM # actual treatment, period 01
)
adsl %>%
select(USUBJID, ARM, TRT01P, ACTARM, TRT01A) %>%
head(5)# A tibble: 5 × 5
USUBJID ARM TRT01P ACTARM TRT01A
<chr> <chr> <chr> <chr> <chr>
1 01-701-1015 Placebo Placebo Placebo Place…
2 01-701-1023 Placebo Placebo Placebo Place…
3 01-701-1028 Xanomeline High Dose Xanomeline High Dose Xanomeline High … Xanom…
4 01-701-1033 Xanomeline Low Dose Xanomeline Low Dose Xanomeline Low D… Xanom…
5 01-701-1034 Xanomeline High Dose Xanomeline High Dose Xanomeline High … Xanom…
Dans une étude réelle, TRT01A n’est souvent pas une copie d’ACTARM — il peut exiger sa propre dérivation lorsque le traitement réel diffère du bras SDTM. Ici, ils coïncident, ce qui maintient l’accent sur la structure.
Dériver les dates et la durée de traitement
Les dates de début (TRTSDT) et de fin (TRTEDT) de traitement proviennent de EX, le domaine d’exposition. Un sujet a de nombreux enregistrements de dosage ; nous voulons la première date de dose valide comme début et la dernière comme fin. admiral procède en deux temps : convertir les datetimes de dose caractères en vrais datetimes R, puis fusionner la première et la dernière sur ADSL.
# Stage 1: impute and convert EX dose datetimes.
# Start date keeps its time; end date imputes a missing time to the last of the day.
ex_ext <- ex %>%
derive_vars_dtm(dtc = EXSTDTC, new_vars_prefix = "EXST") %>%
derive_vars_dtm(dtc = EXENDTC, new_vars_prefix = "EXEN", time_imputation = "last")
# Stage 2: merge the first valid dose (start) and last valid dose (end) onto ADSL.
# The filter keeps only actual exposure: a positive dose, or a zero-dose placebo record.
adsl <- adsl %>%
derive_vars_merged(
dataset_add = ex_ext,
filter_add = (EXDOSE > 0 | (EXDOSE == 0 & str_detect(EXTRT, "PLACEBO"))) & !is.na(EXSTDTM),
new_vars = exprs(TRTSDTM = EXSTDTM, TRTSTMF = EXSTTMF),
order = exprs(EXSTDTM, EXSEQ),
mode = "first",
by_vars = exprs(STUDYID, USUBJID)
) %>%
derive_vars_merged(
dataset_add = ex_ext,
filter_add = (EXDOSE > 0 | (EXDOSE == 0 & str_detect(EXTRT, "PLACEBO"))) & !is.na(EXENDTM),
new_vars = exprs(TRTEDTM = EXENDTM, TRTETMF = EXENTMF),
order = exprs(EXENDTM, EXSEQ),
mode = "last",
by_vars = exprs(STUDYID, USUBJID)
) %>%
# Keep the date part only (analyses split on dates, not datetimes)
derive_vars_dtm_to_dt(source_vars = exprs(TRTSDTM, TRTEDTM)) %>%
# TRTDURD = treatment duration in days, from TRTSDT to TRTEDT
derive_var_trtdurd()
adsl %>%
select(USUBJID, TRTSDT, TRTEDT, TRTDURD) %>%
head(5)# A tibble: 5 × 4
USUBJID TRTSDT TRTEDT TRTDURD
<chr> <date> <date> <dbl>
1 01-701-1015 2014-01-02 2014-07-02 182
2 01-701-1023 2012-08-05 2012-09-01 28
3 01-701-1028 2013-07-19 2014-01-14 180
4 01-701-1033 2014-03-18 2014-03-31 14
5 01-701-1034 2014-07-01 2014-12-30 183
derive_vars_merged() est le cheval de bataille d’admiral : depuis un jeu de données source, il choisit un enregistrement par sujet (mode = "first" ou "last", ordonné par order), le filtre (filter_add), et écrit les valeurs retenues dans de nouvelles colonnes d’ADSL (new_vars). Le filter_add ici est la définition standard du « traité » — une dose positive, ou un enregistrement placebo à dose nulle (le placebo est dosé, simplement à zéro). derive_var_trtdurd() calcule ensuite TRTDURD comme le nombre de jours inclusif de TRTSDT à TRTEDT, si bien qu’un sujet dosé du 2 janvier au 2 juillet affiche 182 jours. Aucune soustraction de dates à la main.
Dériver la disposition : randomisation, fin d’étude et statut
La disposition vit dans DS, le domaine des événements d’étude. Trois éléments comptent pour ADSL : la date de randomisation (RANDDT), la date de fin d’étude (EOSDT) et le statut de fin d’étude (EOSSTT — terminé, arrêté, ou échec de sélection). Chacun est une fusion depuis une tranche filtrée différente de DS.
# Convert the DS start date to a real date once, reuse it for both merges
ds_ext <- derive_vars_dt(ds, dtc = DSSTDTC, new_vars_prefix = "DSST")
# A small helper to collapse the many DSDECOD values into a clean status
format_eosstt <- function(x) {
case_when(
x %in% c("COMPLETED") ~ "COMPLETED",
x %in% c("SCREEN FAILURE") ~ NA_character_, # screen failures have no end-of-study status
TRUE ~ "DISCONTINUED"
)
}
adsl <- adsl %>%
# RANDDT: the date of the RANDOMIZED milestone
derive_vars_merged(
dataset_add = ds_ext,
filter_add = DSDECOD == "RANDOMIZED",
by_vars = exprs(STUDYID, USUBJID),
new_vars = exprs(RANDDT = DSSTDT)
) %>%
# EOSDT: the disposition-event date (excluding the screen-failure record)
derive_vars_merged(
dataset_add = ds_ext,
filter_add = DSCAT == "DISPOSITION EVENT" & DSDECOD != "SCREEN FAILURE",
by_vars = exprs(STUDYID, USUBJID),
new_vars = exprs(EOSDT = DSSTDT)
) %>%
# EOSSTT: completed / discontinued / (NA for screen failures), default ONGOING
derive_vars_merged(
dataset_add = ds,
filter_add = DSCAT == "DISPOSITION EVENT",
by_vars = exprs(STUDYID, USUBJID),
new_vars = exprs(EOSSTT = format_eosstt(DSDECOD)),
missing_values = exprs(EOSSTT = "ONGOING")
)
adsl %>%
select(USUBJID, RANDDT, EOSDT, EOSSTT) %>%
head(5)# A tibble: 5 × 4
USUBJID RANDDT EOSDT EOSSTT
<chr> <date> <date> <chr>
1 01-701-1015 2014-01-02 2014-07-02 COMPLETED
2 01-701-1023 2012-08-05 2012-09-02 DISCONTINUED
3 01-701-1028 2013-07-19 2014-01-14 COMPLETED
4 01-701-1033 2014-03-18 2014-04-14 DISCONTINUED
5 01-701-1034 2014-07-01 2014-12-30 COMPLETED
Le schéma se répète — filtrer DS sur les enregistrements qui définissent chaque variable, fusionner la valeur retenue sur le sujet. format_eosstt() ramène la douzaine de valeurs possibles de DSDECOD aux trois statuts qui intéressent une analyse ; missing_values fournit "ONGOING" pour tout sujet sans enregistrement de disposition. Un décompte rapide confirme la répartition :
adsl %>% count(EOSSTT)# A tibble: 3 × 2
EOSSTT n
<chr> <int>
1 COMPLETED 110
2 DISCONTINUED 144
3 <NA> 52
110 sujets ont terminé, 144 ont arrêté, et 52 échecs de sélection portent un NA (ils n’ont pas de statut de fin d’étude car ils n’ont jamais été sous étude). Ce groupe NA est la population d’échecs de sélection — ils restent dans ADSL mais sont exclus de l’analyse par les indicateurs de population ci-dessous.
Dériver les regroupements d’analyse : tranche d’âge et région
Les tableaux ne ventilent presque jamais selon l’âge brut ; ils ventilent par tranche d’âge. ADaM stocke la tranche dans AGEGR1, et admiral la dérive à partir d’une petite table de correspondance lisible avec derive_vars_cat() — bien plus clair qu’un case_when() imbriqué. Nous ajoutons une région géographique REGION1 de la même manière.
# Lookup tables: each row is condition -> category. First match wins.
agegr1_lookup <- exprs(
~condition, ~AGEGR1,
AGE < 18, "<18",
between(AGE, 18, 64), "18-64",
AGE > 64, ">64",
is.na(AGE), "Missing"
)
region1_lookup <- exprs(
~condition, ~REGION1,
COUNTRY %in% c("CAN", "USA"), "North America",
!is.na(COUNTRY), "Rest of the World",
is.na(COUNTRY), "Missing"
)
adsl <- adsl %>%
derive_vars_cat(definition = agegr1_lookup) %>%
derive_vars_cat(definition = region1_lookup)
adsl %>% count(AGEGR1)# A tibble: 2 × 2
AGEGR1 n
<chr> <int>
1 18-64 42
2 >64 264
C’est un essai chez l’adulte : chaque sujet atterrit donc dans 18-64 (42 sujets) ou >64 (264) — aucun moins de 18 ans. Définir la tranche une fois dans ADSL signifie que le tableau démographique, le tableau des EI et le tableau d’efficacité ventilent tous sur le même AGEGR1, sans risque que trois programmes découpent l’âge de trois façons différentes.
Dériver les indicateurs de population
Les indicateurs de population décident qui est compté dans chaque analyse. Deux sont fondamentaux :
SAFFL(indicateur de population de sécurité) —"Y"si le sujet a pris au moins une dose du médicament à l’étude. C’est le dénominateur de chaque tableau de sécurité.RANDFL(indicateur de randomisation) —"Y"si le sujet a été randomisé.
SAFFL répond à la question « existe-t-il un enregistrement qualifiant dans EX ? », ce à quoi derive_var_merged_exist_flag() répond précisément. RANDFL, nous pouvons le lire directement sur le RANDDT que nous avons déjà dérivé.
adsl <- adsl %>%
# SAFFL = "Y" if the subject has any actual-dose EX record, else "N"
derive_var_merged_exist_flag(
dataset_add = ex,
by_vars = exprs(STUDYID, USUBJID),
new_var = SAFFL,
false_value = "N",
missing_value = "N",
condition = (EXDOSE > 0 | (EXDOSE == 0 & str_detect(EXTRT, "PLACEBO")))
) %>%
# RANDFL = "Y" if the subject was randomized (has a RANDDT)
mutate(RANDFL = if_else(!is.na(RANDDT), "Y", "N"))
adsl %>% count(SAFFL, RANDFL)# A tibble: 2 × 3
SAFFL RANDFL n
<chr> <chr> <int>
1 N N 52
2 Y Y 254
254 sujets sont à la fois randomisés et dosés (Y/Y) ; 52 ne sont ni l’un ni l’autre (N/N) — les échecs de sélection, qui n’ont jamais dépassé la sélection. Les indicateurs concordent ici, mais ils ne posent pas la même question : un sujet randomisé puis retiré avant le dosage serait RANDFL == "Y", SAFFL == "N", et compterait dans une analyse en intention de traiter mais pas dans une analyse de sécurité. C’est tout l’intérêt de porter les deux.
Vérifier la cohérence du résultat
ADSL a un contrat strict : une ligne par sujet. Vérifiez-le avant que quoi que ce soit ne lise ce jeu de données.
# The contract: rows == distinct subjects
nrow(adsl)[1] 306
n_distinct(adsl$USUBJID)[1] 306
# A compact view of the analysis-ready columns
adsl %>%
select(USUBJID, TRT01A, TRTSDT, TRTEDT, TRTDURD, AGEGR1, EOSSTT, SAFFL, RANDFL) %>%
head(5)# A tibble: 5 × 9
USUBJID TRT01A TRTSDT TRTEDT TRTDURD AGEGR1 EOSSTT SAFFL RANDFL
<chr> <chr> <date> <date> <dbl> <chr> <chr> <chr> <chr>
1 01-701-1015 Placebo 2014-01-02 2014-07-02 182 18-64 COMPL… Y Y
2 01-701-1023 Placebo 2012-08-05 2012-09-01 28 18-64 DISCO… Y Y
3 01-701-1028 Xanomeli… 2013-07-19 2014-01-14 180 >64 COMPL… Y Y
4 01-701-1033 Xanomeli… 2014-03-18 2014-03-31 14 >64 DISCO… Y Y
5 01-701-1034 Xanomeli… 2014-07-01 2014-12-30 183 >64 COMPL… Y Y
306 lignes, 306 sujets distincts — le contrat tient. Si ces deux nombres venaient à différer, c’est qu’une fusion a ramené plus d’un enregistrement par sujet (généralement un mode/order manquant sur une source un-à-plusieurs), et vous devez le corriger avant de continuer : chaque fusion en aval hériterait de la duplication. La vérification passant, cet ADSL est prêt à alimenter ADAE, ADTTE, ADLB et le tableau démographique — chacun rappellera ses variables de traitement et de population directement d’ici avec derive_vars_merged().
Demandez à Prova « comment ajouter un poids, une taille et un IMC de référence à mon ADSL depuis le domaine SDTM VS avec admiral ? » — elle répond en s’appuyant sur les leçons de ce pilier, avec du code admiral exécutable que vous pouvez essayer sur les données d’exemple pharmaverse. The runtime is the judge. Demandez à Prova →
Problèmes fréquents
ADSL a plus de lignes que de sujets. Un appel derive_vars_merged() a apparié plus d’un enregistrement source par sujet. Le remède est toujours mode + order : avec mode = "first"/"last" et une expression order, admiral choisit exactement un enregistrement. Si vous les omettez sur une source un-à-plusieurs (comme EX, qui a de nombreuses lignes de dose par sujet), la fusion peut se démultiplier. Relancez la vérification nrow() vs n_distinct(USUBJID) après chaque fusion tant que vous apprenez.
TRTSDT vaut NA pour des sujets que vous attendiez dosés. Le filter_add a retiré leurs enregistrements EX. La cause habituelle est la condition de dose : EXDOSE > 0 seul écarte les sujets sous placebo, dont l’EXDOSE vaut 0. Utilisez EXDOSE > 0 | (EXDOSE == 0 & str_detect(EXTRT, "PLACEBO")) pour que le dosage placebo compte. La même condition doit piloter SAFFL, sinon votre indicateur de sécurité et vos dates de traitement seront en désaccord.
Chaque comparaison avec une variable caractère SDTM se comporte bizarrement. Vous avez sauté convert_blanks_to_na(). SDTM utilise des chaînes vides "" pour les valeurs manquantes, si bien que is.na() renvoie FALSE dessus et que l’imputation de dates s’étrangle. Exécutez toujours convert_blanks_to_na() sur chaque domaine SDTM en première étape, avant toute dérivation.
Questions fréquentes
ADSL est le jeu de données d’analyse au niveau sujet — le jeu de données ADaM avec une ligne par sujet qui contient les variables de traitement, les indicateurs de population, la disposition et les données démographiques clés. C’est le premier jeu de données ADaM construit et l’ossature dont tout autre jeu de données ADaM (ADAE, ADTTE, ADLB) rappelle ses variables au niveau sujet. Le standard CDISC ADaM en définit la structure.
Partez du domaine SDTM DM (déjà une ligne par sujet), définissez les variables de traitement, puis fusionnez ce dont vous avez besoin depuis les autres domaines : les dates de traitement depuis EX avec derive_vars_merged(), la durée de traitement avec derive_var_trtdurd(), la disposition depuis DS, les tranches d’âge avec derive_vars_cat(), et les indicateurs de population tels que SAFFL avec derive_var_merged_exist_flag(). La séquence complète est détaillée ci-dessus et suit la vignette ADSL d’admiral.
TRT01P est le traitement prévu pour la période 01 (ce à quoi le sujet a été randomisé) ; TRT01A est le traitement réel qu’il a reçu. Ils diffèrent quand un sujet est dosé avec autre chose que son bras assigné — par exemple une erreur de dispensation. Le 01 est le numéro de période : un essai en cross-over ajoute donc TRT02P/TRT02A pour la période 02.
SAFFL est l’indicateur de population de sécurité — "Y" pour tout sujet ayant pris au moins une dose du médicament à l’étude ; c’est le dénominateur des tableaux de sécurité. RANDFL signale les sujets qui ont été randomisés. Ils diffèrent pour un sujet randomisé mais jamais dosé : RANDFL == "Y" mais SAFFL == "N". Les indicateurs de population sont stockés comme des caractères "Y"/"N" pour que le code en aval filtre avec SAFFL == "Y".
Au minimum DM (démographie — l’ossature des sujets), EX (exposition — dates de début/fin de traitement) et DS (disposition — randomisation et fin d’étude). Des ADSL plus riches tirent aussi des caractéristiques de référence de VS (signes vitaux : poids, taille, IMC), des dates de dernière nouvelle de vie de AE/LB, et des informations de décès, mais DM, EX et DS sont les trois domaines de base pour un ADSL conforme traitement-et-population.
Parce que tout autre jeu de données ADaM le lit. ADAE, ADTTE, ADLB et ADVS fusionnent chacun les variables de traitement, indicateurs de population et dates clés d’ADSL sur leurs propres enregistrements avec derive_vars_merged() au lieu de les redériver. Définir ces variables une seule fois, dans ADSL, garantit qu’elles sont identiques partout en aval — ADSL doit donc exister et être correct avant que toute autre dérivation ADaM ne commence.
Testez vos connaissances
La population en intention de traiter (ITT) est composée de tout sujet randomisé, analysé tel que randomisé. En partant de l’objet adsl construit dans cette leçon, ajoutez un indicateur ITTFL qui vaut "Y" pour chaque sujet randomisé et "N" sinon, puis comptez combien de sujets sont dans la population ITT.
L’ITT est définie par la randomisation : ITTFL suit donc la même logique que RANDFL — dérivez-le de RANDDT avec mutate() + if_else() + !is.na(). Attention : vous ne pouvez pas le caler sur TRT01P. Les échecs de sélection portent ARM = "Screen Failure" (une chaîne non manquante), si bien que !is.na(TRT01P) signalerait à tort les 306 sujets.
adsl <- adsl %>%
mutate(ITTFL = if_else(!is.na(RANDDT), "Y", "N"))
adsl %>% count(ITTFL)ITTFL vaut "Y" pour les 254 sujets randomisés — il correspond à RANDFL ici parce que l’ITT est définie par la randomisation. Le piège : le tentant if_else(!is.na(TRT01P), "Y", "N") renvoie 306, et non 254, parce que les 52 échecs de sélection portent ARM = "Screen Failure" — une chaîne de traitement prévu non manquante, pas une valeur manquante. L’ITT est définie par la randomisation, jamais par « a une valeur de bras prévu ». C’est exactement le genre de subtilité de population qu’ADSL fixe une fois, pour toute la soumission.
A. Une ligne par sujet par visite B. Une ligne par sujet par paramètre C. Une ligne par sujet
C. ADSL est le jeu de données d’analyse au niveau sujet — une ligne par sujet, un point c’est tout. A décrit une structure au niveau de la visite (comme les enregistrements d’occurrence ADVS) et B décrit la structure de données de base (BDS) utilisée par ADTTE et ADLB. Le contrat une-ligne-par-sujet est ce qui permet à tout autre jeu de données ADaM de fusionner les variables d’ADSL par USUBJID sans dupliquer de lignes.
Conclusion
ADSL ressemble à une longue liste de colonnes, mais c’est en réalité quatre décisions prises une fois par sujet : quel traitement il a reçu (TRT01P/TRT01A, TRTSDT/TRTEDT/TRTDURD), comment son étude s’est terminée (RANDDT, EOSDT, EOSSTT), dans quels groupes d’analyse il tombe (AGEGR1, REGION1), et à quelles populations il appartient (SAFFL, RANDFL). admiral transforme chaque décision en une fusion déclarative — derive_vars_merged(), derive_var_trtdurd(), derive_vars_cat(), derive_var_merged_exist_flag() — lisible et traçable jusqu’à la source SDTM. Construisez ADSL correctement, confirmez le contrat une-ligne-par-sujet, et chaque jeu de données et tableau en aval hérite de variables au niveau sujet propres et cohérentes au lieu de les redériver. ADSL n’est pas seulement le premier jeu de données ADaM — c’est celui qui rend tous les autres faciles.
Cette leçon est reproductible : chaque résultat de cette page a été produit par le code montré — copiez n’importe quel bloc et exécutez-le pour les reproduire. The runtime is the judge.
Leçons connexes
- Les standards CDISC : CDASH, SDTM, ADaM, Define-XML — où ADSL et le modèle ADaM se situent dans le pipeline CDISC. · Le flux de données d’un essai clinique — comment les données brutes DM, EX et DS deviennent les domaines SDTM que lit cette leçon. · Construire le jeu de données ADaM de délai jusqu’à l’événement (ADTTE) — le prochain jeu de données ADaM, qui rappelle le traitement et les covariables de cet ADSL sur ses enregistrements d’événements. · Le passage de SAS à R en programmation clinique — pourquoi admiral joue le rôle d’une bibliothèque de macros de dérivation validée.
- Où cela s’inscrit : les fondations réglementaires et CDISC → construire ADaM avec admiral (ADSL — vous êtes ici → ADTTE et les jeux de données BDS) → produire les tableaux, listings et figures que chaque analyse livre. ADSL est l’ossature au niveau sujet dont tous ces jeux de données partent.
Réutilisation
Citation
@online{2026,
author = {},
title = {Créer ADSL en R avec admiral : le jeu de données d’analyse au
niveau sujet},
date = {2026-06-30},
url = {https://www.datanovia.com/learn/pharma-clinical/03-adam-admiral/create-adsl-admiral},
langid = {fr}
}