This package implements functions to convert prevalence to incidence based on data obtained in point-prevalence studies (PPSs) along the lines of (Rhame and Sudderth 1981),(Freeman and Hutchison 1980) and is a companion to an upcoming paper (Willrich et al. 2019). It also implements methods to simulate PPS-data to benchmark different estimation methods. Notation will follow the companion paper. So a good idea is to read the paper first and afterwards the vignette.
The package has functions to simulate PPS-data based on distributions of length of infection and length of stay. Results of PPS simulations and incidence calculations are stored as tibbles. The functionality in the package can be divided in three parts:
In the following sections, we will go through these different aspects, starting with simulation of PPS-data.
The function simulate_pps_fast can be used to generate
PPS data. This functions simulates a PPS on the basis of a given
prevalence P using a vector of probabilities
dist.X.loi for the values 1:length(dist.X.loi) of \(X_{loi}\). It directly samples the time of
infection up to date based on dist.X.loi. Optionally, the
length of stay is also sampled independently using
dist.X.los which is in the same format as
dist.X.loi. The sample is generated by treating the
marginal distributions of length of stay and length of infection as
independent by assumption. Because of this non-joint sampling rows
should not be interpreted as individual patients.
example.dist <- create_dist_vec(function(x) dpois(x-1, 7), max.dist = 70)
example.dist.los <- create_dist_vec(function(x) dpois(x-1, lambda = 12),
max.dist = 70)
data.pps.fast <- simulate_pps_fast(n.sample=5000,
P=0.05,
dist.X.loi = example.dist,
dist.X.los = example.dist.los)
head(data.pps.fast)## # A tibble: 6 × 5
## A.loi L.loi A.los L.los patient.type
## <dbl> <dbl> <int> <int> <dbl>
## 1 0 0 11 12 1
## 2 0 0 12 20 1
## 3 0 0 10 11 1
## 4 0 0 2 20 1
## 5 0 0 13 15 1
## 6 0 0 14 14 1
Values of zero for A.loi and L.loi indicate
absence of a HAI.
The incidence rate per patient day \(I\) and the expected length of infection in
the whole population \(x_{loi}\) for a
given distribution of \(X_{loi}\) and
given \(P\) can be calculated with
simulate_incidence_stats_fast by supplying a prevalence
P and a vector of probabilities dist.X.loi for
\(X_{loi}\). Optionally one can also
calculate \(I_{pp}\) and \(x_{los}\) if one supplies a vector of
probabilites dist.X.los for \(X_{los}\).
data.fast.inc.theo <- simulate_incidence_stats_fast(P=0.05,
dist.X.loi = example.dist,
dist.X.los = example.dist.los)
data.fast.inc.theo## $x.loi
## [1] 8
##
## $x.los
## [1] 13
##
## $I
## [1] 0.006578947
##
## $I.pp
## [1] 0.08125
While the above method of simulation is fast and efficient and is useful for larger simulation studies, it is useful to have a more explicit simulation technique which samples from the joint distribution of \(X_{los}\) and \(X_{loi}\) and gives more control over subpopulations of patients.
The setup of this simulation model is described in the following.
We assume the following setup. Patients arrive sequentially at a
hospital X. A hospital is a named list with the following
named elements:
inc.factor which modifies the risk of
nosocomial infections for all types of patients,patient.list characterized
below,pat.dist .A patient.type is a list with the following named
elements
dist.X.los of probabilities for the values
1:length(dist.X.los) of \(X_{los}\).,dist.X.loi of probabilities for the values
1:length(dist.X.loi) of \(X_{loi}\).,I.p for
this type of patient.The base-value of the length of stay is additive with the possible length of a nosocomial infection. Clustering of infections is not explicitly modelled.
As an example we define a hospital with two different patient types.
pat.1 <- list(dist.X.los =
create_dist_vec(function(x) dpois(x-1, lambda = 12),
70),
I.p = 0.008,
dist.X.loi =
create_dist_vec(function(x) dpois(x-1, lambda = 10),
70))
pat.2 <- list(dist.X.los =
create_dist_vec(function(x) dpois(x-1, lambda = 10),
70),
I.p = 0.02,
dist.X.loi =
create_dist_vec(function(x) dpois(x-1, lambda = 7),
70))
patient.list <- list(pat.1, pat.2)
# define distribution of patients
pat.1.prob <- 0.4; pat.2.prob <- 0.6
pat.dist.hosp <- c(pat.1.prob, pat.2.prob)
hospital.1 <- list(inc.factor = 1,
pat.dist = pat.dist.hosp,
patient.list = patient.list)Using simulate_pps_data one can generate PPS data by
simulating the evolution of n.sample beds for
steps days.
## # A tibble: 6 × 5
## A.loi A.los L.loi L.los patient.type
## <dbl> <dbl> <dbl> <int> <int>
## 1 7 14 8 22 2
## 2 0 7 0 8 1
## 3 9 24 16 33 1
## 4 0 3 0 15 2
## 5 0 5 0 10 2
## 6 0 24 0 27 2
To get additional theoretical quantities based on the whole
population, one can use simulate_incidence_stats.
data.inc.theo <- simulate_incidence_stats(hospital.1, 365 * 1000)
# gives incidence rate I
data.inc.theo$I## [1] 0.01482022
## [1] 0.1770506
## [1] 11.94656
# average length of stay of patients who had at least one HAI during their stay
data.inc.theo$x.los.only.noso## [1] 17.63234
To use the newly proposed estimator gren presented in the
companion paper, one can use the function
calculate_I_smooth with method="gren". The
data should be supplied as a data frame with at least a
column named A.loi giving lengths of infection up to date
of PPS. Values of zero for A.loi indicate absence of a HAI.
Optionally, the data frame can also contain a column A.los
supplying lengths of stay up to PPS to estimate \(x_{los}\) with the same method as well.
## # A tibble: 1 × 8
## n n.noso P.hat I.hat I.pp.hat x.loi.hat x.los.hat method
## <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 5000 601 0.120 0.0161 0.184 8.46 13.0 gren
## [1] 0.01482022
## # A tibble: 1 × 8
## n n.noso P.hat I.hat I.pp.hat x.loi.hat x.los.hat method
## <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 5000 258 0.0516 0.00822 0.101 6.62 12.9 gren
## [1] 0.006578947
There is another variation of this estimator specified with
method = "rear". This uses the rearrangement estimator
studied in (Jankowski and Wellner 2009)
instead of the Grenander estimator as an estimator for the monotonously
decreasing distribution of \(A_{loi}\)
and \(A_{los}\). We will denote this
type of estimator by rear.
There are two helper functions to calculate confidence intervals for
the estimates of \(I_{pp}\) with the
gren estimator: One ( calculate_CI_I_pp) is based
on the typical output of calculate_I_smooth:
## # A tibble: 1 × 8
## n n.noso P.hat I.hat I.pp.hat x.loi.hat x.los.hat method
## <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 5000 258 0.0516 0.00822 0.101 6.62 12.9 gren
## # A tibble: 1 × 2
## CI.lower.Ipp CI.upper.Ipp
## <dbl> <dbl>
## 1 0.0678 0.134
The other (CI_np_bs) is based on a bootstrapping
approach which resamples from the estimates of the distributions for
\(A_{loi}\) and \(Alos\) based on the Grenander estimator. It
works with data as output by simulate_pps_data*.
## # A tibble: 1 × 2
## CI.lower.Ipp CI.upper.Ipp
## <dbl> <dbl>
## 1 0.0733 0.131
The function calculate_I_rhame can be used to calculate
the incidence with a user-supplied value x.loi.hat for the
estimated length of infection \(x_{loi}\) and an optional specification of
x.los.hat for the estimated length of stay \(x_{los}\) to get an estimate of \(I_{pp}\) too. Here we take the example of
an estimator where x.loi.hat and x.los.hat are
fixed to their theoretical values and which depends only on the estimate
of \(P\). We will call this type of
estimator rhame.theo .
calculate_I_rhame(data.pps,
x.loi.hat = data.inc.theo$x.loi,
x.los.hat = data.inc.theo$x.los,
method = "method identifier")## # A tibble: 1 × 8
## n n.noso P.hat I.hat I.pp.hat x.loi.hat x.los.hat method
## <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 5000 601 0.120 0.0158 0.187 8.66 13.5 method identifier
## [1] 0.01482022
## [1] 0.1770506
calculate_I_rhame(data.pps.fast,
x.loi.hat = data.fast.inc.theo$x.loi,
x.los.hat = data.fast.inc.theo$x.los,
method = "method identifier")## # A tibble: 1 × 8
## n n.noso P.hat I.hat I.pp.hat x.loi.hat x.los.hat method
## <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 5000 258 0.0516 0.00680 0.0839 8 13 method identifier
## [1] 0.006578947
## [1] 0.08125
As a convenience function, one can use calculate_I to
get estimates of I for a range of estimators (including the ones studied
in (Willrich et al. 2019)) based on PPS
data and the accompanying theoretical data .
The estimators are the following:
## # A tibble: 8 × 8
## n n.noso P.hat I.hat I.pp.hat x.loi.hat x.los.hat method
## <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 5000 258 0.0516 0.00822 0.101 6.62 12.9 gren
## 2 5000 258 0.0516 0.00822 0.0949 6.62 12.2 rear
## 3 5000 258 0.0516 0.0106 0.129 5.15 12.9 pps.mixed
## 4 5000 258 0.0516 0.0109 0.0722 5 7 pps.median
## 5 5000 258 0.0516 0.0108 0.0768 5.02 7.47 pps.mean
## 6 5000 258 0.0516 0.00671 0.0831 8.11 13.1 L.full
## 7 5000 258 0.0516 0.00680 0.0839 8 13 rhame.theo
## 8 5000 258 0.0516 0.00822 0.102 6.62 13.1 naive
If one wants to combine the (fast) simulation step with the
estimation step one can use generate_I_fast. This is just a
wrapper for first calling simulate_pps_fast and then
calling calculate_I.
generate_I_fast(n.sample = 10000,
P = 0.05,
dist.X.loi = example.dist,
data.theo = data.fast.inc.theo)## # A tibble: 8 × 8
## n n.noso P.hat I.hat I.pp.hat x.loi.hat x.los.hat method
## <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 10000 491 0.0491 0.00663 NA 7.79 NA gren
## 2 10000 491 0.0491 0.00673 NA 7.67 NA rear
## 3 10000 491 0.0491 0.00819 NA 6.30 NA pps.mixed
## 4 10000 491 0.0491 0.0103 NA 5 NA pps.median
## 5 10000 491 0.0491 0.0105 NA 4.94 NA pps.mean
## 6 10000 491 0.0491 0.00646 NA 7.99 NA L.full
## 7 10000 491 0.0491 0.00645 0.0798 8 13 rhame.theo
## 8 10000 491 0.0491 0.00652 NA 7.92 NA naive
The function monotone_smoother implements the
rearrangement estimator and Grenander estimator described in (Jankowski and Wellner 2009).
A.loi.smoothed <- monotone_smoother(A.loi.sample, method = "gren")
# estimated monotonously decreasing distribution
plot(A.loi.smoothed)For creating length-biased distributions there is
length_biased_dist, which takes a vector of probabilities
of a discrete positive distribution as an argument.
# geometric distribution starting in 1 and cutoff at 70 with mean at about 8.
geom.dist <- create_dist_vec(geom_dist_fct, max.dist = 70)
# calculate mean
sum(1:length(geom.dist)*geom.dist)## [1] 7.993895
To calculate the mean of the original distribution based on the
length-biased distribution one can use
length_unbiased_mean.
## [1] 7.993895