Domaine SDTM EX en R avec sdtm.oak : exposition

Mappez un extrait brut de dosage du médicament à l’étude vers un domaine SDTM EX conforme à CDISC en R avec sdtm.oak — la classe d’observation Interventions, les qualificateurs dose/voie/fréquence, les dates ISO 8601, le numéro de séquence et les jours d’étude

Un tutoriel complet et exécutable pour le domaine SDTM EX (exposure, exposition) en R. Découvrez ce qu’est la classe d’observation Interventions de SDTM CDISC (un enregistrement par épisode d’administration, indexé par la variable topic EXTRT), en quoi elle diffère des classes Findings et Events, puis mappez un extrait de dosage brut vers un domaine EX conforme avec sdtm.oak : generate_oak_id_vars() pour la traçabilité des enregistrements, assign_no_ct() pour le traitement et la quantité de dose, assign_ct() pour les qualificateurs de Controlled Terminology (EXDOSU/EXDOSFRM/EXDOSFRQ/EXROUTE), assign_datetime() pour les EXSTDTC/EXENDTC ISO 8601, derive_seq() pour EXSEQ, et derive_study_day() pour EXSTDY/EXENDY — chaque ligne exécutable, l’enregistrement d’exposition que lit chaque analyse d’efficacité et de sécurité.

Date de publication

1 juillet 2026

Modifié

7 juillet 2026

AstucePoints clés
  • EX est un domaine Interventions — une troisième forme d’enregistrement. La classe Findings (signes vitaux, analyses biologiques) enregistre des mesures ; la classe Events (événements indésirables) enregistre des choses qui sont arrivées ; la classe Interventions enregistre des choses administrées au sujet — une ligne par épisode de dosage, indexée par le traitement EXTRT.
  • La variable topic est EXTRT, le traitement administré. assign_no_ct() copie le nom de traitement défini par l’étude tel que collecté ; la quantité de dose EXDOSE est copiée de la même façon.
  • Les descripteurs de dose, eux, sont contrôlés. assign_ct() recode l’unité, la forme galénique, la fréquence et la voie collectées vers leurs termes standard CDISC (EXDOSU, EXDOSFRM, EXDOSFRQ, EXROUTE).
  • Un épisode d’exposition est borné par deux dates ISO 8601. assign_datetime() construit le début (EXSTDTC) et la fin (EXENDTC) qui fixent la période où le sujet était sous traitement.
  • derive_seq() numérote les épisodes et derive_study_day() les situe sur le calendrier de l’étude. EXSEQ est unique par sujet ; EXSTDY/EXENDY comptent les jours depuis la date de référence — et l’ensemble du domaine devient l’entrée que lisent les variables de traitement d’ADSL.

Introduction

Le sujet a pris 54 mg de médicament à l’étude par voie transdermique de janvier à juin, puis sa dose a été augmentée à 81 mg. Cet enregistrement d’administration a une seule mission : parvenir au régulateur sous la forme du domaine SDTM (Study Data Tabulation Model) EX (exposure, exposition) — l’exposition à laquelle est comparée chaque analyse d’efficacité et de sécurité. Ce que le site enregistre est plus approximatif : une page de CRF (case report form, cahier d’observation) avec un nom de médicament, un nombre, une forme cochée « Patch », une date de début et de fin saisies comme le coordinateur les a saisies. Le travail ici consiste à transformer cet extrait brut en un domaine EX conforme qu’un évaluateur peut ouvrir et lire de la même façon pour n’importe quelle étude.

Cette leçon réalise ce mapping de bout en bout en R avec sdtm.oak, le package pharmaverse pour la transformation des données brutes en SDTM. Elle complète le trio des classes d’observation : le domaine Findings (signes vitaux) enregistre ce qui a été mesuré, le domaine Events (événements indésirables) enregistre ce qui est arrivé, et EX enregistre ce qui a été administré — les mêmes algorithmes oak, une troisième forme d’enregistrement. Le SDTM est l’amont du flux de données clinique — brut → SDTM → ADaM → tables, listings et figures (TLF) — de sorte qu’un domaine EX propre ici permet à la couche d’analyse de dériver les dates de début et de fin de traitement qui ancrent le jeu de données ADSL de niveau sujet.

Voici où nous allons — le domaine EX conforme que nous allons construire, dessiné comme la chronologie d’exposition qu’il encode, directement à partir du résultat mappé :

