Create ADAE in R with admiral: the Adverse-Events Analysis Dataset

Derive a CDISC-conformant ADAE — the OCCDS occurrence structure, the treatment-emergent flag TRTEMFL, and occurrence flags — from SDTM with admiral, then summarize adverse events by treatment arm and system organ class

Pharma & Clinical

A complete, runnable tutorial for ADAE, the adverse-events analysis dataset. Learn the ADaM OCCDS occurrence structure (one row per adverse-event record, not one per subject), derive a conformant ADAE in R from a pre-built ADSL and the SDTM AE domain with admiral: merge treatment variables with derive_vars_merged(), impute analysis dates with derive_vars_dt(), build the treatment-emergent flag TRTEMFL with derive_var_trtemfl(), add on-treatment and first-occurrence flags, and produce a basic adverse-event summary by treatment arm and system organ class — on public pharmaverse data, so every line runs.

Published

June 30, 2026

Modified

July 7, 2026

TipKey takeaways
  • ADAE is the dataset behind every adverse-event table. It holds one row per adverse-event record — the OCCDS occurrence structure — so a subject who reports three events has three rows, unlike ADSL’s one-row-per-subject backbone.
  • You build it from SDTM AE plus ADSL. The raw AE domain supplies the events; ADSL supplies treatment dates and analysis variables, merged onto every AE record with derive_vars_merged().
  • TRTEMFL is the variable that matters most. The treatment-emergent flag marks the AEs that started on or after first dose — the ones safety tables actually count. derive_var_trtemfl() derives it from the analysis date and the treatment window.
  • Occurrence flags pick one row to count. derive_var_extreme_flag() flags the first treatment-emergent event per subject (AOCCFL) and per system organ class (AOCCSFL), so a “subjects with ≥1 AE” table counts each subject once.
  • The system organ class and preferred term are already coded. ADAE reads AEBODSYS (SOC) and AEDECOD (preferred term) straight from the SDTM AE domain — no MedDRA dictionary lookup is needed to summarize events by body system.

Introduction

Every safety read-out in a clinical study report — which adverse events occurred, in whom, how often, and on which arm — is computed from one analysis dataset: ADAE, the adverse-events ADaM (Analysis Data Model) dataset. Before a single AE summary table or treatment-emergent listing can be produced, someone has to turn the raw, messy AE domain into an analysis-ready ADAE: real analysis dates, a treatment-emergent flag, occurrence flags, and the treatment variables every table splits by.

ADAE is the first dataset where the occurrence structure shows up: unlike ADSL, which carries exactly one row per subject, ADAE carries one row per adverse-event record. That single structural difference drives everything — how you flag treatment emergence, how you count “subjects with an event” without double-counting, and how you summarize by body system. This lesson builds a conformant ADAE in R with admiral, the pharmaverse package for ADaM derivation, working on public pharmaverse example data so every line runs as written. The build follows admiral’s official OCCDS / ADAE vignette, re-authored into a single guided walkthrough.

Here is where we are headed — treatment-emergent adverse events by system organ class and arm, computed straight from the ADAE we derive:

Grouped horizontal bar chart of the eight most frequent system organ classes for treatment-emergent adverse events, built from the derived ADAE dataset. For each system organ class, three bars give the number of subjects with at least one such event on Placebo (azure), Xanomeline High Dose (orange), and Xanomeline Low Dose (green). General disorders and administration-site conditions and skin and subcutaneous tissue disorders dominate, and the two active Xanomeline arms have far more subjects affected in those classes than placebo, the expected pattern for a transdermal patch.

That figure reads off three ADAE columns — AEBODSYS, TRT01A, and TRTEMFL — plus one row per event. By the end of this lesson you will have derived the flags it depends on. If “ADaM”, “OCCDS”, or “SDTM” are new, start with the CDISC standards, which maps where ADAE sits; this lesson assumes you have a built ADSL, the subject-level backbone the ADSL lesson produces.

