---
title: "Counts, costs, bounded and censored outcomes"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Counts, costs, bounded and censored outcomes}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>",
                      fig.width = 6, fig.height = 4)
```

Health outcomes are rarely Gaussian. This vignette shows the `panglm`
models for the common cases:

| Outcome | Example | Model |
|---|---|---|
| Count | GP visits, exacerbations | Poisson or negative binomial (NB2), `family = "poisson"` or `"negbin"` |
| Count with many zeros | exacerbations | hurdle, `panhurdle()` |
| Cost with zeros, skewed when positive | annual expenditure | two-part model, `twopart()` |
| Proportion in (0, 1) | proportion of days covered | beta, `family = "beta"` |
| Ordered category | severity grade | ordered logit or probit, `orderedfamily()` |
| Censored at a bound | EQ-5D index at 1 | tobit, `tobitfamily()` |

All of them use the same `index`, `model`, `vcov`, `partialeffects()`
and `predict()` interface as the Gaussian model of
`vignette("panglm-intro")`. The examples use small samples so that the
vignette builds in seconds; the companion book uses the full data and
more quadrature nodes (`R`).

```{r setup}
library(panglm)
```

## Counts: Poisson and negative binomial

We simulate a panel of 200 patients over 5 years. The number of GP visits
depends on a chronic condition, age and sex, plus a patient effect `a`
that also raises the chance of having the condition, so pooled models
are biased. The counts are overdispersed (NB2 with size 2).

```{r count-data}
set.seed(42)
N <- 200; TT <- 5
d <- data.frame(id = rep(1:N, each = TT), year = rep(1:TT, N))
a <- rnorm(N, sd = 0.6)
d$age <- rep(round(runif(N, 50, 80)), each = TT) + d$year - 1
d$female <- rep(rbinom(N, 1, 0.5), each = TT)
d$chronic <- rbinom(N * TT, 1, plogis(-0.5 + a[d$id]))
mu <- exp(0.5 * d$chronic + 0.03 * (d$age - 65) + 0.2 * d$female + a[d$id])
d$visits <- rnbinom(N * TT, mu = mu, size = 2)
```

**Fixed-effects Poisson** is the conditional Poisson estimator of
Hausman, Hall and Griliches (1984). It is consistent for the slopes
whenever the conditional mean is correct, whatever the distribution of
the counts, so with a cluster covariance it is robust to overdispersion
and serial correlation (Wooldridge 1999). This makes it the default
choice for panel counts.

```{r fe-poisson}
fe_pois <- panglm(visits ~ chronic + age, data = d, index = c("id", "year"),
                  model = "within", family = "poisson", vcov = "cluster")
summary(fe_pois)
```

The true effect is 0.5: a chronic condition raises the visit rate by a
factor of about $\exp(0.51) = 1.66$. Sex does not vary within a patient,
so it is not in the model.

The dispersion test of Cameron and Trivedi (1990) checks whether the
variance exceeds the Poisson mean. A ratio well above 1 calls for
cluster standard errors, or for a negative binomial model when
efficiency or predicted probabilities matter.

```{r dispersion}
pandispersiontest(fe_pois)
```

**Negative binomial** fits add the NB2 variance $\mu + \mu^2 / \theta$.
The fixed-effects version uses one intercept per patient (the incidental
parameter bias is small for count models); the random-effects version
is the beta-negative-binomial model of Hausman, Hall and Griliches
(1984). Random effects keep time-invariant regressors such as sex.

```{r negbin}
fe_nb <- panglm(visits ~ chronic + age, data = d, index = c("id", "year"),
                model = "within", family = "negbin")
coef(fe_nb)
fe_nb$theta
re_nb <- panglm(visits ~ chronic + age + female, data = d,
                index = c("id", "year"), model = "random", family = "negbin")
coef(re_nb)
```

The random-effects Poisson (gamma mixing) and negative binomial models
assume that the patient effect is independent of the regressors. Here it
is not: patients with a high `a` are more often chronic, and the
random-effects NB slope of `chronic` (0.63) is above the fixed-effects
one (0.54) and the true 0.5. `cre = TRUE` removes the bias from the time-varying
regressors, as in the Gaussian case.

```{r re-poisson}
re_pois <- panglm(visits ~ chronic + age + female, data = d,
                  index = c("id", "year"), model = "random",
                  family = "poisson", cre = TRUE, vcov = "cluster")
