Getting started with the daoh package

David Cumin

Overview

The daoh package calculates Days Alive and Out of Hospital (DAOH) from administrative admission/discharge/mortality records.

The package supports three hospital-time algorithms and three approaches to incorporating death, allowing direct comparison of results under different methodological assumptions.


Core formula

\[\text{DAOH} = \max\!\bigl(0,\; T - H - D\bigr)\]

where \(T\) is the follow-up period (days), \(H\) is total merged hospital time, and \(D\) is dead time, both clipped to \([t_0,\; t_0 + T]\).


Example 1 — Day-stay: the 1-day difference

A patient admitted and discharged on the same calendar date contributes 0 nights (nights algorithm) but 1 day (days algorithm). This is the most common source of disagreement between the two approaches.

ex <- load_example("daystay")
ex$events
#>   patientID  admission  discharge  dod
#> 1      P001 2020-03-10 2020-03-10 <NA>

# Nights: 0 nights in hospital -> DAOH = 30/30 = 100%
calc_daoh(ex$events, ex$index_dates, period = 30, method = "nights")
#>   patientID  indexDate n_episodes dih dd daoh daohPC
#> 1      P001 2020-03-10          1   0  0   30    100

# Days: 1 day in hospital -> DAOH = 29/30 = 96.7%
calc_daoh(ex$events, ex$index_dates, period = 30, method = "days")
#>   patientID  indexDate n_episodes dih dd daoh   daohPC
#> 1      P001 2020-03-10          1   1  0   29 96.66667

For a population with \(N\) merged hospital episodes in the period:

\[H^{\text{days}} - H^{\text{nights}} \approx N_{\text{episodes}}\]

So the expected difference in DAOH (days − nights) equals the mean number of distinct hospital episodes per patient.


Example 2 — Death handling

A patient with four admissions who dies within the 30-day follow-up period.

ex2 <- load_example("death")
ex2$events
#>   patientID  admission  discharge        dod
#> 1      P002 2020-01-01 2020-01-02 2020-01-18
#> 2      P002 2020-01-05 2020-01-07 2020-01-18
#> 3      P002 2020-01-05 2020-01-05 2020-01-18
#> 4      P002 2020-01-09 2020-01-10 2020-01-18

# All seven variants
results <- expand.grid(
  method       = c("nights", "days", "exact"),
  death_method = c("midday", "midnight", "zero"),
  stringsAsFactors = FALSE
)

results$daoh <- mapply(function(m, dm) {
  calc_daoh(ex2$events, ex2$index_dates,
            period = 30, method = m, death_method = dm)$daoh
}, results$method, results$death_method)

results$daohPC <- round(100 * results$daoh / 30, 1)
print(results)
#>   method death_method daoh daohPC
#> 1 nights       midday 13.5   45.0
#> 2   days       midday 10.5   35.0
#> 3  exact       midday 13.5   45.0
#> 4 nights     midnight 13.0   43.3
#> 5   days     midnight 10.0   33.3
#> 6  exact     midnight 13.0   43.3
#> 7 nights         zero  0.0    0.0
#> 8   days         zero  0.0    0.0
#> 9  exact         zero  0.0    0.0

Note the wide range of DAOH values (0% to ~40%) depending on the method chosen — underscoring the importance of explicit reporting.


Example 3 — Population-level analysis

pop <- load_example("population")

Compare nights vs days

res_n <- calc_daoh(pop$events, pop$index_dates, period = 90, method = "nights")
res_d <- calc_daoh(pop$events, pop$index_dates, period = 90, method = "days")

# Summary statistics
cat("Nights: median DAOH% =", round(median(res_n$daohPC), 1), "\n")
#> Nights: median DAOH% = 96.7
cat("Days:   median DAOH% =", round(median(res_d$daohPC), 1), "\n")
#> Days:   median DAOH% = 94.4

# Difference ≈ number of episodes per patient
cat("Mean episodes (nights):", round(mean(res_n$n_episodes), 2), "\n")
#> Mean episodes (nights): 1.71
cat("Mean difference in DAOH (nights - days):",
    round(mean(res_n$daoh - res_d$daoh), 3), "days\n")
#> Mean difference in DAOH (nights - days): 1.706 days

Bland-Altman analysis

ba <- bland_altman_daoh(res_n, res_d)
cat(sprintf("Mean difference: %.3f%%\n95%% LoA: %.3f%% to %.3f%%\n",
            ba$mean_diff, ba$loa_lower, ba$loa_upper))
#> Mean difference: 1.896%
#> 95% LoA: 0.085% to 3.706%

plot_daoh_ba(ba, method_a = "Nights", method_b = "Days")

Quartile reclassification

rc <- daoh_reclassify(res_n, res_d, n_groups = 4)
cat(sprintf("%.1f%% of patients change quartile when switching nights → days\n",
            rc$pct_reclassified))
#> 51.6% of patients change quartile when switching nights → days
print(rc$confusion_matrix)
#>    b
#> a     1   2   3
#>   1  91   0   0
#>   2  71  57   0
#>   3   0  82  94
#>   4   0   0 105
plot_daoh_reclassify(rc, method_a = "Nights", method_b = "Days")

Distribution plot

plot_daoh_dist(res_n, title = "DAOH – Nights algorithm, 90-day period")