What ADAE is

ADAE is built on the OCCDS structure — the ADaM Structure for Occurrence Data defined by CDISC for events that occur rather than being measured: adverse events (ADAE), concomitant medications (ADCM), medical history (ADMH). Its defining rule is the one that catches people moving over from ADSL:

  • ADSL is one row per subject.
  • OCCDS / ADAE is one row per record — one row per adverse event. A subject with five adverse events has five rows.
  • BDS (the structure of ADTTE, ADLB, ADVS) is one row per subject per parameter per analysis timepoint, keyed by PARAMCD.

That structural choice is why ADAE needs flags rather than a single value per subject: with many rows per subject, you flag the rows that count (treatment-emergent, on-treatment) and the row to count once (first occurrence), instead of collapsing to one number.

The columns fall into a few groups. These are the load-bearing ones this lesson derives or carries:

Group Variables What they hold
Subject & treatment (from ADSL) STUDYID, USUBJID, TRT01A, TRTA, TRTSDT, TRTEDT Subject keys plus the treatment variables and dates merged from ADSL.
The event (from SDTM AE) AETERM, AEDECOD, AEBODSYS, AESEV, AESER, AESEQ Reported term, the coded preferred term (AEDECOD) and system organ class (AEBODSYS), severity, seriousness.
Analysis dates ASTDT, AENDT, ASTDY, AENDY, ADURN, ADURU The AE start/end as real analysis dates, the study day relative to first dose, and the event duration.
Timing flags TRTEMFL, ONTRTFL "Y"/NA flags marking treatment-emergent and on-treatment events.
Occurrence flags AOCCFL, AOCCSFL "Y"/NA flags marking the first treatment-emergent event per subject and per system organ class.
Analysis values ASEV, AREL Analysis copies of severity and relationship, kept distinct from the SDTM source so SDTM stays untouched.

Two conventions are worth fixing up front:

  • AEDECOD and AEBODSYS arrive already coded. In the SDTM AE domain the preferred term (AEDECOD) and system organ class (AEBODSYS) are populated by the study’s MedDRA (Medical Dictionary for Regulatory Activities) coding step before ADaM. ADAE reads them as ordinary columns — so you can summarize by body system without a dictionary on hand, and this lesson ships no licensed MedDRA terminology.
  • A flag is "Y" or missing, not "Y"/"N". ADaM occurrence and timing flags are populated "Y" for the records that qualify and left NA otherwise (the OCCDS convention), so downstream code filters with TRTEMFL == "Y" and a count of "Y" is the count that matters.

The trial we use is the CDISC pilot study shipped in pharmaversesdtm and pharmaverseadam — a synthetic, license-free parallel-arm study comparing placebo against two doses of Xanomeline, delivered as a transdermal patch.

The source data

admiral builds ADAE from two inputs: the raw AE domain (the events) and a pre-built ADSL (the subject-level treatment and date backbone). We take ADSL ready-made from pharmaverseadam so this lesson stays focused on the AE side; the ADSL lesson shows how that backbone is built.

library(admiral)
library(dplyr, warn.conflicts = FALSE)
library(pharmaversesdtm)
library(pharmaverseadam)
library(lubridate)
library(stringr)

# ADSL — one row per subject, the treatment + date backbone
adsl <- pharmaverseadam::adsl

# AE — the raw adverse-event domain, one row per reported event.
# convert_blanks_to_na() turns SDTM's empty strings "" into proper NA.
ae <- pharmaversesdtm::ae %>% convert_blanks_to_na()

ae %>%
  select(USUBJID, AETERM, AEDECOD, AEBODSYS, AESEV, AESTDTC) %>%
  head(5)
# A tibble: 5 × 6
  USUBJID     AETERM                              AEDECOD AEBODSYS AESEV AESTDTC
  <chr>       <chr>                               <chr>   <chr>    <chr> <chr>  