partialeffects(re_pois)
```

The average partial effect is on the count scale: a chronic condition
adds about one visit a year on average.

## Excess zeros: the hurdle model

A hurdle model separates whether any event happens from how many events
happen once the hurdle is crossed. `panhurdle()` fits a conditional
(fixed-effects) logit for $P(y > 0)$ and a zero-truncated Poisson or
negative binomial fixed-effects model for the positive counts. Patients
whose outcome never changes between zero and positive carry no
information for the binary part and are dropped from it.

```{r hurdle}
data(copd)
hur <- panhurdle(exacerbations ~ crp, data = copd, index = c("id", "visit"))
summary(hur)
```

Within a patient, higher CRP goes with higher odds of any exacerbation
and with more exacerbations among visits with at least one, but with 60
patients neither effect is precisely estimated. Only 34 patients switch
between zero and positive counts, which is typical of short panels.

## Costs: the two-part model

Health care costs have a mass at zero and a long right tail. The
two-part model of Duan et al. (1983) fits a probit or logit for
$P(y > 0)$ on all observations and a gamma GLM with a log link for
$E(y \mid y > 0)$ on the positive costs, so that
$E(y) = P(y > 0)\, E(y \mid y > 0)$ needs no retransformation
(Manning and Mullahy 2001). `positive = "lognormal"` fits a linear model
for $\log y$ with smearing instead.

```{r cost-data}
set.seed(11)
N <- 150; TT <- 4
cst <- data.frame(id = rep(1:N, each = TT), year = rep(1:TT, N))
a <- rnorm(N, sd = 0.5)
cst$age <- rep(round(runif(N, 40, 85)), each = TT)
cst$chronic <- rbinom(N * TT, 1, plogis(-0.5 + a[cst$id]))
p_any <- pnorm(-0.3 + 0.6 * cst$chronic + 0.01 * (cst$age - 60) + a[cst$id])
mu <- exp(7 + 0.5 * cst$chronic + 0.01 * (cst$age - 60) + 0.5 * a[cst$id])
cst$cost <- ifelse(runif(N * TT) < p_any,
                   rgamma(N * TT, shape = 2, rate = 2 / mu), 0)
mean(cst$cost == 0)
```

```{r twopart}
tp <- twopart(cost ~ chronic + age, data = cst, index = c("id", "year"),
              model = "pooling", vcov = "cluster")
summary(tp)
partialeffects(tp)
```

The two parts are on different scales; `partialeffects()` combines them
into effects on expected cost. A chronic condition adds about 900
currency units a year: part of it because more patients have any cost,
part because their costs are higher. `model = "random"` adds a random
intercept to each part (and `correlated = TRUE` lets the two intercepts
correlate, for the lognormal part).

## Proportions: the beta model

Outcomes strictly between 0 and 1, such as the proportion of days
covered by a prescription, follow a beta regression with a logit link
and precision $\phi$ (Ferrari and Cribari-Neto 2004). `model = "random"`
adds a normal random intercept on the link scale.

```{r beta}
m <- plogis(1 - 0.4 * cst$chronic - 0.01 * (cst$age - 60) + a[cst$id])
cst$pdc <- rbeta(N * TT, m * 20, (1 - m) * 20)
cst$age10 <- (cst$age - 60) / 10
fit_beta <- panglm(pdc ~ chronic + age10, data = cst, model = "random",
                   index = c("id", "year"), family = "beta", R = 5)
summary(fit_beta)
partialeffects(fit_beta)
```

Patients with a chronic condition cover about 7 percentage points fewer
days. Age is rescaled to decades from 60: the beta fit is sensitive to
badly scaled regressors, so centring and scaling them is good practice.
Values of exactly 0 or 1 must be moved inside the interval first, or
modelled with a two-part model.

## Ordered outcomes

Severity grades and satisfaction scales are ordinal.
`family = orderedfamily("logit")` (or `"probit"`) fits the cumulative
link model with estimated cut points. The random-effects version adds a
normal random intercept; the fixed-effects ordered logit uses the
"blow-up and cluster" estimator of Baetschmann, Staub and Winkelmann
(2015), which is consistent for the slopes.

```{r ordered}
copd$severity <- cut(copd$exacerbations, c(-Inf, 0, 2, Inf),
                     labels = c("none", "mild", "severe"),
                     ordered_result = TRUE)
