A simulated longitudinal (panel) dataset of chronic obstructive pulmonary
disease (COPD) patients followed over five clinic visits, used
throughout this package's examples and vignettes. It is entirely
synthetic (not real patient data), generated to have a realistic panel
structure (time-invariant baseline covariates plus individual-level
frailties or random intercepts). Because every data-generating value is
known (see Details), it is the dataset on which students can check that
an estimator recovers the truth before using it on the real panels
shipped with the package (docvisits, meps, medicaid,
healthspend, cigar). The generating code is in data-raw/copd.R
in the package's GitHub repository.
Format
A data frame with 300 rows (60 patients x 5 visits) and 16 columns;
the panel index is c("id", "visit"):
- id
integer patient identifier (1-60), the panel individual index
- visit
integer visit number (1-5), the panel time index
- treatment
integer treatment arm, time-invariant (0 = control, 1 = active)
- age
numeric patient age in whole years at baseline, time-invariant
- smoker
integer current-smoker indicator, time-invariant (0/1)
- bmi
numeric body mass index (kg/m^2) at baseline, one decimal, time-invariant; not used to generate the outcomes
- crp
numeric C-reactive protein (mg/L) measured at each visit, one decimal and at least 0.1; the one time-varying covariate, needed for fixed-effects ("within") fits to have something left to estimate after demeaning
- fev1
numeric forced expiratory volume in 1 second (litres), two decimals and at least 0.5; a continuous lung-function outcome, one value per visit
- exacerbations
integer number of COPD exacerbations since the previous visit; a count outcome, one value per visit
- hospitalized
integer indicator (0/1) of a hospital admission in the interval since the previous visit; a binary outcome, one value per visit
- clinic
integer clinic (1-6) treating the patient, time-invariant; 10 patients per clinic
- adopt
integer visit at which the patient's clinic adopted the care-management programme (3 or 4), 0 if the clinic never adopted; the
treatcolumn forattgt(),etwfe()andeventstudy()- programme
integer indicator (0/1) that the programme is in place at this visit (
adopt > 0andvisit >= adopt)- cost
numeric outpatient plus inpatient cost (euros, two decimals) since the previous visit; 28.7 percent zeros and a right-skewed positive part
- adherence
numeric proportion of prescribed inhaler doses taken since the previous visit, in (0, 1), three decimals
- symptoms
ordered factor of symptom severity at the visit: none < mild < moderate < severe
Details
The first ten columns (id to hospitalized) are unchanged from
earlier releases. The last six (clinic to symptoms) add health
economics outcomes and were generated afterwards in a separate random
number stream, so the clinical columns did not change.
Data-generating values (patient random intercepts are normal with mean
zero and are independent of the covariates; visit enters linearly).
exacerbations: Poisson with meanf_i exp(0.4 - 0.35 treatment + 0.02 (age - 65) + 0.3 smoker + 0.05 crp), with a gamma frailtyf_iof mean 1 and variance 0.25.hospitalized: logit with index-1.5 - 0.6 treatment + 0.03 (age - 65) + 0.5 smoker + 0.08 crp + r_i,sd(r_i) = 0.4.fev1:3.2 - 0.02 (age - 65) - 0.25 smoker + 0.15 treatment - 0.03 crp + r_i + e,sd(e) = 0.2(samer_i).cost, any cost: probit with index-0.6 + 0.4 exacerbations + 1.5 hospitalized + 0.3 smoker - 0.2 treatment + 0.05 crp + a_i,sd(a_i) = 0.5.cost, positive part: lognormal, `log(cost) = 5.8 + 0.1 exacerbations0.7 hospitalized + 0.25 smoker - 0.2 treatment + 0.04 crp + 0.05 visit
0.5 programme + c_k + b_i + e
, withsd(b_i) = 0.4,corr(a_i, b_i) = 0.5,sd(e) = 0.4and clinic effectsc_k = (0.20, 0.10, 0.15, 0.00, -0.10, -0.15)for clinics 1 to 6. The programme therefore lowers expected cost among users by1 - exp(-0.5)`, about 39 percent, without changing the probability of any cost. Clinics 1 and 2 adopt at visit 3, clinics 3 and 4 at visit 4, clinics 5 and 6 never; adopting clinics have higher baseline costs (selection on levels) but parallel trends hold. Because both potential costs were simulated from the same draws, the sample average effect on the treated rows is known: about -406.0 euros per visit interval (100 treated patient-visits).
adherence: beta with precision 25 and logit mean0.8 + 0.6 treatment - 0.5 smoker - 0.08 visit + v_i,sd(v_i) = 0.3.symptoms: ordered logit with latent index0.5 smoker - 0.6 treatment + 0.25 crp + w_i,sd(w_i) = 0.8, and cut points 0.5, 2.0 and 3.5.
Random-effects (conditional) estimators target these values; pooled
nonlinear fits estimate population-averaged coefficients, which are
attenuated for the binary, ordered and beta outcomes. With only 60
patients the estimates are noisy: data-raw/copd.R also refits the
correctly specified models on a 6,000-patient panel drawn from the same
design and checks that they land close to these values.
Teaching use
Lung function and inflammation (
fev1oncrp): pooled, within, between and random effects, CRE andpanhausman().Exacerbation counts:
family = "poisson"or"negbin",panhurdle(),panfmm().Hospital admission:
family = "binomial"or"probit", withdynamic = TRUEfor state dependence.What drives outpatient and inpatient cost?
twopart()(probit plus lognormal or gamma,correlated = TRUE),family = "gamma"on positive costs,family = "tobit",panqr()for cost quantiles.Did the care-management programme lower costs?
attgt(),etwfe(),eventstudy()withtreat = "adopt", against the known effect above.Adherence (
family = "beta") and symptom severity (family = "ologit", within = fixed-effects ordered logit).
Examples
data(copd)
str(copd)
#> 'data.frame': 300 obs. of 16 variables:
#> $ id : int 1 1 1 1 1 2 2 2 2 2 ...
#> $ visit : int 1 2 3 4 5 1 2 3 4 5 ...
#> $ treatment : int 1 1 1 1 1 1 1 1 1 1 ...
#> $ age : num 70 70 70 70 70 64 64 64 64 64 ...
#> $ smoker : int 0 0 0 0 0 0 0 0 0 0 ...
#> $ bmi : num 28.5 28.5 28.5 28.5 28.5 24 24 24 24 24 ...
#> $ crp : num 5.9 0.1 4.1 5.1 3.3 4.2 4.4 1.4 4.9 3.7 ...
#> $ fev1 : num 2.61 3.19 2.88 3.12 2.91 2.81 3.01 3.04 2.74 2.8 ...
#> $ exacerbations: int 2 3 5 1 3 0 1 1 2 1 ...
#> $ hospitalized : int 0 0 1 0 0 0 0 0 0 1 ...
#> $ clinic : int 6 6 6 6 6 4 4 4 4 4 ...
#> $ adopt : int 0 0 0 0 0 4 4 4 4 4 ...
#> $ programme : int 0 0 0 0 0 0 0 0 1 1 ...
#> $ cost : num 386 0 717 0 455 ...
#> $ adherence : num 0.891 0.889 0.716 0.834 0.708 0.762 0.787 0.856 0.785 0.769 ...
#> $ symptoms : Ord.factor w/ 4 levels "none"<"mild"<..: 2 2 1 2 2 4 3 1 2 3 ...
mean(copd$cost == 0)
#> [1] 0.2866667
# two-part model of cost, programme effect on the positive part
# (clinic dummies absorb the clinic cost levels that differ between
# adopting and never-adopting clinics)
tp <- twopart(cost ~ exacerbations + hospitalized + smoker + treatment +
crp + visit + programme + factor(clinic),
binary_formula = ~ exacerbations + hospitalized + smoker +
treatment + crp,
data = copd, index = c("id", "visit"), positive = "lognormal")
summary(tp)
#>
#> Call:
#> twopart(formula = cost ~ exacerbations + hospitalized + smoker +
#> treatment + crp + visit + programme + factor(clinic), data = copd,
#> index = c("id", "visit"), binary_formula = ~exacerbations +
#> hospitalized + smoker + treatment + crp, positive = "lognormal")
#>
#> Estimator: two-part model (pooling)
#> n = 300 groups = 60 positive = 214 vcov: classical
#>
#> Part 1: P(y > 0), binomial probit
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -0.54237 0.31625 -1.715 0.0863 .
#> exacerbations 0.36359 0.07030 5.172 2.32e-07 ***
#> hospitalized 1.77472 0.35753 4.964 6.91e-07 ***
#> smoker 0.27834 0.19551 1.424 0.1546
#> treatment 0.13107 0.19405 0.675 0.4994
#> crp 0.01649 0.04424 0.373 0.7093
#> ---
#> Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#>
#> Part 2: E[y | y > 0], linear model for log(y)
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) 6.21068 0.17872 34.750 < 2e-16 ***
#> exacerbations 0.07996 0.02057 3.888 0.000101 ***
#> hospitalized 0.76694 0.08127 9.437 < 2e-16 ***
#> smoker 0.26218 0.08430 3.110 0.001871 **
#> treatment -0.32499 0.08399 -3.870 0.000109 ***
#> crp 0.04715 0.01932 2.440 0.014672 *
#> visit 0.03582 0.03874 0.925 0.355133
#> programme -0.51788 0.13450 -3.850 0.000118 ***
#> factor(clinic)2 -0.34519 0.13484 -2.560 0.010466 *
#> factor(clinic)3 0.01610 0.14289 0.113 0.910264
#> factor(clinic)4 -0.22703 0.14696 -1.545 0.122401
#> factor(clinic)5 -0.21778 0.16107 -1.352 0.176358
#> factor(clinic)6 -0.23223 0.15280 -1.520 0.128539
#> ---
#> Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#>
#> Retransformation (smearing): 1.158
#> Log-likelihood: -1734
#>
# staggered adoption: group-time effects of the programme on cost
att <- attgt(cost ~ 1, data = copd, index = c("id", "visit"),
treat = "adopt", control = "notyet")
summary(att)
#>
#> Callaway and Sant'Anna group-time ATT
#> Aggregation: overall (simple weighted average)
#> Control group: not yet treated Estimator: unconditional Individuals: 60
#>
#> ATT: -184 (SE 199.1, 95% CI -574.2 to 206.2)
#>
#> Pre-trend test (pre-treatment ATT(g, t) = 0): Chi-squared = 2.116, df = 3, p-value = 0.5487
#>