1 01-701-1015 APPLICATION SITE ERYTHEMA           APPLIC… GENERAL… MILD  2014-0…
2 01-701-1015 APPLICATION SITE PRURITUS           APPLIC… GENERAL… MILD  2014-0…
3 01-701-1015 DIARRHOEA                           DIARRH… GASTROI… MILD  2014-0…
4 01-701-1023 ATRIOVENTRICULAR BLOCK SECOND DEGR… ATRIOV… CARDIAC… MILD  2012-0…
5 01-701-1023 ERYTHEMA                            ERYTHE… SKIN AN… MILD  2012-0…

Each AE row is one reported event: a verbatim AETERM, its coded AEDECOD/AEBODSYS, a severity, and a character start date AESTDTC (an ISO string that may be partial). convert_blanks_to_na() is the essential first step — SDTM uses empty strings for missing values, and admiral’s date and merge functions expect a real NA.

Merge the ADSL treatment variables onto each AE

ADAE needs each subject’s treatment dates and treatment arm on every one of their AE rows, because treatment emergence is defined relative to first dose. derive_vars_merged() copies the chosen ADSL variables onto each matching AE record by subject.

adsl_vars <- exprs(TRTSDT, TRTEDT, TRT01A, TRT01P, DTHDT, EOSDT, AGE, SEX, RACE)

adae <- ae %>%
  derive_vars_merged(
    dataset_add = adsl,
    new_vars = adsl_vars,
    by_vars = exprs(STUDYID, USUBJID)
  )

adae %>%
  select(USUBJID, AEDECOD, TRT01A, TRTSDT, TRTEDT) %>%
  head(5)
# A tibble: 5 × 5
  USUBJID     AEDECOD                              TRT01A  TRTSDT     TRTEDT    
  <chr>       <chr>                                <chr>   <date>     <date>    
1 01-701-1015 APPLICATION SITE ERYTHEMA            Placebo 2014-01-02 2014-07-02
2 01-701-1015 APPLICATION SITE PRURITUS            Placebo 2014-01-02 2014-07-02
3 01-701-1015 DIARRHOEA                            Placebo 2014-01-02 2014-07-02
4 01-701-1023 ATRIOVENTRICULAR BLOCK SECOND DEGREE Placebo 2012-08-05 2012-09-01
5 01-701-1023 ERYTHEMA                             Placebo 2012-08-05 2012-09-01

Because ADSL has one row per subject and AE has many, this is a one-to-many merge: the single ADSL record fans out onto all of a subject’s AE rows. TRTSDT (first dose) and TRTEDT (last dose) are the two dates that define the treatment window we need next.

Derive the analysis dates

The AE start and end arrive as character strings (AESTDTC, AEENDTC) that may be partial — a value like 2014-01 has no day. derive_vars_dt() imputes the missing parts and converts each to a real R date. derive_vars_dy() then computes the study day relative to first dose, and derive_vars_duration() the event’s length.

adae <- adae %>%
  # AESTDTC -> ASTDT, imputing a missing day/month to the first; never before first dose
  derive_vars_dt(
    new_vars_prefix = "AST", dtc = AESTDTC,
    highest_imputation = "M", min_dates = exprs(TRTSDT)
  ) %>%
  # AEENDTC -> AENDT, imputing a missing day/month to the last; never after death / end of study
  derive_vars_dt(
    new_vars_prefix = "AEN", dtc = AEENDTC,
    highest_imputation = "M", date_imputation = "last", max_dates = exprs(DTHDT, EOSDT)
  ) %>%
  # ASTDY / AENDY: AE start/end as a study day relative to first dose (TRTSDT = day 1)
  derive_vars_dy(reference_date = TRTSDT, source_vars = exprs(ASTDT, AENDT)) %>%
  # ADURN / ADURU: how many days the event lasted, with its unit
  derive_vars_duration(new_var = ADURN, new_var_unit = ADURU, start_date = ASTDT, end_date = AENDT)