Exposure-timeline (Gantt) chart of the mapped SDTM EX domain. Each horizontal segment is one dosing episode for a subject (six subjects on the y axis), running from its start date EXSTDTC to its end date EXENDTC on the x axis, coloured by dose: grey for the 0 mg placebo arm, light azure for 54 mg, dark azure for the 81 mg up-titration. Subjects on active drug show one to three consecutive segments — some stepping up in dose over months, some continuing at the same dose across a new dosing interval; the two placebo subjects show a single grey segment. The point is that a raw dosing extract has become a tidy, standardized set of exposure episodes, each with a treatment, a dose, a route, and a start and end date on the study clock.

Chaque segment ici est un enregistrement SDTM — un traitement, une dose, une voie, borné par un début et une fin. À la fin de cette leçon, vous les aurez tous produits à partir d’un extrait brut. Nouveau dans le pipeline plus large ? Commencez par le flux de données des essais cliniques, qui situe où se place le SDTM, et les standards CDISC, qui placent le SDTM aux côtés de CDASH et ADaM.

Ce qu’est la classe Interventions du SDTM

Le SDTM — le Study Data Tabulation Model — est le standard CDISC (Clinical Data Interchange Standards Consortium) pour organiser les données collectées d’un essai en domaines fixes. Il est publié sous la forme du standard fondamental SDTM et du SDTM Implementation Guide (SDTMIG). Le SDTM range chaque observation dans l’une des trois classes générales d’observation, et la classe détermine la forme d’un enregistrement :

Classe d’observation Ce qu’elle enregistre Exemples de domaines Variable topic
Interventions Choses administrées au sujet ou pratiquées sur lui EX (exposition), CM (médicaments concomitants), PR (procédures) --TRT
Events Choses qui sont arrivées au sujet AE (événements indésirables), MH (antécédents médicaux), DS (disposition) --TERM
Findings Mesures et évaluations VS (signes vitaux), LB (analyses biologiques), EG (ECG) --TESTCD

La leçon sur les signes vitaux mappait un domaine Findings, où la variable topic est un code de test (VSTESTCD = « ce qui a été mesuré ») ; la leçon sur les événements indésirables mappait un domaine Events, indexé par un terme rapporté (AETERM = « ce qui est arrivé »). Les Interventions sont la troisième forme. L’exposition au médicament à l’étude n’est ni une mesure ni une occurrence — c’est un traitement administré, donc la variable topic est le traitement EXTRT (« ce qui a été administré »), et il y a un enregistrement par épisode de dosage constant : un nouvel enregistrement à chaque changement de dose, de voie ou de forme — et aussi à un intervalle de dosage protocolaire ou à une limite de visite, de sorte qu’un sujet peut avoir deux enregistrements consécutifs à la même dose. C’est toute la distinction — un traitement au lieu d’un code de test ou d’un terme, un épisode au lieu d’une mesure ou d’un événement.

Un enregistrement EX, c’est ce traitement topic accompagné de ses qualificateurs de dose, identifiants et temporalité :

Rôle de la variable Exemple EX Ce qu’elle porte
Identifiants STUDYID, USUBJID, DOMAIN, EXSEQ L’étude, le sujet, le code de domaine (EX), et un numéro de séquence unique par enregistrement.
Topic EXTRT Le nom du traitement administré (le médicament défini par l’étude ou PLACEBO).
Qualificateurs de dose EXDOSE, EXDOSU, EXDOSFRM, EXDOSFRQ, EXROUTE Quantité de dose, unité, forme galénique, fréquence et voie d’administration.
Temporalité EXSTDTC, EXENDTC, EXSTDY, EXENDY Début et fin de l’épisode au format ISO 8601 (--DTC), et le jour d’étude de chacun.

Deux conventions font l’essentiel du mapping. D’abord, la variable topic (EXTRT) nomme l’intervention et tout le reste la qualifie. Ensuite, les descripteurs de dose sont restreints par la Controlled Terminology (CT) — des codelists publiés par CDISC qui fixent les valeurs autorisées (EXROUTE doit valoir TRANSDERMAL, pas « transdermal » ni « patch »). CDISC les maintient sous le nom de SDTM Controlled Terminology. Mapper le brut vers le SDTM consiste, en substance, à remplir les bonnes colonnes de qualificateurs avec les bonnes valeurs valides au regard de la CT — le même travail que pour les Findings et les Events, réalisé pour une troisième forme d’enregistrement.

L’extrait brut de dosage et sa Controlled Terminology

Deux entrées pilotent un mapping : l’extrait brut et la Controlled Terminology de l’étude. sdtm.oak est livré avec des exemples bruts pour les médicaments concomitants et les signes vitaux, mais pas pour l’exposition ; nous construisons donc un petit extrait de dosage brut dans la forme sous laquelle un système EDC (electronic data capture, saisie électronique des données) l’exporte — une ligne large par épisode de dosage, des noms de colonnes choisis par le promoteur, des dates dans le format qu’utilisait le formulaire. Il suit le pilote CDISC public : un médicament à l’étude transdermique titré entre 54 mg et 81 mg face à un bras placebo.

