The early_warning_biomarker function is designed to detect unexpected changes in biomarker values for individual patients based on clinical chemistry data. It will flag cases where patients' biomarker results deviate from defined thresholds or exhibit significant changes within a specified time window.

early_warning_biomarker(
  df,
  testcode = NULL,
  ...,
  column_date = NULL,
  column_patientid = NULL,
  column_testcode = NULL,
  column_testresult = NULL,
  threshold_min = NULL,
  threshold_max = NULL,
  window_days = NULL,
  max_delta_absolute = NULL,
  max_delta_relative = NULL,
  direction = "any"
)

Arguments

df

A data frame containing clinical chemistry data with columns for patient ID, date, test code, and test result.

testcode

Value of the column containing test codes to filter on.

...

Filter arguments, e.g. testcode == "eGFR"

column_date

Name of the column to use for dates. If left blank, the first date column will be used.

column_patientid

Name of the column to use for patient IDs. If left blank, the first column resembling "patient|patid" will be used.

column_testcode

Name of the column containing test codes.

column_testresult

Name of the column containing test results.

threshold_min

Minimum threshold for biomarkers.

threshold_max

Maximum threshold for biomarkers.

window_days

Number of days for the time window to check for changes.

max_delta_absolute

Maximum allowable absolute change in biomarkers.

max_delta_relative

Maximum allowable relative change in biomarkers.

direction

Direction of change to check ("up", "down", or "any").

Value

A list with the following components:

  • flags: A list of flags per patient, containing data frames for each patient with details on dates, test codes, test results, and flagging criteria. The structure of each data frame includes the following columns:

    • patient: Patient identifier.

    • date: Date of the biomarker measurement.

    • testcode: Code of the biomarker test.

    • testresult: Biomarker test result.

    • delta_absolute: Absolute change in biomarker values.

    • delta_relative: Relative change in biomarker values.

    • threshold_min_flag: A logical flag indicating if the threshold minimum is exceeded.

    • threshold_max_flag: A logical flag indicating if the threshold maximum is exceeded.

    • delta_absolute_flag: A logical flag indicating if the absolute change exceeds the threshold.

    • delta_relative_flag: A logical flag indicating if the relative change exceeds the threshold.

  • details: A data frame containing all patient details and calculated flags, regardless of whether they meet the flagging criteria. The data frame includes the same columns as the individual patient data frames.

Details

This whole function, including the documentation, was written by ChatGPT 3.5 in October 2023. Only minor changes were applied manually.

This function is particularly useful in early detection of anomalous biomarker results, which can be indicative of health issues or treatment response. By providing detailed flags, it allows healthcare professionals and researchers to take timely action, conduct further investigations, or make informed clinical decisions.

The output of this function can be utilised for:

  • Generating patient-specific reports for healthcare providers.

  • Identifying trends and patterns in biomarker changes for research purposes.

  • Enhancing patient care by enabling proactive interventions when necessary.

  • Supporting data-driven clinical epidemiology studies and research.

The format() function allows you to format the results of the early_warning_biomarker() function for better readability and analysis. It organises the flag information into a structured data frame for easier inspection.

Examples

data <- data.frame(date = Sys.Date() + 1:10,
                   patient = "test",
                   value = c(10,12,14,15,13,21,22,19,14,12))

check <- data |> early_warning_biomarker(window_days = 6, max_delta_absolute = 10)
#> Using column 'date' for dates
#> Using column 'patient' for patient IDs
#> Using column 'value' for test results

check
#> A total of 1 patients with a total of 2 flags.
#> 
#> # A tibble: 1 × 6
#>   patient total_flags flag_threshold_min flag_threshold_max flag_delta_absolute
#>   <chr>         <int>              <int>              <int>               <int>
#> 1 test              2                  0                  0                   2
#> # ℹ 1 more variable: flag_delta_relative <int>