adae %>%
  select(USUBJID, AESTDTC, ASTDT, ASTDY, AENDT, ADURN, ADURU) %>%
  head(5)
# A tibble: 5 × 7
  USUBJID     AESTDTC    ASTDT      ASTDY AENDT      ADURN ADURU
  <chr>       <chr>      <date>     <dbl> <date>     <dbl> <chr>
1 01-701-1015 2014-01-03 2014-01-03     2 NA            NA <NA> 
2 01-701-1015 2014-01-03 2014-01-03     2 NA            NA <NA> 
3 01-701-1015 2014-01-09 2014-01-09     8 2014-01-11     3 DAYS 
4 01-701-1023 2012-08-26 2012-08-26    22 NA            NA <NA> 
5 01-701-1023 2012-08-07 2012-08-07     3 2012-08-30    24 DAYS 

Two imputation choices encode clinical rules. A start date imputes to the first of the period and is bounded below by TRTSDT (min_dates), so an AE recorded as 2014-01 for a subject dosed on 2014-01-15 is read as 2014-01-15, never before first dose. An end date imputes to the last of the period and is bounded above by death or end of study (max_dates), so it never runs past the point the subject left the study. ASTDY is the AE’s study day — day 1 is first dose — and ADURN is its duration in days. None of this is date arithmetic by hand.

Derive the treatment-emergent flag (TRTEMFL)

This is the variable ADAE exists for. A treatment-emergent adverse event (TEAE) is one that started on or after first dose (and, by convention, up to a window after last dose) — the events plausibly attributable to study drug, and the ones safety tables count. derive_var_trtemfl() compares each AE’s analysis dates against the treatment window and sets TRTEMFL to "Y" for the emergent ones.

adae <- adae %>%
  derive_var_trtemfl(
    start_date = ASTDT,
    end_date = AENDT,
    trt_start_date = TRTSDT,
    trt_end_date = TRTEDT,
    end_window = 30
  )

adae %>%
  select(USUBJID, ASTDT, TRTSDT, TRTEDT, TRTEMFL) %>%
  head(5)
# A tibble: 5 × 5
  USUBJID     ASTDT      TRTSDT     TRTEDT     TRTEMFL
  <chr>       <date>     <date>     <date>     <chr>  
1 01-701-1015 2014-01-03 2014-01-02 2014-07-02 Y      
2 01-701-1015 2014-01-03 2014-01-02 2014-07-02 Y      
3 01-701-1015 2014-01-09 2014-01-02 2014-07-02 Y      
4 01-701-1023 2012-08-26 2012-08-05 2012-09-01 Y      
5 01-701-1023 2012-08-07 2012-08-05 2012-09-01 Y      
adae %>% count(TRTEMFL)
# A tibble: 2 × 2
  TRTEMFL     n
  <chr>   <int>
1 Y        1122
2 <NA>       69

end_window = 30 extends the treatment-emergent period to 30 days after last dose — a common choice so a late-onset event still counts as drug-related; your statistical analysis plan sets the exact window. Of the 1191 AE records, 1122 are treatment-emergent and 69 are not (they started before first dose — pre-treatment events that belong in a medical-history listing, not a TEAE table). From here on, TRTEMFL == "Y" is the filter for every safety summary.

Add the on-treatment and occurrence flags

Two more flags finish the analysis-ready ADAE. The on-treatment flag (ONTRTFL) marks events that fall strictly inside the treatment window — a stricter cut than treatment-emergent, used for on-treatment analyses. The occurrence flags solve the counting problem the OCCDS structure creates: with many rows per subject, which row do you count for a “subjects with ≥1 AE” table? derive_var_extreme_flag() flags the first qualifying record, and restrict_derivation() limits the flag to the treatment-emergent rows.