library(sdtm.oak)
library(dplyr, warn.conflicts = FALSE)

# A raw study-drug dosing extract: one row per dosing episode, as collected
ex_raw <- data.frame(
  SUBJ    = c("1015","1015","1015","1023","1028","1028","1033","1039","1039","1044","1044","1044"),
  EXSPID  = c("EX01","EX02","EX03","EX01","EX01","EX02","EX01","EX01","EX02","EX01","EX02","EX03"),
  DRUG    = c("Xanomeline","Xanomeline","Xanomeline","Placebo","Xanomeline","Xanomeline",
              "Placebo","Xanomeline","Xanomeline","Xanomeline","Xanomeline","Xanomeline"),
  DOSE    = c(54, 54, 81, 0, 54, 81, 0, 54, 54, 54, 81, 81),
  DOSEU   = "mg",
  FORM    = "Patch",
  FREQ    = "Once daily",
  ROUTE   = "Transdermal",
  EXSTDAT = c("02 Jan 2014","17 Jan 2014","19 Jun 2014","05 Aug 2012","11 Mar 2013","28 Mar 2013",
              "22 Sep 2013","03 Feb 2014","20 Feb 2014","09 Apr 2013","24 Apr 2013","10 Jun 2013"),
  EXENDAT = c("16 Jan 2014","18 Jun 2014","02 Jul 2014","27 Aug 2012","27 Mar 2013","30 May 2013",
              "18 Oct 2013","19 Feb 2014","30 Jun 2014","23 Apr 2013","09 Jun 2013","25 Jul 2013"),
  stringsAsFactors = FALSE
)

ex_raw |>
  select(SUBJ, DRUG, DOSE, DOSEU, ROUTE, EXSTDAT, EXENDAT) |>
  head()
  SUBJ       DRUG DOSE DOSEU       ROUTE     EXSTDAT     EXENDAT
1 1015 Xanomeline   54    mg Transdermal 02 Jan 2014 16 Jan 2014
2 1015 Xanomeline   54    mg Transdermal 17 Jan 2014 18 Jun 2014
3 1015 Xanomeline   81    mg Transdermal 19 Jun 2014 02 Jul 2014
4 1023    Placebo    0    mg Transdermal 05 Aug 2012 27 Aug 2012
5 1028 Xanomeline   54    mg Transdermal 11 Mar 2013 27 Mar 2013
6 1028 Xanomeline   81    mg Transdermal 28 Mar 2013 30 May 2013

Chaque ligne brute est un épisode de dosage : le traitement (DRUG), la quantité de dose et l’unité (DOSE, DOSEU), la forme galénique, la fréquence et la voie de dose, et la date de début et de fin de l’épisode. Un sujet sous médicament actif a plusieurs lignes consécutives — à mesure que la dose augmente, ou lorsqu’un nouvel intervalle de dosage commence à la même dose. La Controlled Terminology fait correspondre chaque valeur collectée à son terme CDISC standard au sein d’un codelist. Une CT d’étude réelle est livrée dans le cadre de la spécification SDTM ; ici, nous définissons le petit ensemble de codelists de descripteurs de dose dont nous avons besoin :

# Study controlled terminology: collected value -> CDISC standard term, by codelist
ex_ct <- data.frame(
  codelist_code   = c("C71620",  "C66726",  "C71113",     "C66729"),
  term_value      = c("mg",      "PATCH",   "QD",         "TRANSDERMAL"),  # CDISC standard term
  collected_value = c("mg",      "Patch",   "Once daily", "Transdermal"),  # as the CRF recorded it
  term_preferred_term = NA_character_, term_synonyms = NA_character_,
  stringsAsFactors = FALSE
)

ex_ct |> select(codelist_code, collected_value, term_value)
  codelist_code collected_value  term_value
1        C71620              mg          mg
2        C66726           Patch       PATCH
3        C71113      Once daily          QD
4        C66729     Transdermal TRANSDERMAL

collected_value est ce que le CRF a enregistré ; term_value est le terme standard CDISC que sdtm.oak substituera. Les codelists sont des standards CDISC : C71620 est le codelist Unit (EXDOSU), C66726 le codelist Pharmaceutical Dosage Form (EXDOSFRM), C71113 le codelist Frequency (EXDOSFRQ, où « Once daily » → QD), et C66729 le codelist Route of Administration (EXROUTE). L’argument ct_clst de chaque fonction sensible à la CT pointe vers l’une de ces valeurs codelist_code.

Estampiller la traçabilité des enregistrements avec oak_id_vars

