| Type: | Package |
| Title: | Days Alive and Out of Hospital (DAOH) Calculation |
| Version: | 0.1.0 |
| Description: | Calculates Days Alive and Out of Hospital (DAOH) from administrative admission/discharge/mortality data using three algorithms (nights, days, exact) and three death-handling approaches (midday, midnight, zero). Includes tools for comparing methods (Bland-Altman, ICC, reclassification), and plotting. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| Imports: | ggplot2 (≥ 3.4.0), scales |
| Suggests: | testthat (≥ 3.0.0), knitr, rmarkdown, irr |
| LazyData: | true |
| VignetteBuilder: | knitr |
| URL: | https://github.com/davecumin/daoh |
| BugReports: | https://github.com/davecumin/daoh/issues |
| Config/roxygen2/version: | 8.0.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-06-12 19:44:10 UTC; dcum007 |
| Author: | David Cumin [aut, cre] |
| Maintainer: | David Cumin <d.cumin@auckland.ac.nz> |
| Depends: | R (≥ 3.5.0) |
| Repository: | CRAN |
| Date/Publication: | 2026-06-19 12:20:24 UTC |
Bland-Altman statistics for two DAOH variants
Description
Computes the mean difference, standard deviation of differences, and 95% limits of agreement between two DAOH vectors (matched by patientID x indexDate).
Usage
bland_altman_daoh(res_a, res_b, use_pc = TRUE)
Arguments
res_a, res_b |
data.frames (output of |
use_pc |
Logical. If |
Value
A list with elements mean_diff, sd_diff, loa_lower,
loa_upper, and data (data.frame of paired values for plotting).
Calculate Days Alive and Out of Hospital (DAOH)
Description
The main calculation function. For each patient-index-date pair, computes DAOH using the specified hospital-time algorithm and death-handling approach.
Usage
calc_daoh(
events,
index_dates,
period = 90,
method = c("nights", "days", "exact"),
death_method = c("midday", "midnight", "zero"),
gap_hours = 12,
origin = as.Date("1970-01-01")
)
Arguments
events |
|
index_dates |
|
period |
Numeric. Follow-up period in days. Default 90. |
method |
Character. Hospital-time algorithm: |
death_method |
Character. How to handle death: |
gap_hours |
Numeric. Gap tolerance in hours for merging adjacent admissions. Default 12. |
origin |
Date. Numeric reference date. Default |
Value
A data.frame with one row per patient-index-date pair and columns:
patientIDPatient identifier.
indexDateIndex date.
n_episodesNumber of merged hospital episodes in period.
dihDays in hospital (numeric, using chosen algorithm).
ddDays dead within the period (0 if survived or death=0).
daohDAOH in days.
daohPCDAOH as a percentage of the period (0-100).
DAOH formula
\text{DAOH} = \max\!\bigl(0,\; T - H - D\bigr)
where:
TPeriod length in days (e.g., 90).
HTotal hospital time within the period (days), computed from merged, boundary-truncated intervals. See
hospital_time().DTotal dead time within the period (days), computed from date of death. See
dead_time().
Overlapping hospital events are merged using a 12-hour gap tolerance before summing: any two admissions separated by <= 12 hours are treated as a single continuous episode. This removes double-counting and models the clinical reality that rapid re-admissions represent continuous care.
Algorithm differences
For N merged hospital episodes in the period, the systematic
difference between algorithms is:
H^{\text{days}} - H^{\text{nights}} \approx N_{\text{episodes}}
because each episode contributes one additional day under the days algorithm (admission = 00:00, discharge = 24:00 vs. both at noon). Therefore:
\text{DAOH}^{\text{nights}} - \text{DAOH}^{\text{days}} \approx N_{\text{episodes}}
Examples
# --- Example 1: Simple day-stay (highlights nights vs days difference) ---
events <- data.frame(
patientID = "P1",
admission = as.Date("2020-03-10"),
discharge = as.Date("2020-03-10"), # same-day admission
dod = NA
)
idx <- data.frame(patientID = "P1", indexDate = as.Date("2020-03-10"))
calc_daoh(events, idx, period = 30, method = "nights")$daoh # 30 days
calc_daoh(events, idx, period = 30, method = "days")$daoh # 29 days
# --- Example 2: Death handling ---
events2 <- data.frame(
patientID = "P2",
admission = as.Date("2020-03-10"),
discharge = as.Date("2020-03-12"),
dod = as.Date("2020-03-20") # died 8 days after discharge
)
idx2 <- data.frame(patientID = "P2", indexDate = as.Date("2020-03-10"))
calc_daoh(events2, idx2, period = 30, method = "nights",
death_method = "midday")$daoh # credits pre-death days
calc_daoh(events2, idx2, period = 30, method = "nights",
death_method = "zero")$daoh # returns 0
Clip intervals to a window and return total length
Description
Clips merged intervals to [window_start, window_end] and returns the sum of their lengths. Used internally to calculate total time in hospital or dead within the DAOH period.
Usage
clip_and_sum(intervals, window_start, window_end)
Arguments
intervals |
data.frame with columns |
window_start |
Numeric start of the clipping window. |
window_end |
Numeric end of the clipping window. |
Value
Scalar numeric: total length of intervals within the window.
Intraclass Correlation Coefficient across DAOH methods
Description
Computes two-way mixed ICC (consistency) treating each DAOH calculation method as a rater, following Shrout & Fleiss (1979). Requires the irr package.
Usage
daoh_icc(results_list, use_pc = TRUE)
Arguments
results_list |
Named list of data.frames (output of |
use_pc |
Logical. Use |
Value
The output of irr::icc() for the combined method matrix.
Quartile reclassification across two DAOH methods
Description
Assesses the practical impact of switching from one DAOH method to another by computing the proportion of patients who move between quartiles. Analogous to the Net Reclassification Index (NRI).
Usage
daoh_reclassify(res_a, res_b, n_groups = 4, use_pc = TRUE)
Arguments
res_a, res_b |
data.frames (output of |
n_groups |
Integer. Number of groups (default 4 = quartiles). |
use_pc |
Logical. Use |
Value
A list with:
confusion_matrixTable of group assignments under a vs b.
pct_reclassifiedPercentage of patients changing group.
mean_group_shiftMean absolute group shift.
Examples
# See vignette("getting_started", package = "daoh")
Centile-boundary reclassification across two DAOH methods
Description
For each specified centile boundary, classifies patients as inside or outside that boundary under each algorithm — using each algorithm's own empirical threshold — then reports the proportion classified differently. This quantifies the clinical impact of algorithm choice at cut-points such as "bottom 10% poor outcome", which are common in adaptive trial enrichment and secondary outcome definitions.
Usage
daoh_reclassify_centile(
res_a,
res_b,
boundaries = c(0.05, 0.1, 0.9, 0.95),
use_pc = TRUE
)
Arguments
res_a, res_b |
data.frames (output of |
boundaries |
Numeric vector of centile probabilities at which to
evaluate reclassification. Values below 0.5 define lower ("poor outcome")
boundaries; values at or above 0.5 define upper ("excellent outcome")
boundaries. Default |
use_pc |
Logical. Use |
Details
Unlike daoh_reclassify(), which uses a pooled distribution to set group
boundaries, this function applies each algorithm's threshold independently.
That reflects the realistic scenario in which a researcher picks a single
algorithm, defines a centile-based threshold from their own study population,
and applies it — so the threshold itself changes with the algorithm.
Value
A data.frame with one row per boundary and columns:
boundaryHuman-readable label, e.g.
"Bottom 5%"or"Top 10%".centileThe probability supplied in
boundaries.threshold_aEmpirical centile value for algorithm A.
threshold_bEmpirical centile value for algorithm B.
n_patientsNumber of matched patient-index pairs evaluated.
n_reclassifiedNumber of patients classified differently across the boundary.
pct_reclassifiedPercentage classified differently.
See Also
daoh_reclassify() for group-based (quartile) reclassification.
Examples
# See vignette("getting_started", package = "daoh")
Compute DAOH summary statistics across all methods and periods
Description
Compute DAOH summary statistics across all methods and periods
Usage
daoh_summary(results_list, quantiles = c(0.1, 0.25, 0.5))
Arguments
results_list |
Named list of data.frames, each the output of
|
quantiles |
Numeric vector of quantiles to report. Default
|
Value
A data.frame with one row per method/period and columns for mean, median, and the requested quantiles.
Calculate dead time within a DAOH period
Description
Calculate dead time within a DAOH period
Usage
dead_time(
dod,
period_start,
period_end,
death_method = c("midday", "midnight", "zero"),
origin = as.Date("1970-01-01")
)
Arguments
dod |
Date or |
period_start |
Numeric. Start of the DAOH period (days since origin). |
period_end |
Numeric. End of the DAOH period (days since origin). |
death_method |
Character: |
origin |
Date used as numeric zero. |
Value
Numeric: dead time in days within the period. NA if
death_method = "zero" and death occurred in the period (caller should
set DAOH to 0).
Mathematical definitions
Let t_0 be the index date (numeric, days) and T the period
length in days, so the period window is [t_0,\; t_0 + T].
Midday death (default):
D = [t_{\text{DOD}} + 0.5,\; t_0 + T]
i.e., the patient is assumed to die at noon on the date of death.
Midnight death (conservative):
D = [t_{\text{DOD}},\; t_0 + T]
The patient is assumed to die at midnight (start of the day of death), maximising dead time.
Death = 0:
If the patient died at any time within [t_0, t_0 + T], DAOH is
set to 0 directly (handled in calc_daoh(), not here).
If t_{\text{DOD}} is outside the period, dead time is 0.
Synthetic patient example: single day-stay admission
Description
A minimal example designed to illustrate the difference between the 'nights' and 'days' algorithms for a same-day (day-stay) admission. Under 'nights' the patient contributes 0 nights (DAOH = 30). Under 'days' the patient contributes 1 day (DAOH = 29).
Usage
example_daystay
Format
A list with two data.frames:
eventsOne row: day-stay admission on the index date, no death.
index_datesOne row: the index date for this patient.
Examples
data(example_daystay)
calc_daoh(example_daystay$events, example_daystay$index_dates,
period = 30, method = "nights")
calc_daoh(example_daystay$events, example_daystay$index_dates,
period = 30, method = "days")
Synthetic patient example: multiple admissions and death
Description
A patient with four hospital admissions who dies 8 days after the last discharge, within a 30-day follow-up period. Illustrates all seven DAOH variants.
Usage
example_death
Format
A list with two data.frames:
eventsFour rows of admissions plus date of death.
index_datesOne index date (day of first admission).
Examples
data(example_death)
# All seven variants
for (meth in c("nights", "days", "exact")) {
for (dm in c("midday", "midnight", "zero")) {
res <- calc_daoh(example_death$events, example_death$index_dates,
period = 30, method = meth, death_method = dm)
cat(meth, dm, "DAOH =", round(res$daoh, 2), "\n")
}
}
Synthetic population: 500 patients, mixed admission patterns
Description
A larger synthetic dataset suitable for demonstrating summary statistics, Bland-Altman analysis, and reclassification. Patients have between 1 and 5 admissions over a 365-day period, with a 5% mortality rate.
Usage
example_population
Format
A list with two data.frames:
eventsHospital events with columns patientID, admission, discharge, dod.
index_datesOne index date per patient.
Examples
data(example_population)
res_n <- calc_daoh(example_population$events, example_population$index_dates,
period = 90, method = "nights")
res_d <- calc_daoh(example_population$events, example_population$index_dates,
period = 90, method = "days")
bland_altman_daoh(res_n, res_d)
Convert admission/discharge date pairs to numeric time intervals
Description
Applies one of the three DAOH hospital-time algorithms to convert admission and discharge dates (or datetimes) into numeric time intervals expressed in fractional days from a reference origin.
Usage
hospital_time(
admission_dates,
discharge_dates,
method = c("nights", "days", "exact"),
origin = as.Date("1970-01-01")
)
Arguments
admission_dates |
Date or POSIXct vector of admission dates/times. |
discharge_dates |
Date or POSIXct vector of discharge dates/times. |
method |
Character string: |
origin |
Date or POSIXct used as numeric zero. Defaults to
|
Value
A data.frame with columns start (numeric, days since origin) and
end (numeric, days since origin) representing the hospital time
interval under the chosen algorithm.
Mathematical definitions
Let a_i be the admission date and d_i the discharge date for
event i, expressed as calendar dates (integers at midnight).
Nights algorithm
h_i = d_i - a_i
Equivalent to assuming both admission and discharge occur at 12:00 (noon). A same-day admission contributes 0 nights. This matches the conventional hospital "length of stay" metric.
Days algorithm
h_i = (d_i + 1) - a_i
Equivalent to assuming admission at 00:00 and discharge at 24:00 of the
respective dates. A same-day admission contributes 1 day. For any
admission, h_i^{\text{days}} = h_i^{\text{nights}} + 1, so the
total difference across N merged episodes equals N days:
H^{\text{days}} - H^{\text{nights}} \approx N_{\text{episodes}}
Exact algorithm
h_i = t_i^{\text{discharge}} - t_i^{\text{admission}}
Uses recorded timestamps directly (in fractional days). Partial days are included.
Examples
# Same-day admission: nights=0, days=1
hospital_time(
admission_dates = as.Date("2020-03-01"),
discharge_dates = as.Date("2020-03-01"),
method = "nights"
)
hospital_time(
admission_dates = as.Date("2020-03-01"),
discharge_dates = as.Date("2020-03-01"),
method = "days"
)
# Two-night stay
hospital_time(
admission_dates = as.Date("2020-03-01"),
discharge_dates = as.Date("2020-03-03"),
method = "nights" # 2 nights
)
Load a built-in example dataset
Description
Reads one of the three synthetic example datasets bundled with the
package as CSV files in inst/extdata/. This is the preferred way
to access examples without needing to run the data-generation script.
Usage
load_example(name = c("daystay", "death", "population"))
Arguments
name |
Character. One of:
|
Value
A named list with elements events and index_dates, both
data.frames ready to pass directly to calc_daoh().
Examples
ex <- load_example("daystay")
calc_daoh(ex$events, ex$index_dates, period = 30, method = "nights")
calc_daoh(ex$events, ex$index_dates, period = 30, method = "days")
Merge overlapping or near-adjacent time intervals
Description
Given a set of intervals [start, end], merges those that overlap or are
separated by less than gap time units. This is used to consolidate
hospital admissions that are separated by short gaps (e.g., < 12 hours),
treating them as a single continuous episode.
Usage
merge_intervals(starts, ends, gap = 0.5)
Arguments
starts |
Numeric or POSIXct vector of interval start times. |
ends |
Numeric or POSIXct vector of interval end times (must be >= the corresponding start). |
gap |
Numeric. Intervals with a gap smaller than this value are
merged. Units must match |
Value
A data.frame with columns start and end representing the
merged intervals, sorted by start time.
Examples
# Two admissions 10 hours apart -> merged into one
merge_intervals(
starts = c(0, 1.5),
ends = c(1.0, 2.5),
gap = 0.5
)
# Two admissions 2 days apart -> kept separate
merge_intervals(
starts = c(0, 3),
ends = c(1, 4),
gap = 0.5
)
Plot a Bland-Altman comparison of two DAOH methods
Description
Plot a Bland-Altman comparison of two DAOH methods
Usage
plot_daoh_ba(
ba_result,
method_a = "Method A",
method_b = "Method B",
use_hex = TRUE
)
Arguments
ba_result |
Output of |
method_a, method_b |
Character labels for the two methods. |
use_hex |
Logical. Use |
Value
A ggplot2 object.
Plot the distribution of DAOH scores
Description
Produces a histogram of DAOH scores (as percentage) with deaths overlaid in a contrasting colour. The y-axis is log-scaled to aid visualisation of the bimodal distribution.
Usage
plot_daoh_dist(result, log_y = TRUE, title = "DAOH distribution", bins = 50)
Arguments
result |
data.frame (output of |
log_y |
Logical. Use log10 y-axis (default |
title |
Character. Plot title. |
bins |
Integer. Number of histogram bins (default 50). |
Value
A ggplot2 object.
Visualise quartile reclassification between two DAOH methods
Description
Plots a heatmap of the reclassification table (method A group vs method B group) with cell counts and an annotation of the overall reclassification rate.
Usage
plot_daoh_reclassify(
reclass_result,
method_a = "Method A",
method_b = "Method B"
)
Arguments
reclass_result |
Output of |
method_a, method_b |
Character labels for the two methods. |
Value
A ggplot2 object.