adae <- adae %>%
  # ONTRTFL: events within the treatment window (first dose to last dose + 30 days)
  derive_var_ontrtfl(
    start_date = ASTDT,
    ref_start_date = TRTSDT,
    ref_end_date = TRTEDT,
    ref_end_window = 30
  ) %>%
  # AOCCFL: first treatment-emergent AE per subject (count each subject once overall)
  restrict_derivation(
    derivation = derive_var_extreme_flag,
    args = params(
      by_vars = exprs(USUBJID),
      order = exprs(ASTDT, AESEQ),
      new_var = AOCCFL,
      mode = "first"
    ),
    filter = TRTEMFL == "Y"
  ) %>%
  # AOCCSFL: first treatment-emergent AE per subject within each system organ class
  restrict_derivation(
    derivation = derive_var_extreme_flag,
    args = params(
      by_vars = exprs(USUBJID, AEBODSYS),
      order = exprs(ASTDT, AESEQ),
      new_var = AOCCSFL,
      mode = "first"
    ),
    filter = TRTEMFL == "Y"
  )

adae %>% count(AOCCFL)
# A tibble: 2 × 2
  AOCCFL     n
  <chr>  <int>
1 Y        217
2 <NA>     974
adae %>% count(AOCCSFL)
# A tibble: 2 × 2
  AOCCSFL     n
  <chr>   <int>
1 Y         549
2 <NA>      642

AOCCFL == "Y" on 217 rows means 217 subjects had at least one treatment-emergent AE — flag the first event per subject, count the flag, and each subject is counted exactly once. AOCCSFL does the same within each AEBODSYS, so a “subjects affected, by system organ class” table reads off AOCCSFL == "Y" without double-counting a subject who had three events in the same class. The restrict_derivation() wrapper is what keeps the flags on treatment-emergent rows only — flagging a pre-treatment event as a subject’s “first occurrence” would be wrong.

Summarize the adverse events

With the flags in place, the standard safety summaries are short filters and counts. Start with the overall extent of exposure to AEs — how many subjects on each arm had at least one treatment-emergent event — using the per-subject occurrence flag.

teae <- adae %>% filter(TRTEMFL == "Y", TRT01A != "Screen Failure")

# subjects with >=1 TEAE per arm (AOCCFL counts each subject once)
teae %>%
  filter(AOCCFL == "Y") %>%
  count(TRT01A, name = "subjects_with_teae")
# A tibble: 3 × 2
  TRT01A               subjects_with_teae
  <chr>                             <int>
1 Placebo                              65
2 Xanomeline High Dose                 68
3 Xanomeline Low Dose                  84

Sixty-five placebo subjects had a treatment-emergent AE, against 68 and 84 on the two Xanomeline arms — the active arms affect more subjects, as expected for an active drug. Next, the most frequent system organ classes, counting subjects once per class with AOCCSFL:

teae %>%
  filter(AOCCSFL == "Y") %>%
  count(AEBODSYS, sort = TRUE, name = "n_subjects") %>%
  head(8)
# A tibble: 8 × 2
  AEBODSYS                                             n_subjects
  <chr>                                                     <int>
1 GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS        108
2 SKIN AND SUBCUTANEOUS TISSUE DISORDERS                       98
3 NERVOUS SYSTEM DISORDERS                                     53
4 GASTROINTESTINAL DISORDERS                                   51
5 CARDIAC DISORDERS                                            40
6 INFECTIONS AND INFESTATIONS                                  38
7 PSYCHIATRIC DISORDERS                                        28
8 RESPIRATORY, THORACIC AND MEDIASTINAL DISORDERS              27

And the most frequent preferred terms, counting events (every TEAE row, not just first occurrences):

teae %>%
  count(AEDECOD, sort = TRUE, name = "n_events") %>%
  head(8)
# A tibble: 8 × 2
  AEDECOD                     n_events
  <chr>                          <int>