Parce que nous mappons un champ brut à la fois puis recousons les morceaux ensemble, sdtm.oak a besoin d’une clé stable sur chaque ligne brute. generate_oak_id_vars() en ajoute trois : oak_id (le numéro de ligne), raw_source (de quel extrait elle provient) et patient_number.

ex_raw <- ex_raw |>
  generate_oak_id_vars(pat_var = "SUBJ", raw_src = "ex_raw")

ex_raw |>
  select(oak_id, raw_source, patient_number, DRUG, DOSE) |>
  head()
  oak_id raw_source patient_number       DRUG DOSE
1      1     ex_raw           1015 Xanomeline   54
2      2     ex_raw           1015 Xanomeline   54
3      3     ex_raw           1015 Xanomeline   81
4      4     ex_raw           1023    Placebo    0
5      5     ex_raw           1028 Xanomeline   54
6      6     ex_raw           1028 Xanomeline   81

Ces trois colonnes constituent les oak_id_vars. Chaque mapping de qualificateur ci-dessous passe id_vars = oak_id_vars(), ce qui indique à sdtm.oak de joindre la nouvelle colonne sur le bon enregistrement par cette clé — le mécanisme qui permet aux mappings partiels de se combiner sans dupliquer de lignes.

Mapper la variable topic et la quantité de dose

Un enregistrement Interventions commence par son topic — le traitement administré. Contrairement à un code de test Findings, EXTRT est un nom de traitement défini par l’étude copié tel que collecté, nous utilisons donc assign_no_ct() (« assign », parce qu’elle copie une valeur collectée ; « no_ct », parce que nous reprenons le nom de médicament propre à l’étude verbatim). La quantité de dose EXDOSE est de même un nombre collecté, copié de la même façon.

ex <- assign_no_ct(raw_dat = ex_raw, raw_var = "DRUG", tgt_var = "EXTRT") |>
  assign_no_ct(raw_dat = ex_raw, raw_var = "DOSE", tgt_var = "EXDOSE",
               id_vars = oak_id_vars())

ex |>
  select(oak_id, patient_number, EXTRT, EXDOSE) |>
  head()
# A tibble: 6 × 4
  oak_id patient_number EXTRT      EXDOSE
   <int> <chr>          <chr>       <dbl>
1      1 1015           Xanomeline     54
2      2 1015           Xanomeline     54
3      3 1015           Xanomeline     81
4      4 1023           Placebo         0
5      5 1028           Xanomeline     54
6      6 1028           Xanomeline     81

Deux colonnes SDTM existent pour l’instant, un enregistrement par épisode brut : le traitement et sa quantité de dose. Les lignes à 0 mg sont le bras placebo — un vrai enregistrement EX, dose comprise, car le SDTM tabule ce qui a été administré, et « placebo, 0 mg » est une administration.

Mapper les qualificateurs de dose de la Controlled Terminology

Maintenant, les colonnes qui décrivent la dose : son unité, sa forme galénique, la fréquence à laquelle elle a été administrée, et par quelle voie. Chacune est une valeur collectée recodée via la Controlled Terminology, chacune utilise donc assign_ct() avec le codelist qui la régit :

  • EXDOSU (unité de dose) — le codelist Unit C71620 : mg reste mg.
  • EXDOSFRM (forme galénique) — le codelist Pharmaceutical Dosage Form C66726 : PatchPATCH.
  • EXDOSFRQ (fréquence) — le codelist Frequency C71113 : Once dailyQD.
  • EXROUTE (voie) — le codelist Route of Administration C66729 : TransdermalTRANSDERMAL.
ex <- ex |>
  assign_ct(raw_dat = ex_raw, raw_var = "DOSEU", tgt_var = "EXDOSU",
            ct_spec = ex_ct, ct_clst = "C71620", id_vars = oak_id_vars()) |>
  assign_ct(raw_dat = ex_raw, raw_var = "FORM", tgt_var = "EXDOSFRM",
            ct_spec = ex_ct, ct_clst = "C66726", id_vars = oak_id_vars()) |>
  assign_ct(raw_dat = ex_raw, raw_var = "FREQ", tgt_var = "EXDOSFRQ",
            ct_spec = ex_ct, ct_clst = "C71113", id_vars = oak_id_vars()) |>
  assign_ct(raw_dat = ex_raw, raw_var = "ROUTE", tgt_var = "EXROUTE",
            ct_spec = ex_ct, ct_clst = "C66729", id_vars = oak_id_vars())

ex |>
  select(patient_number, EXTRT, EXDOSE, EXDOSU, EXDOSFRM, EXDOSFRQ, EXROUTE) |>
  head()
