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.
\[\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]\).
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.66667For 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.
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.0Note the wide range of DAOH values (0% to ~40%) depending on the method chosen — underscoring the importance of explicit reporting.
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 daysba <- 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")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")