1 PRURITUS                          78
2 APPLICATION SITE PRURITUS         77
3 ERYTHEMA                          56
4 APPLICATION SITE ERYTHEMA         46
5 APPLICATION SITE IRRITATION       41
6 RASH                              40
7 APPLICATION SITE DERMATITIS       36
8 DIZZINESS                         31

The picture is coherent and clinically obvious: general disorders and administration-site conditions and skin and subcutaneous tissue disorders dominate, and the top preferred terms are pruritus and application-site pruritus/erythema. Xanomeline in this study is a transdermal patch, so skin and application-site reactions are exactly the expected safety signal — and the derived ADAE surfaces it directly. That is the whole point of the dataset: once the flags are right, the adverse-event story falls out of a few count() calls.

🟢 With an AI agent

Ask Prova “how do I add a maximum-severity flag to my ADAE so I can build an AE table by worst severity grade per subject with admiral?” — it answers grounded in this pillar’s lessons, with runnable admiral code you can try on the example pharmaverse data. The runtime is the judge. Ask Prova →

Common issues

Your TEAE counts are too high — pre-treatment events are sneaking in. You filtered on the AE domain but not on TRTEMFL. An AE table must filter TRTEMFL == "Y"; without it, events that started before first dose (medical history captured as AEs) inflate every count. Derive the flag, then filter on it for every safety summary.

A “subjects with an AE” count is larger than the number of subjects. You counted AE rows, not subjects. Because ADAE has many rows per subject, count(TRT01A) on the raw rows counts events. To count subjects once, filter on the occurrence flag (AOCCFL == "Y" overall, AOCCSFL == "Y" per system organ class) — that is exactly what the occurrence flags are for.

derive_var_trtemfl() errors that ASTDTM/AENDTM are missing. Its defaults expect datetime variables. If you derived date variables with derive_vars_dt() (as here), pass them explicitly: start_date = ASTDT, end_date = AENDT. The datetime route (derive_vars_dtm()ASTDTM/AENDTM) is the alternative when you need the time component.

Every comparison against an SDTM character variable behaves oddly. You skipped convert_blanks_to_na(). SDTM uses empty strings "" for missing values, so is.na() returns FALSE on them and date imputation chokes. Always run convert_blanks_to_na() on the AE domain first.

Frequently asked questions

ADAE is the adverse-events analysis dataset — the ADaM dataset behind every adverse-event summary, listing, and treatment-emergent table. It follows the OCCDS occurrence structure, which is one row per adverse-event record (a subject with three events has three rows), and it carries treatment variables merged from ADSL plus analysis dates and the flags — TRTEMFL, AOCCFL — that safety analyses filter on.

A treatment-emergent adverse event is one that started on or after the first dose of study drug (commonly extended to a window after the last dose). It separates events plausibly related to treatment from pre-existing conditions recorded before dosing. In ADAE it is marked by the TRTEMFL flag ("Y" for emergent events), which admiral derives with derive_var_trtemfl() by comparing each AE’s analysis date to the treatment window. Safety tables count treatment-emergent events only.

Start from the SDTM AE domain and a pre-built ADSL. Merge ADSL’s treatment dates onto each AE record with derive_vars_merged(), convert the partial AE dates to real dates with derive_vars_dt(), derive the treatment-emergent flag with derive_var_trtemfl(), add the on-treatment flag with derive_var_ontrtfl(), and flag first occurrences with derive_var_extreme_flag() inside restrict_derivation(). The full sequence is worked through above and follows admiral’s OCCDS vignette.

Because ADAE uses the OCCDS occurrence structure: one row per event, not per subject. A subject who reports five adverse events contributes five rows. This is the opposite of ADSL, which is one row per subject. To count subjects (for a “subjects with ≥1 AE” table) you flag the first qualifying event per subject with an occurrence flag (AOCCFL) and count the flag — counting raw rows would count events, not subjects.