# A tibble: 6 × 7
  patient_number EXTRT      EXDOSE EXDOSU EXDOSFRM EXDOSFRQ EXROUTE    
  <chr>          <chr>       <dbl> <chr>  <chr>    <chr>    <chr>      
1 1015           Xanomeline     54 mg     PATCH    QD       TRANSDERMAL
2 1015           Xanomeline     54 mg     PATCH    QD       TRANSDERMAL
3 1015           Xanomeline     81 mg     PATCH    QD       TRANSDERMAL
4 1023           Placebo         0 mg     PATCH    QD       TRANSDERMAL
5 1028           Xanomeline     54 mg     PATCH    QD       TRANSDERMAL
6 1028           Xanomeline     81 mg     PATCH    QD       TRANSDERMAL

Chaque valeur collectée est désormais un terme standard CDISC : la forme est PATCH, la fréquence QD, la voie TRANSDERMAL. C’est tout l’intérêt de la Controlled Terminology — un évaluateur, ou un outil de validation de la FDA, lit les mêmes valeurs codées d’une étude à l’autre, quelle que soit la façon dont chaque site les a formulées sur le CRF.

Note

Lorsqu’un descripteur est le même pour chaque enregistrement, hardcode_ct() est l’outil plus adapté. Ici, chaque épisode est un patch transdermique en une prise par jour, de sorte que EXDOSFRM/EXDOSFRQ/EXROUTE pourraient chacun être hardcodés à leur valeur CT fixe avec hardcode_ct() (comme le fait la leçon sur les signes vitaux pour VSORRESU = "mmHg") au lieu d’être recodés depuis une colonne brute. Nous utilisons assign_ct() parce qu’une étude réelle les collecte enregistrement par enregistrement et peut porter plus d’une forme ou d’une voie — recoder la valeur collectée est le schéma général.

Mapper les variables de temporalité

Un épisode de dosage a un début et une fin, chacun étant une date au format ISO 8601 (variables --DTC). L’ISO 8601 est le standard de date international (2014-01-02) qui rend les dates triables et comparables d’une étude à l’autre. Les dates brutes se trouvent dans deux champs, dans un format non standard ; assign_datetime() les analyse et écrit la colonne conforme.

ex <- ex |>
  assign_datetime(raw_dat = ex_raw, raw_var = "EXSTDAT", tgt_var = "EXSTDTC",
                  raw_fmt = list(c("d-m-y", "dd mmm yyyy")), id_vars = oak_id_vars()) |>
  assign_datetime(raw_dat = ex_raw, raw_var = "EXENDAT", tgt_var = "EXENDTC",
                  raw_fmt = list(c("d-m-y", "dd mmm yyyy")), id_vars = oak_id_vars())

ex |>
  select(patient_number, EXTRT, EXDOSE, EXSTDTC, EXENDTC) |>
  head()
# A tibble: 6 × 5
  patient_number EXTRT      EXDOSE EXSTDTC    EXENDTC   
  <chr>          <chr>       <dbl> <iso8601>  <iso8601> 
1 1015           Xanomeline     54 2014-01-02 2014-01-16
2 1015           Xanomeline     54 2014-01-17 2014-06-18
3 1015           Xanomeline     81 2014-06-19 2014-07-02
4 1023           Placebo         0 2012-08-05 2012-08-27
5 1028           Xanomeline     54 2013-03-11 2013-03-27
6 1028           Xanomeline     81 2013-03-28 2013-05-30

raw_fmt indique à sdtm.oak comment la date brute a été écrite (02 Jan 2014) ; il renvoie la forme standard 2014-01-02. Les dates d’exposition sont généralement collectées au jour près, ce sont donc des valeurs --DTC en date seule — le même assign_datetime() gère aussi un champ d’heure apparié et renvoie sans risque une date partielle lorsqu’un jour brut est inconnu, plutôt que d’en inventer un. La vignette sur la gestion des dates documente l’ensemble complet des formats pris en charge et des règles relatives aux dates partielles.

Ajouter les identifiants, la séquence et les jours d’étude

Un enregistrement conforme a besoin de ses identifiants, d’un numéro de séquence et de sa place sur le calendrier de l’étude. STUDYID, DOMAIN et USUBJID sont de simples affectations ; derive_seq() affecte EXSEQ — un numéro de séquence unique par enregistrement au sein d’un sujet ; et derive_study_day() calcule EXSTDY/EXENDY, le jour d’étude de chaque date par rapport à la date de début de référence du sujet RFSTDTC (portée par le domaine de démographie DM). Le jour d’étude 1 est la date de référence elle-même — il n’y a pas de jour 0.