unlist(check)
#>             flags.test.patient1             flags.test.patient2 
#>                          "test"                          "test" 
#>                flags.test.date1                flags.test.date2 
#>                         "20038"                         "20039" 
#>            flags.test.testcode1            flags.test.testcode2 
#>                              NA                              NA 
#>          flags.test.testresult1          flags.test.testresult2 
#>                            "21"                            "22" 
#>      flags.test.delta_absolute1      flags.test.delta_absolute2 
#>                             "8"                             "1" 
#>      flags.test.delta_relative1      flags.test.delta_relative2 
#>             "0.615384615384615"            "0.0476190476190476" 
#>  flags.test.threshold_min_flag1  flags.test.threshold_min_flag2 
#>                         "FALSE"                         "FALSE" 
#>  flags.test.threshold_max_flag1  flags.test.threshold_max_flag2 
#>                         "FALSE"                         "FALSE" 
#> flags.test.delta_absolute_flag1 flags.test.delta_absolute_flag2 
#>                          "TRUE"                          "TRUE" 
#> flags.test.delta_relative_flag1 flags.test.delta_relative_flag2 
#>                         "FALSE"                         "FALSE" 
#>  flags.test.sum_delta_absolute1  flags.test.sum_delta_absolute2 
#>                            "11"                            "12" 
#>     flags.test.cumulative_days1     flags.test.cumulative_days2 
#>                             "5"                             "6" 
#>                details.patient1                details.patient2 
#>                          "test"                          "test" 
#>                details.patient3                details.patient4 
#>                          "test"                          "test" 
#>                details.patient5                details.patient6 
#>                          "test"                          "test" 
#>                details.patient7                details.patient8 
#>                          "test"                          "test" 
#>                details.patient9               details.patient10 
#>                          "test"                          "test" 
#>                   details.date1                   details.date2 
#>                         "20033"                         "20034" 
#>                   details.date3                   details.date4 
#>                         "20035"                         "20036" 
#>                   details.date5                   details.date6 
#>                         "20037"                         "20038" 
#>                   details.date7                   details.date8 
#>                         "20039"                         "20040" 
#>                   details.date9                  details.date10 
#>                         "20041"                         "20042" 
#>               details.testcode1               details.testcode2 
#>                              NA                              NA 
#>               details.testcode3               details.testcode4 
#>                              NA                              NA 
#>               details.testcode5               details.testcode6 
#>                              NA                              NA 
#>               details.testcode7               details.testcode8 
#>                              NA                              NA 
#>               details.testcode9              details.testcode10 
#>                              NA                              NA 
#>             details.testresult1             details.testresult2 
#>                            "10"                            "12" 
#>             details.testresult3             details.testresult4 
#>                            "14"                            "15" 
#>             details.testresult5             details.testresult6 
#>                            "13"                            "21" 
#>             details.testresult7             details.testresult8 
#>                            "22"                            "19" 
#>             details.testresult9            details.testresult10 
#>                            "14"                            "12" 
#>         details.delta_absolute1         details.delta_absolute2 
#>                             "0"                             "2" 
#>         details.delta_absolute3         details.delta_absolute4 
#>                             "2"                             "1" 
#>         details.delta_absolute5         details.delta_absolute6 
#>                            "-2"                             "8" 
#>         details.delta_absolute7         details.delta_absolute8 
#>                             "1"                            "-3" 
#>         details.delta_absolute9        details.delta_absolute10 
#>                            "-5"                            "-2" 
#>         details.delta_relative1         details.delta_relative2 
#>                             "0"                           "0.2" 
#>         details.delta_relative3         details.delta_relative4 
#>             "0.166666666666667"            "0.0714285714285714" 
#>         details.delta_relative5         details.delta_relative6 
#>            "-0.133333333333333"             "0.615384615384615" 
#>         details.delta_relative7         details.delta_relative8 
#>            "0.0476190476190476"            "-0.136363636363636" 
#>         details.delta_relative9        details.delta_relative10 
#>            "-0.263157894736842"            "-0.142857142857143" 
#>     details.threshold_min_flag1     details.threshold_min_flag2 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_min_flag3     details.threshold_min_flag4 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_min_flag5     details.threshold_min_flag6 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_min_flag7     details.threshold_min_flag8 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_min_flag9    details.threshold_min_flag10 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_max_flag1     details.threshold_max_flag2 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_max_flag3     details.threshold_max_flag4 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_max_flag5     details.threshold_max_flag6 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_max_flag7     details.threshold_max_flag8 
#>                         "FALSE"                         "FALSE" 
#>     details.threshold_max_flag9    details.threshold_max_flag10 
#>                         "FALSE"                         "FALSE" 
#>    details.delta_absolute_flag1    details.delta_absolute_flag2 
#>                         "FALSE"                         "FALSE" 
#>    details.delta_absolute_flag3    details.delta_absolute_flag4 
#>                         "FALSE"                         "FALSE" 
#>    details.delta_absolute_flag5    details.delta_absolute_flag6 
#>                         "FALSE"                          "TRUE" 
#>    details.delta_absolute_flag7    details.delta_absolute_flag8 
#>                          "TRUE"                         "FALSE" 
#>    details.delta_absolute_flag9   details.delta_absolute_flag10 
#>                         "FALSE"                         "FALSE" 
#>    details.delta_relative_flag1    details.delta_relative_flag2 
#>                         "FALSE"                         "FALSE" 
#>    details.delta_relative_flag3    details.delta_relative_flag4 
#>                         "FALSE"                         "FALSE" 
#>    details.delta_relative_flag5    details.delta_relative_flag6 
#>                         "FALSE"                         "FALSE" 
#>    details.delta_relative_flag7    details.delta_relative_flag8 
#>                         "FALSE"                         "FALSE" 
#>    details.delta_relative_flag9   details.delta_relative_flag10 
#>                         "FALSE"                         "FALSE" 
#>     details.sum_delta_absolute1     details.sum_delta_absolute2 
#>                             "0"                             "2" 
#>     details.sum_delta_absolute3     details.sum_delta_absolute4 
#>                             "4"                             "5" 
#>     details.sum_delta_absolute5     details.sum_delta_absolute6 
#>                             "3"                            "11" 
#>     details.sum_delta_absolute7     details.sum_delta_absolute8 
#>                            "12"                             "9" 
#>     details.sum_delta_absolute9    details.sum_delta_absolute10 
#>                             "4"                             "2" 
#>        details.cumulative_days1        details.cumulative_days2 
#>                             "0"                             "1" 
#>        details.cumulative_days3        details.cumulative_days4 
#>                             "2"                             "3" 
#>        details.cumulative_days5        details.cumulative_days6 
#>                             "4"                             "5" 
#>        details.cumulative_days7        details.cumulative_days8 
#>                             "6"                             "7" 
#>        details.cumulative_days9       details.cumulative_days10 
#>                             "8"                             "9" 
#>               details.any_flag1               details.any_flag2 
#>                         "FALSE"                         "FALSE" 
#>               details.any_flag3               details.any_flag4 
#>                         "FALSE"                         "FALSE" 
#>               details.any_flag5               details.any_flag6 
#>                         "FALSE"                          "TRUE" 
#>               details.any_flag7               details.any_flag8 
#>                          "TRUE"                         "FALSE" 
#>               details.any_flag9              details.any_flag10 
#>                         "FALSE"                         "FALSE"