fit_ord <- panglm(severity ~ treatment + age + crp, data = copd,
                  index = c("id", "visit"), model = "random",
                  family = orderedfamily("logit"), R = 8)
summary(fit_ord)
fe_ord <- panglm(severity ~ crp, data = copd, index = c("id", "visit"),
                 model = "within", family = orderedfamily("logit"))
coef(fe_ord)
```

`partialeffects()` reports effects on the probability of each category,
and `predict(type = "prob")` gives the predicted probabilities.

```{r ordered-ape}
partialeffects(fit_ord)
head(predict(fit_ord, type = "prob"), 3)
```

Active treatment lowers the probability of the "severe" category by
about 11 percentage points and raises that of "none" by about 9
(imprecisely estimated); the effects across categories sum to zero.

## Censored outcomes: the tobit model

The EQ-5D index is capped at 1 (full health), and many patients sit at
the cap. A linear model then underestimates the effects, because the
outcome cannot rise above 1 whatever the latent health. The tobit model
(Tobin 1958) treats the observed value as a censored latent variable;
`tobitfamily(left, right)` sets the bounds. Pooled and random-effects
tobit are available; the fixed-effects tobit is inconsistent with short
panels, so use `cre = TRUE` instead.

```{r tobit-data}
set.seed(7)
N <- 80; TT <- 4
eq <- data.frame(id = rep(1:N, each = TT), wave = rep(1:TT, N))
u <- rnorm(N, sd = 0.15)
eq$age <- rep(round(runif(N, 40, 85)), each = TT)
eq$chronic <- rpois(N * TT, 0.5 + 0.02 * (eq$age - 40))
ystar <- 1.15 - 0.006 * (eq$age - 40) - 0.08 * eq$chronic + u[eq$id] +
  rnorm(N * TT, sd = 0.12)
eq$eq5d <- pmin(ystar, 1)
mean(eq$eq5d == 1)
```

```{r tobit, warning = FALSE}
fit_tob <- panglm(eq5d ~ age + chronic, data = eq, index = c("id", "wave"),
                  model = "random", family = tobitfamily(left = -Inf, right = 1),
                  R = 5)
coef(fit_tob)
c(sigma_e = fit_tob$sigma_e, sigma_u = fit_tob$sigma)
fit_lin <- panglm(eq5d ~ age + chronic, data = eq, index = c("id", "wave"),
                  model = "random")
coef(fit_lin)
```

The tobit slopes refer to latent health. The linear random-effects
slopes are attenuated by the ceiling, by about 40% here, since 43% of
the observations sit at 1. Use `partialeffects()` for effects on the
observed, censored outcome.

## References

Baetschmann, G., Staub, K. E., and Winkelmann, R. (2015). Consistent
estimation of the fixed effects ordered logit model. *Journal of the
Royal Statistical Society A*, 178, 685-703.

Cameron, A. C., and Trivedi, P. K. (1990). Regression-based tests for
overdispersion in the Poisson model. *Journal of Econometrics*, 46,
347-364.

Duan, N., Manning, W. G., Morris, C. N., and Newhouse, J. P. (1983). A
comparison of alternative models for the demand for medical care.
*Journal of Business and Economic Statistics*, 1, 115-126.

Ferrari, S., and Cribari-Neto, F. (2004). Beta regression for modelling
rates and proportions. *Journal of Applied Statistics*, 31, 799-815.

Hausman, J., Hall, B. H., and Griliches, Z. (1984). Econometric models
for count data with an application to the patents-R&D relationship.
*Econometrica*, 52, 909-938.

Manning, W. G., and Mullahy, J. (2001). Estimating log models: to
transform or not to transform? *Journal of Health Economics*, 20,
461-494.

Tobin, J. (1958). Estimation of relationships for limited dependent
variables. *Econometrica*, 26, 24-36.

Wooldridge, J. M. (1999). Distribution-free estimation of some nonlinear
panel data models. *Journal of Econometrics*, 90, 77-97.