# The reference start date per subject lives on DM; here is the minimal slice derive_study_day needs
dm <- data.frame(
  USUBJID = paste0("CDISCPILOT01-", c("1015","1023","1028","1033","1039","1044")),
  RFSTDTC = c("2014-01-02","2012-08-05","2013-03-11","2013-09-22","2014-02-03","2013-04-09"),
  stringsAsFactors = FALSE
)

ex <- ex |>
  mutate(
    STUDYID = "CDISCPILOT01",
    DOMAIN = "EX",
    USUBJID = paste0(STUDYID, "-", patient_number)
  ) |>
  derive_seq(tgt_var = "EXSEQ", rec_vars = c("USUBJID", "EXTRT", "EXSTDTC")) |>
  derive_study_day(dm_domain = dm, tgdt = "EXSTDTC", refdt = "RFSTDTC", study_day_var = "EXSTDY") |>
  derive_study_day(dm_domain = dm, tgdt = "EXENDTC", refdt = "RFSTDTC", study_day_var = "EXENDY") |>
  select(STUDYID, DOMAIN, USUBJID, EXSEQ, EXTRT, EXDOSE, EXDOSU, EXDOSFRM, EXDOSFRQ,
         EXROUTE, EXSTDTC, EXENDTC, EXSTDY, EXENDY)

head(ex)
# A tibble: 6 × 14
  STUDYID     DOMAIN USUBJID EXSEQ EXTRT EXDOSE EXDOSU EXDOSFRM EXDOSFRQ EXROUTE
  <chr>       <chr>  <chr>   <int> <chr>  <dbl> <chr>  <chr>    <chr>    <chr>  
1 CDISCPILOT… EX     CDISCP…     1 Xano…     54 mg     PATCH    QD       TRANSD…
2 CDISCPILOT… EX     CDISCP…     2 Xano…     54 mg     PATCH    QD       TRANSD…
3 CDISCPILOT… EX     CDISCP…     3 Xano…     81 mg     PATCH    QD       TRANSD…
4 CDISCPILOT… EX     CDISCP…     1 Plac…      0 mg     PATCH    QD       TRANSD…
5 CDISCPILOT… EX     CDISCP…     1 Xano…     54 mg     PATCH    QD       TRANSD…
6 CDISCPILOT… EX     CDISCP…     2 Xano…     81 mg     PATCH    QD       TRANSD…
# ℹ 4 more variables: EXSTDTC <date>, EXENDTC <date>, EXSTDY <int>,
#   EXENDY <int>

Voilà un domaine EX conforme : d’abord les colonnes d’identifiants SDTM, puis le topic (EXTRT), les qualificateurs de dose, la temporalité et les jours d’étude. derive_seq() ordonne les enregistrements par rec_vars et les numérote 1, 2, 3… au sein de chaque sujet, de sorte que EXSEQ soit unique par USUBJID ; derive_study_day() situe chaque épisode sur le calendrier de l’étude (le premier patch du sujet -1015 commence au EXSTDY 1 et l’augmentation de dose survient des mois plus tard), ce qui est ce que la couche d’analyse utilise pour calculer la durée d’exposition. Un rapide contrôle structurel confirme le contrat SDTM :

required <- c("STUDYID", "DOMAIN", "USUBJID", "EXSEQ", "EXTRT", "EXDOSE")
all(required %in% names(ex))                  # required identifiers + topic present?
[1] TRUE
length(unique(ex$DOMAIN)) == 1                # one domain code?
[1] TRUE
!any(duplicated(ex[c("USUBJID", "EXSEQ")]))   # EXSEQ unique within subject?
[1] TRUE

Trois TRUE : le domaine est structurellement sain. Cela correspond aussi à la réalité — les colonnes que nous avons construites (EXTRT, EXDOSE, EXDOSU, EXDOSFRM, EXDOSFRQ, EXROUTE, EXSTDTC, EXENDTC, EXSTDY, EXENDY) sont exactement les variables d’exposition que porte le jeu de données de référence ex publié de pharmaversesdtm. En production, le contrôle complet est un outil de conformité (Pinnacle 21, ou le package pharmaverse sdtmchecks, présenté dans la leçon sur les signes vitaux) qui exécute les mêmes règles d’intégrité qu’un régulateur. Avec un domaine EX conforme en main, la couche d’analyse lit les dates de début et de fin de traitement directement à partir de lui pour construire le jeu de données ADSL de niveau sujet.

🟢 Avec un agent IA

Demandez à Prova « comment regrouper des épisodes de dosage EX consécutifs en une exposition totale de niveau sujet et dériver les dates de début et de fin de traitement (TRTSDTM/TRTEDTM) pour ADSL ? » — elle répond en s’appuyant sur les leçons de ce pilier, avec du code exécutable que vous pouvez essayer sur les données d’exemple. The runtime is the judge. Demandez à Prova →