No — not to build or summarize it from the pilot data here. The system organ class (AEBODSYS) and preferred term (AEDECOD) are coded in the SDTM AE domain during the study’s MedDRA coding step, before ADaM. ADAE reads them as ordinary columns, so you can summarize events by body system or preferred term with no dictionary. MedDRA (and the licensed terminology) matters when you perform the coding upstream of SDTM, which is outside ADAE derivation.

TRTEMFL flags treatment-emergent events — those that started on or after first dose, usually including a window after last dose, so a late-onset event still counts. ONTRTFL flags on-treatment events — those falling strictly inside the treatment window. On-treatment is the stricter cut: every on-treatment event is treatment-emergent, but a treatment-emergent event in the post-treatment follow-up window is not on-treatment. Which one an analysis uses depends on the statistical analysis plan.

Test your understanding

Using the adae object built in this lesson, count how many subjects had at least one serious treatment-emergent adverse event, by treatment arm. Serious AEs are flagged by AESER == "Y" in the data. Count each subject once per arm.

You need treatment-emergent and serious and each subject counted once. Filter TRTEMFL == "Y" and AESER == "Y", then count distinct subjects per arm — distinct(USUBJID, TRT01A) before count(TRT01A) collapses each subject to one row. (You cannot reuse AOCCFL here: it flags the first AE of any kind, which may not be a serious one.)

adae %>%
  filter(TRTEMFL == "Y", AESER == "Y", TRT01A != "Screen Failure") %>%
  distinct(USUBJID, TRT01A) %>%
  count(TRT01A, name = "subjects_with_serious_teae")

Serious AEs are far rarer than AEs overall, so expect small counts in each arm. The key idea is that AOCCFL will not help: it flags a subject’s first treatment-emergent event regardless of seriousness, so to count subjects with a serious event you must filter on AESER and then reduce to distinct subjects yourself. In a production ADAE you would derive a dedicated serious-occurrence flag (derive_var_extreme_flag() restricted to TRTEMFL == "Y" & AESER == "Y") so the table is a single flag-count.

A. One row per subject B. One row per subject per parameter C. One row per adverse-event record (OCCDS)

C. ADAE uses the OCCDS occurrence structure — one row per adverse-event record, so a subject with several events has several rows. A describes ADSL (the subject-level dataset) and B describes the Basic Data Structure (BDS) used by ADTTE and ADLB. The occurrence structure is the reason ADAE relies on flags (TRTEMFL, AOCCFL) to mark which rows to count.

Conclusion

ADAE turns a raw stack of adverse-event records into an analysis-ready dataset by answering three questions per row: when did the event happen (the analysis dates ASTDT/AENDT and study day ASTDY), does it count as treatment-emergent (TRTEMFL, and the stricter ONTRTFL), and is it the one to count once (the occurrence flags AOCCFL/AOCCSFL). admiral turns each into a declarative step — derive_vars_merged(), derive_vars_dt(), derive_var_trtemfl(), derive_var_extreme_flag() — that is readable and traceable back to the SDTM AE source. Get the flags right and every safety summary is a short filter() plus count(), with the system organ class and preferred term already coded in the data. ADAE is the dataset that makes the adverse-event tables of a clinical study report a few lines of code instead of a maze of date logic.

Note

This lesson is reproducible: every result on this page was produced by the code shown — copy any block and run it to reproduce them. The runtime is the judge.

Reuse

Citation

BibTeX citation:
@online{2026,
  author = {},
  title = {Create {ADAE} in {R} with Admiral: The {Adverse-Events}
    {Analysis} {Dataset}},
  date = {2026-06-30},
  url = {https://www.datanovia.com/learn/pharma-clinical/03-adam-admiral/adae-adverse-events-admiral},
  langid = {en}
}
For attribution, please cite this work as:
“Create ADAE in R with Admiral: The Adverse-Events Analysis Dataset.” 2026. June 30. https://www.datanovia.com/learn/pharma-clinical/03-adam-admiral/adae-adverse-events-admiral.