# Introduction to sdtmchecks

The purpose of the `sdtmchecks` package is to help detect and investigate potential analysis relevant issues in SDTM data. This is done using a set of data check functions. These check functions are intended to be generalizable, actionable, and meaningful for analysis.

## Setting Up

To start using `sdtmchecks` first install it via

    # install.packages("devtools")
    devtools::install_github("pharmaverse/sdtmchecks", ref="main")

Then just load the package

    library(sdtmchecks)

## Documentation

Here’s how to access the help page for the package

    # type ??sdtmchecks into the console
    ??sdtmchecks

## Metadata

The package comes with the `sdtmchecksmeta` dataset which contains metadata on each check function. It contains details like function name, category, priority, and descriptions. Each function is given a Category (Cross Therapeutic Area, Oncology, Covid-19, Patient Reported Outcomes, Ophthalmology) and a Priority (High, Medium, Low).

    #Just type this in
    sdtmchecksmeta

    ## # A tibble: 10 × 5
    ##    check                              title            category priority domains
    ##    <chr>                              <chr>            <chr>    <chr>    <chr>
    ##  1 check_ae_aeacn_ds_disctx_covid     COVID AE trt di… COVID    Low      ae, ds
    ##  2 check_ae_aeacnoth                  AE AEACNOTH mul… ALL      Low      ae
    ##  3 check_ae_aeacnoth_ds_disctx        AE AEACNOTx Dis… ALL      Low      ae, ds
    ##  4 check_ae_aeacnoth_ds_stddisc_covid COVID AE study … COVID    Low      ae, ds
    ##  5 check_ae_aedecod                   AE Missing PT    ALL      High     ae
    ##  6 check_ae_aedthdtc_aesdth           AE Death Date v… ALL      High     ae
    ##  7 check_ae_aedthdtc_ds_death         DS Death Dates … ALL      High     ae, ds
    ##  8 check_ae_aelat                     AE AELAT Missing OPHTH    High     ae
    ##  9 check_ae_aeout                     AE Death Outcome ALL      High     ae
    ## 10 check_ae_aeout_aeendtc_aedthdtc    Fatal AE Resolu… ALL      High     ae

## Running a Check

Let’s do an example using `check_ae_ds_partial_death_dates(AE,DS)`

This check flags records with partial death dates (i.e. length <10) in AE and DS. If any are found, then data check returns `FALSE` with attributes containing a list of flagged records as well as a brief message explaining the result. If no issues are detected the check returns `TRUE`.

    # Use sample data frames.
    AE

    ##   USUBJID AEDECOD   AEDTHDTC
    ## 1       1     AE1 2017-01-01
    ## 2       2     AE2       2017
    ## 3       3     AE3       <NA>

    DS

    ##   USUBJID       DSSCAT DSDECOD    DSSTDTC
    ## 1       4 STUDY DISCON   DEATH 2018-01-01
    ## 2       5 STUDY DISCON   DEATH 2017-03-03
    ## 3       6 STUDY DISCON   DEATH 2018-01-02
    ## 4       7 STUDY DISCON   DEATH    2016-10

    # Run the data check.
    check_ae_ds_partial_death_dates(AE,DS)

    ## [1] FALSE
    ## attr(,"msg")
    ## [1] "There are 2 patients with partial death dates. "
    ## attr(,"data")
    ##   USUBJID       DSSCAT DSDECOD DSSTDTC AEDECOD AEDTHDTC
    ## 1       2         <NA>    <NA>    <NA>     AE2     2017
    ## 2       7 STUDY DISCON   DEATH 2016-10    <NA>     <NA>

## Running Many Checks

Running all the checks on your data is super easy. Just use the `run_all_checks` function. This function assumes you have all of your sdtm datasets as objects in your global environment, e.g. `ae`,`dm`,`ex`,etc.

    # Read data to your global environment
    ae = haven::read_sas("path/to/ae.sas7bdat")
    ds = haven::read_sas("path/to/ds.sas7bdat")

    # Run the checks and save as an object called "myreport"
    myreport=run_all_checks(metads = sdtmchecksmeta,
                   priority = c("High", "Medium", "Low"), #subset checks based on priority
                   type = c("ALL", "ONC", "COVID", "PRO", "OPHTH"), #subset checks based category
                   verbose = TRUE)

    class(myreport) #results in a list object
    names(myreport) #each check result is saved in a slot of the list
    myreport[["check_ae_aedecod"]] #investigate the results of a check

The `run_all_checks` function also lets you easily subset on category or priority

    myreport=run_all_checks(metads = sdtmchecksmeta,
                   priority = c("High"),
                   type = c("ONC"),
                   verbose = TRUE)

You can also choose specific checks to run. Here’s a way to get started with some checks that should work fairly well for most datasets

    # Read data to your global environment
    ae = haven::read_sas("path/to/ae.sas7bdat")
    cm = haven::read_sas("path/to/cm.sas7bdat")
    dm = haven::read_sas("path/to/dm.sas7bdat")

    # Subset to checks that should work OK for most datasets
    metads = sdtmchecksmeta %>%
      filter(check %in% c("check_ae_aedecod",
                          "check_ae_aetoxgr",
                          "check_ae_dup",
                          "check_cm_cmdecod",
                          "check_cm_missing_month",
                          "check_dm_age_missing",
                          "check_dm_usubjid_dup",
                          "check_dm_armcd"
                          ))

    myreport=run_all_checks(metads = metads,
                   verbose = TRUE)

## Writing Out Results

You can then write results out to an xlsx for easy sharing.

    report_to_xlsx(res=myreport,outfile="check_report.xlsx")

## Making a Customizable Script

There’s also a convenient helper function to write out a user friendly R script with all the check function calls.

    create_R_script(file = "run_the_checks.R")