Problèmes fréquents

Vous mettez l’exposition au médicament dans un domaine Findings — en cherchant un --TESTCD et un résultat. C’est le piège de la classe : l’exposition n’est pas une mesure, elle n’a donc ni code de test ni valeur de résultat. C’est une Intervention — un traitement administré — sa variable topic est donc EXTRT (le médicament), mappée avec assign_no_ct(), qualifiée par la dose et la voie, non par un couple test-et-résultat. Si vous cherchez un EXTESTCD, vous avez la mauvaise classe d’observation en tête ; mappez le traitement, pas un test.

assign_ct() avertit qu’une valeur « could not be mapped », et la colonne SDTM conserve le texte brut. La valeur collectée n’est pas dans le codelist que vous avez indiqué — un vrai constat, pas un bug. Une cause fréquente est une différence de casse ou d’orthographe : sdtm.oak fait une correspondance exacte de collected_value, de sorte qu’un "transdermal" brut ne correspondra pas à une entrée de codelist enregistrée comme "Transdermal". Vérifiez le codelist avec subset(ex_ct, codelist_code == "<code>") et confirmez que sa colonne collected_value contient la valeur brute exactement telle qu’écrite ; sdtm.oak laisse passer la valeur non mappée inchangée, pour que vous corrigiez la terminologie, pas les données.

EXSEQ n’est pas unique, ou derive_seq() met deux lignes à égalité. Les rec_vars que vous avez donnés n’ordonnent pas de façon unique les enregistrements au sein d’un sujet. Pour l’EX, un sujet a plusieurs épisodes consécutifs, ordonnez donc par le traitement plus la date de début (c("USUBJID", "EXTRT", "EXSTDTC")) ; si deux épisodes pouvaient partager une date de début, ajoutez un autre champ distinctif pour que chaque enregistrement au sein d’un sujet se trie à une position distincte.

Questions fréquentes

Le domaine SDTM EX (exposure, exposition) est le jeu de données CDISC SDTM qui enregistre l’exposition d’un sujet au traitement à l’étude — un enregistrement standardisé par épisode de dosage continu, dans la classe d’observation Interventions. Chaque enregistrement porte le traitement EXTRT, les qualificateurs de dose (EXDOSE, EXDOSU, EXDOSFRM, EXDOSFRQ, EXROUTE), des dates de début/fin ISO 8601 (EXSTDTC, EXENDTC) avec leurs jours d’étude (EXSTDY, EXENDY), et des identifiants (USUBJID, EXSEQ). C’est un domaine obligatoire dans une soumission réglementaire et la source des dates de traitement et des variables d’exposition dans ADSL et les jeux de données d’analyse de l’exposition.

Ce sont les trois classes générales d’observation du SDTM, distinguées par ce que représente un enregistrement. Interventions enregistre quelque chose d’administré au sujet ou pratiqué sur lui (le médicament à l’étude dans EX, les médicaments concomitants dans CM) — variable topic --TRT. Events enregistre quelque chose qui est arrivé (un événement indésirable dans AE, un antécédent médical dans MH) — variable topic --TERM. Findings enregistre une mesure ou une évaluation (un signe vital dans VS, une analyse biologique dans LB) — variable topic --TESTCD, avec un résultat. Les mêmes algorithmes sdtm.oak, trois formes d’enregistrement : pour l’EX, vous mappez un traitement avec des qualificateurs de dose, non un couple test-et-résultat ni un terme rapporté.

La quantité de dose EXDOSE est un nombre collecté, copié tel quel avec assign_no_ct(). Les descripteurs de dose relèvent de la Controlled Terminology, chacun est donc recodé avec assign_ct() pointé vers son codelist : l’unité EXDOSU (codelist Unit C71620), la forme galénique EXDOSFRM (C66726), la fréquence EXDOSFRQ (C71113, par exemple « Once daily » → QD), et la voie EXROUTE (codelist Route of Administration C66729, par exemple « Transdermal » → TRANSDERMAL). Lorsqu’un descripteur est le même pour chaque enregistrement, vous pouvez hardcode_ct() la valeur fixe à la place. Voir SDTM Controlled Terminology pour les codelists publiés.

Les deux sont des domaines Interventions, mais EX enregistre le traitement à l’étude étudié — le médicament spécifié par le protocole avec lequel le sujet est dosé — tandis que CM (médicaments concomitants) enregistre les autres médicaments que le sujet prend en parallèle (thérapie de fond, médicaments de secours). La forme d’enregistrement est la même (une variable topic de traitement plus des qualificateurs de dose et la temporalité), de sorte que le schéma de mapping sdtm.oak de cette leçon se transpose directement à CM : mappez CMTRT avec assign_no_ct(), les qualificateurs de dose avec assign_ct(), et les dates avec assign_datetime().

Utilisez assign_no_ct() pour les valeurs copiées telles quelles (le traitement EXTRT et la quantité de dose EXDOSE) ; assign_ct() pour les valeurs collectées recodées via un codelist (EXDOSU, EXDOSFRM, EXDOSFRQ, EXROUTE) — ou hardcode_ct() lorsque cette valeur est fixe pour chaque enregistrement ; assign_datetime() pour les dates ISO 8601 (EXSTDTC, EXENDTC) ; derive_seq() pour EXSEQ ; et derive_study_day() pour les jours d’étude EXSTDY/EXENDY. generate_oak_id_vars() estampille d’abord la clé de traçabilité sur laquelle chaque mapping se rejoint. La vignette sur les algorithmes en dresse la liste complète.

Testez vos connaissances

Supposons que l’extrait brut ait gagné un bras de secours dosé sous forme de comprimé oral : un champ FORM collecté comme Tablet et ROUTE collecté comme Oral. Esquissez comment vous étendriez le mapping pour que EXDOSFRM et EXROUTE ressortent en termes standard CDISC — qu’est-ce qui change dans la Controlled Terminology, et quelle fonction sdtm.oak reste la même ?

EXDOSFRM et EXROUTE sont déjà mappés avec assign_ct() — la fonction ne change pas. Ce qui doit changer, c’est la CT de l’étude : les codelists doivent contenir une ligne collected_valueterm_value pour chaque nouvelle valeur collectée, dans le bon codelist_code.

Ajoutez les nouveaux termes à ex_ct — le codelist Pharmaceutical Dosage Form C66726 et le codelist Route of Administration C66729 régissent déjà ces variables, vous étendez donc ces codelists, non le code :

# add rows to ex_ct: collected -> CDISC standard term
#   codelist_code  collected_value  term_value
#   C66726         "Tablet"         "TABLET"
#   C66729         "Oral"           "ORAL"

Les appels assign_ct() pour EXDOSFRM et EXROUTE sont inchangés — ils recodent désormais TabletTABLET et OralORAL parce que la CT contient les entrées. C’est exactement pourquoi les algorithmes de sdtm.oak sont réutilisables : le code de mapping est fixe, et la CT de l’étude porte chaque valeur autorisée.

A. Parce que l’EX est un domaine Findings et que EXTRT est son code de test B. Parce que l’EX est un domaine Interventions — il enregistre un traitement administré, indexé par le nom du traitement C. Parce que sdtm.oak exige que chaque domaine utilise une variable topic --TRT

B. L’EX appartient à la classe d’observation Interventions, qui enregistre des choses administrées au sujet. Sa variable topic est donc le traitement EXTRT (« ce qui a été administré »), avec un enregistrement par épisode de dosage — contrairement à la classe Findings (signes vitaux, analyses biologiques), dont le topic est un code de test --TESTCD (« ce qui a été mesuré »). A se trompe de classe (l’EX est Interventions, pas Findings), et C est faux — la variable topic dépend de la classe d’observation, pas d’une règle du package.

Conclusion

Mapper le domaine EX est la même boucle champ par champ que pour n’importe quel domaine SDTM, appliquée à la classe Interventions : remplir la bonne colonne SDTM à partir du bon champ brut avec le bon algorithme. La variable topic EXTRT nomme le traitement (copiée verbatim avec assign_no_ct(), aux côtés de la quantité de dose EXDOSE) ; assign_ct() recode l’unité, la forme, la fréquence et la voie via la Controlled Terminology ; assign_datetime() construit le début et la fin ISO 8601 ; derive_seq() numérote les épisodes ; et derive_study_day() les situe sur le calendrier de l’étude. Maîtrisez la boucle Interventions ici et le domaine des médicaments concomitants (CM) est la même boucle avec des champs différents. Avec un SDTM EX conforme en main, l’étape suivante est la couche d’analyse, où les dates de début et de fin de traitement qu’il porte ancrent le jeu de données ADSL de niveau sujet construit avec admiral.

Note

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

Cette page vous a-t-elle été utile ?

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Domaine SDTM EX en R avec sdtm.oak : exposition},
  date = {2026-07-01},
  url = {https://www.datanovia.com/learn/pharma-clinical/02-sdtm-programming/sdtm-ex-exposure-domain},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Domaine SDTM EX en R avec sdtm.oak : exposition.” 2026. July 1. https://www.datanovia.com/learn/pharma-clinical/02-sdtm-programming/sdtm-ex-exposure-domain.