Skip to contents

Introduction

This vignette demonstrates how to use the Zresidual package to compute component-wise Z-residuals for diagnosing Bayesian hurdle models (Mullahy 1986), based on the output from the brms package in R (Bürkner 2017) can be calculated separately for the zero, count and hurdle components to reveal potential model misspecifications. The examples illustrate the practical use of these residuals for RPP (Feng, Li, and Sadeghpour 2020) diagnostics. For a detailed explanation of the methodology and theoretical foundations, please refer to the “To be updated”.

Definitions of Component-wise Z-residuals for Bayesian Hurdle Models

This section demonstrates the definiotns of component-wise posterior predictive quantities including the posterior predictive PMF, survival function, and RPP for Bayesian hurdle models. Hurdle models consist of two parts:
  • A logistic component modeling the probability of structural zeros.
  • A count component modeling positive counts using a zero-truncated distribution.

Let Ci{0,1}C_i \in \{0, 1\}, where Ci=1C_i = 1 indicates a non-zero value, and Ci=0C_i = 0 indicates a zero value for the $i^\th$ observations. If Ci=1C_i=1, the corresponding count model then operates on yi+{1,2,}y_i^+ \in \{1, 2, \dots\}, i.e., the positive counts only.

Using Bayesian estimation (e.g., via the brms package), we draw TT samples from the posterior distribution. Let θ(t)\theta^{(t)} denote the $t^\th$ posterior draw, including component-specific parameters like:
  • πio\pi^o_i : the zero porbability,
  • μi(t),ϕ(t)\mu_i^{(t)}, \phi^{(t)} : parameters for the count component.

For a given observation yiobsy_i^\text{obs}, the component-wise posterior predictive PMF and survival functions are defined below.

Hurdle Model:

pipost,πiordle(yiobs)=1Tt=1T{πio(t)if yiobs=0,(1πio(t))piUT(yiobs|θ(t))1piUT(0|θ(t))if yiobs=1,2,,0otherwise.\begin{equation} p_i^{\text{post}, \pi^o_irdle}(y_i^\text{obs}) = \frac{1}{T} \sum_{t=1}^T \begin{cases} {\pi^o_i}^{(t)} & \text{if } y_i^\text{obs} = 0, \\ (1 - {\pi^o_i}^{(t)}) \cdot\frac{p_i^\text{UT}(y_i^\text{obs} | \theta^{(t)})}{1 - p_i^\text{UT}(0 | \theta^{(t)})} & \text{if } y_i^\text{obs} =1, 2, \ldots,\\ 0 & \text{otherwise.} \end{cases} \end{equation}Sipost,πiordle(yiobs)=1Tt=1T{1if yiobs<0,1πio(t)if 0yiobs<1,(1πio(t))SiUT(yiobsθ(t))1piUT(0θ(t))if yiobs1.\begin{equation} S_i^{\text{post}, \pi^o_irdle}(y_i^\text{obs}) = \frac{1}{T} \sum_{t=1}^T \begin{cases} 1 & \text{if } y_i^\text{obs} < 0, \\ 1-{\pi^o_i}^{(t)} & \text{if } 0 \le y_i^\text{obs} < 1, \\ (1 - {\pi^o_i}^{(t)}) \cdot \frac{S_i^\text{UT}(y_i^\text{obs} \mid \theta^{(t)})}{1-p_i^\text{UT}(0 \mid \theta^{(t)})} & \text{if } y_i^\text{obs} \ge 1. \end{cases} \end{equation}

Logistic Component:

pipost,logit(ciobs)=1Tt=1T{πio(t)if ciobs=0,1πio(t)if ciobs=1,0otherwise.\begin{equation} \label{componentwise_logistic_pmf} p_i^{\text{post}, \text{logit}}(c_i^\text{obs}) = \frac{1}{T} \sum_{t=1}^T \begin{cases} {\pi^o_i}^{(t)} & \text{if } c_i^\text{obs} = 0, \\ 1 - {\pi^o_i}^{(t)} & \text{if } c_i^\text{obs} = 1,\\ 0 & \text{otherwise.} \end{cases} \end{equation}

Sipost,logit(ciobs)=1Tt=1T{1if ciobs<0,1πio(t)if 0ciobs<1,0,if ciobs1.\begin{equation} \label{componentwise_logistic_survival} S_i^{\text{post}, \text{logit}}(c_i^\text{obs}) = \frac{1}{T} \sum_{t=1}^T \begin{cases} 1 & \text{if } c_i^\text{obs} < 0, \\ 1-{\pi^o_i}^{(t)} & \text{if } 0 \le c_i^\text{obs} < 1, \\ 0, & \text{if } c_i^\text{obs} \ge 1. \end{cases} \end{equation}

Count Compoenent:

pipost,count(yi+obs)=1Tt=1T{piUT(yi+obsθ(t))1piUT(0θ(t)), for yi+obs=1,2,,0 otherwise.\begin{equation} \label{componentwise_count_pmf} p_i^{\text{post},\text{count}}({y_i^+}^\text{obs}) = \frac{1}{T} \sum_{t=1}^T \begin{cases} \frac{p_i^\text{UT}({y_i^+}^\text{obs} \mid \theta^{(t)})}{1 - p_i^\text{UT}(0 \mid \theta^{(t)})}, & \text{ for } {y_i^{+}}^\text{obs} = 1,2,\ldots,\\ 0 & \text{ otherwise.} \end{cases} \end{equation}

Sipost,count(yi+obs)=1Tt=1T{1 if yi+obs<1SiUT(yi+obsθ(t))1piUT(0θ(t)), if yi+obs1\begin{equation} \label{componentwise_count_survival} S_i^{\text{post}, \text{count}}({y_i^+}^\text{obs}) = \frac{1}{T} \sum_{t=1}^T \begin{cases} 1 & \text{ if } {y_i^+}^\text{obs} < 1 \\ \frac{S_i^\text{UT}({y_i^+}^\text{obs} \mid \theta^{(t)})}{1-p_i^\text{UT}(0 \mid \theta^{(t)})}, & \text{ if } {y_i^+}^\text{obs} \ge 1 \end{cases} \end{equation}

where piUT(.θ(t))p_i^\text{UT}(. \mid \theta^{(t)}) and SiUT(.θ(t))S_i^\text{UT}(. \mid \theta^{(t)}) denote the PMF and survival function of the untruncated count distribution, given the component-specific posterior parameters θ(t)\theta^{(t)}.

For any observed value yiobsy_i^\text{obs}, we define: rppi(yiobs|θ(t))=Si(yiobs|θ(t))+Ui×pi(yiobs|θ(t))\begin{equation} \label{eq:post_rpp}\text{rpp}_i(y_i^\text{obs} | \theta^{(t)}) = S_i(y_i^\text{obs} | \theta^{(t)}) + U_i \times p_i(y_i^\text{obs} | \theta^{(t)}) \end{equation} where UiUniform(0,1)U_i \sim \text{Uniform}(0,1). Here, yiobsy_i^\text{obs} is the observed value, which can refer to either the binary response CiC_i or the positive count yi+obs{y_i^+}^\text{obs}, depending on the component being evaluated. Then, the Z-residual of a discrete response variable is, zi=Φ1(rppi(yiobs|θ))N(0,1)\begin{equation} \label{eq:z_residual} z_i = -\Phi^{-1}(\text{rpp}_i(y_i^\text{obs}|\theta)) \sim N(0, 1) \end{equation} where Φ1(.)\Phi^{-1}(.) is the quantile function of standard normal distribution.

Installation

To be updated<>

A Simulation Example

Model fitting with brms

To demonstrate how Zresidual works with hurdle models, we first simulate data from a HNB model. This simulated dataset allows us to evaluate how well the model and residual diagnostics perform when the true data-generating process is known.

# Simulation parameters
n <- 100
beta0 <- -1   # Intercept for hurdle (zero) part
beta1 <- -1  # Coefficient for hurdle part
alpha0 <- 2  # Intercept for count part
alpha1 <- 6  # Coefficient for count part
size <- 6      # Dispersion parameter for negative binomial

x <- rnorm(n) # Predictor

# Hurdle (zero) part
logit_p <- beta0 + beta1 * x
p_zero <- exp(logit_p) / (1 + exp(logit_p))
zeros <- rbinom(n, 1, p_zero)

# Count (non-zero) part
log_mu <- alpha0 + alpha1 * x
mu <- exp(log_mu)

# Generate from zero-truncated negative binomial
prob <- size / (size + mu)
y <- (1-zeros)*distributions3::rztnbinom(n, size, prob)

# A random error variable
z <- rnorm(n, mean = 0, sd = 1)

# Final dataset
sim_data <- data.frame(y = y, x = x, z = z)

This dataset includes a single continuous predictor x, a rando error variable z and the outcome y is generated from a hurdle negative binomial process. Note that the error variable is not included in generating the y outcome variable. The hurdle (zero) part is modeled with a logistic function and the count part uses a zero-truncated negative binomial distribution.

Now, we use the brms package to fit a hurdle negative binomial model to the simulated data.

library(brms)
fit_hnb <- brm(bf(y ~ x + z, hu ~ x + z),
               data = sim_data, 
               family = hurdle_negbinomial())

The hu formula models the hurdle (zero) part, while the main formula models the count component. The family = hurdle_negbinomial() tells brms to use a hurdle model with a negative binomial distribution for the non-zero counts. We use default parameter setting on this example to fit the model.

Computing Z-residuals

In this example, we compute Z-residuals for the HNB model separately for, logistic component (zero part) and count component using zresidual_hurdle_negbinomial(). Apart from component-wise Z-residuals, the Zresidual package support overall model Z-residual calculation. The package take brms fit as an input and the type argument ("zero", "count" or "hurdle") specifies which component to use when calculating the residuals. By default, Z-residuals are computed using the Importance Sampling Cross-Validation (iscv) method based on randomized predictive p-values (RPP). Alternatively, users can choose the standard Posterior RPP method by setting method = "post".

library(hurdlemodels)
zres_hnb_post_zero <- zresidual_hurdle_negbinomial(fit_hnb, type = "zero", method = "post")
zres_hnb_post_count <- zresidual_hurdle_negbinomial(fit_hnb, type = "count", method = "post")
zres_hnb_post_hurdle <- zresidual_hurdle_negbinomial(fit_hnb, type = "hurdle", method = "post")
What the function returns

The function zresidual_hurdle_negbinomial() (and other Z-residual computing functions) returns a matrix of Z-residuals, with additional attributes. The returned object is of class zresid, which includes metadata useful for diagnostic and plotting purposes.

Return Value

A numeric matrix of dimension n × nrep, where n is the number of observations in the data and nrep is the number of randomized replicates of Z-residuals (default is 1). Each column represents a set of Z-residuals computed from a RPP, using either posterior (post) or importance sampling cross-validation (iscv) log predictive distributions.

Matrix Attributes

The returned matrix includes the following attached attributes:
  • type: The component of the hurdle model the residuals correspond to. One of “zero”, “count”, or “hurdle”.
  • zero_id: Indices of observations where the response value was 0. Useful for separating diagnostics by zero and non-zero parts.
  • log_pmf: A matrix of log predictive probabilities (log-PMF) per observation and posterior draw.
  • log_cdf: A matrix of log predictive CDF values used in computing the RPPs.
  • covariates: A data frame containing the covariates used in the model (excluding the response variable). This can be used for plotting or conditional diagnostics.
  • fitted.value: The posterior mean predicted value for each observation depending on the type.

Diagnostic Tools for Z-Residuals

Visualizing Z-residuals
The Zresidual package includes built-in plotting functions (QQ Plot, Scatter Plot, Boxplot) to help diagnose model fit using Z-residuals. These functions are designed to work directly with objects of class zresid returned by functions like zresidual_hurdle_negbinomial(). These plots help assess:
  • Whether residuals are approximately standard normal (via QQ plots),
  • Whether there are patterns in residuals across fitted values (which may suggest model misspecification),
  • Whether residuals differ across covariates (optional extensions).
par(mfrow = c(1,3))
qqnorm.zresid(zres_hnb_post_zero)
qqnorm.zresid(zres_hnb_post_count)
qqnorm.zresid(zres_hnb_post_hurdle)

par(mfrow = c(1,3))
plot.zresid(zres_hnb_post_zero, X="fitted.value", outlier.return = TRUE)
plot.zresid(zres_hnb_post_count, X="fitted.value", outlier.return = TRUE, log = "x")
plot.zresid(zres_hnb_post_hurdle, X="fitted.value", outlier.return = TRUE, log = "x")

par(mfrow = c(1,3))
boxplot.zresid(zres_hnb_post_zero, X="fitted.value")
boxplot.zresid(zres_hnb_post_count, X="fitted.value")
boxplot.zresid(zres_hnb_post_hurdle, X="fitted.value")

The diagnostic evaluations for the true model—comprising scatter plots, Q-Q plots, and boxplots of Z-residuals—demonstrate that the model adequately captures the data structure. Across the logistic, count, and hurdle components, Z-residuals are evenly scattered around zero and mostly fall within the range of -3 to 3, indicating no visible model misfit. Complementary statistical tests, including the SW test for normality, ANOVA for mean equality, and BL test for variance homogeneity, all return p-values above the 0.05 threshold. This suggests that the residuals follow a normal distribution and exhibit equal means and variances across fitted value intervals. The Q-Q plots further support normality through close alignment with the 45-degree reference line, while the boxplots confirm consistent residual means across partitions. Collectively, these diagnostics validate that the true model satisfies key distributional assumptions and that the proposed Z-residual methods are effective in detecting model adequacy.

The plotting functions in the Zresidual package are designed to be flexible and lightweight, allowing users to quickly visualize residual patterns across different components of hurdle models. These functions support all customizable arguments in base R functions such as axes, labels etc. by making them adaptable to a wide range of diagnostic workflows. The plot.zresid() function offers flexible diagnostic plotting for Z-residuals, supporting various x-axes such as index, fitted values, and covariates. Both plot.zresid() and qqnorm.zresid() automatically highlights outlier residuals that fall outside the typical (or user specified)range making it easier to identify problematic observations.

Statistical Tests

In addition to visual diagnostics, the package offers formal statistical tests to quantify deviations from normality or homogeneity of variance in Z-residuals by taking an zresid class object as an input.

Shapiro-Wilk Test for Normality (SW)

sw.test.zresid(zres_hnb_post_zero)
## [1] 0.2378934
sw.test.zresid(zres_hnb_post_count)
## [1] 0.1950657
sw.test.zresid(zres_hnb_post_hurdle)
## [1] 0.3845721

Analysis of Variance (ANOVA)

aov.test.zresid(zres_hnb_post_zero)
## [1] 0.7293346
aov.test.zresid(zres_hnb_post_count)
## [1] 0.4973731
aov.test.zresid(zres_hnb_post_hurdle)
## [1] 0.3801038

Bartlett Test (BL)

bartlett.test.zresid(zres_hnb_post_zero)
## [1] 0.5471266
bartlett.test.zresid(zres_hnb_post_count)
## 'x' must be a list with at least 2 elements. Fitted values converted to log.
## [1] 0.294551
bartlett.test.zresid(zres_hnb_post_hurdle)
## [1] 0.376077

These tests return standard htest or aov objects, making them easy to report, summarize, or integrate into automated workflows. One advantage of the visualization functions provided by the Zresidual package is that they allow users to diagnose the model both visually and using statistical tests simultaneously.

We might be also interested in comparing our HNB model to HP model taking the HP model as misspecified model .

fit_hp <- brm(bf(y ~ x + z, hu ~ x + z),
               data = sim_data, 
               family = hurdle_negbinomial(),
               prior = prior("normal(1000, 1)", class = "shape"))

This prior("normal(1000, 1)", class = "shape") is a very strong prior, tightly centered around 1000. Its practical effect is to force the shape parameter to be very large, which in turn makes the model behave almost like a Poisson distribution for the positive counts (truncated part of the hurdle model).

zres_hp_post_zero <- zresidual_hurdle_poisson(fit_hp, type = "zero", method = "post")
zres_hp_post_count <- zresidual_hurdle_poisson(fit_hp, type = "count", method = "post")
zres_hp_post_hurdle <- zresidual_hurdle_poisson(fit_hp, type = "hurdle", method = "post")
par(mfrow = c(1,3))
qqnorm.zresid(zres_hp_post_zero)
qqnorm.zresid(zres_hp_post_count)
qqnorm.zresid(zres_hp_post_hurdle)

par(mfrow = c(1,3))
plot.zresid(zres_hp_post_zero, X="fitted.value", outlier.return = TRUE)
plot.zresid(zres_hp_post_count, X="fitted.value", outlier.return = TRUE, log = "x")
plot.zresid(zres_hp_post_hurdle, X="fitted.value", outlier.return = TRUE, log = "x")

par(mfrow = c(1,3))
boxplot.zresid(zres_hp_post_zero, X="fitted.value")
boxplot.zresid(zres_hp_post_count, X="fitted.value")
boxplot.zresid(zres_hp_post_hurdle, X="fitted.value")

While the logistic component shows randomly scattered residuals and normal Q-Q alignment, supported by non-significant p-values, the count and hurdle components display clear signs of misspecification. These include banded residual patterns, heavy tails, Q-Q deviations, and significant p-values from the SW, ANOVA, and BL tests. The overall hurdle model diagnostics reflect similar issues but cannot isolate the source of misfit. This highlights a key advantage of component-wise residual analysis: it reveals that the logistic sub-model is correctly specified, while the count component is not. Such separation enables more precise identification and correction of modeling issues.

A Real-World Example

Dataset

This example illustrates the use of hurdle models to analyze healthcare utilization among older adults. The dataset is drawn from the National Medical Expenditure Survey (NMES), a nationally representative U.S. survey conducted in 1987-1988. A subsample of 4,406 individuals aged 66 and older, all enrolled in Medicare, is used. The primary response variable is the number of emergency department (ED) visits, with demographic, socioeconomic, and health-related covariates included in the analysis.

library(hurdlemodels)
data("nmes.data")
nmes.data$hlth <- NA  # Initialize with NA
nmes.data$hlth[nmes.data$exclhlth == 1] <- 2 # Set hlth = 2 for Excellent
nmes.data$hlth[nmes.data$poorhlth == 1] <- 0 # Set hlth = 0 for Poor
nmes.data$hlth[nmes.data$exclhlth == 0 & nmes.data$poorhlth == 0] <- 1 # Set hlth = 2 for Average

Fit models

The data are modeled using hurdle Poisson (HP) and hurdle negative binomial (HNB) models via the brms package in R. These models allow to examine whether the logistic and count components offer additional, more localized insights compared to those obtained from the combined hurdle model.

nmes.data1 <- nmes.data %>% select(c(emr, numchron, hlth, adldiff, school))
nmes.data2 <- nmes.data %>% select(c(emr, numchron, hlth, adldiff, school, black))
predictors_hnb <- c("numchron", "hlth", "adldiff", "school")
predictors_hp <- c("numchron", "hlth", "adldiff", "school", "black")
count_formula_hnb <- formula(paste("emr ~ ", paste(predictors_hnb, collapse=" + ")))
zero_formula_hnb <- formula(paste("hu ~ ", paste(predictors_hnb, collapse=" + ")))
count_formula_hp <- formula(paste("emr ~ ", paste(predictors_hp, collapse=" + ")))
zero_formula_hp <- formula(paste("hu ~ ", paste(predictors_hp, collapse=" + ")))
fit_hnb <- brm(bf(count_formula_hnb, zero_formula_hnb),
               data = nmes.data1,
               family = hurdle_negbinomial(link = "log", link_shape = "identity", link_hu = "logit"),
               prior = c(prior(normal(0, 5), class = "b"),
                         prior(normal(0, 5), class = "Intercept"),
                         prior(gamma(0.01, 0.01), class = "shape"),
                         prior(normal(0, 2), class = "b", dpar = "hu")),
               refresh = 0)

fit_hp <- brm(bf(count_formula_hp, zero_formula_hp),
              data = nmes.data2,
              family = hurdle_negbinomial(link = "log",
                                          link_shape = "identity",
                                          link_hu = "logit"),
              prior = prior("normal(1000, 1)", class = "shape"), refresh = 0)

Z-residual calculation

We computed Z-residuals for logistic, count and hurdle components separately using the Posterior RPP method for the NMES dataset.

zres_hnb_zero <- zresidual_hurdle_negbinomial(fit_hnb, type = "zero", method = "post", nrep = 50)
zres_hnb_count <- zresidual_hurdle_negbinomial(fit_hnb, type = "count", method = "post", nrep = 50)
zres_hnb_hurdle <- zresidual_hurdle_negbinomial(fit_hnb, type = "hurdle", method = "post", nrep = 50)

zres_hp_zero <- zresidual_hurdle_poisson(fit_hp, type = "zero", method = "post", nrep = 50)
zres_hp_count <- zresidual_hurdle_poisson(fit_hp, type = "count", method = "post", nrep = 50)
zres_hp_hurdle <- zresidual_hurdle_poisson(fit_hp, type = "hurdle", method = "post", nrep = 50)

Graphically assess model

Figure 1 displays diagnostic plots of Z-residuals for the logistic, count, and overall components of the HNB model. The residuals generally fall within the expected range (-3 to 3) without showing strong patterns, indicating a good model fit. Some outliers are present, particularly in the logistic component, as highlighted in the Q-Q plots. These outliers also appear in the overall model but are mostly driven by the logistic part. None of the residual-based statistical tests (SW, ANOVA, rBL`) yield significant p-values for any of the model components, providing no strong evidence of model misspecification. Collectively, these diagnostic results suggest that the hurdle negative binomial model offers an adequate fit to the data.

  for(i in 1:50){
    par(mfrow = c(2,3), mar = c(2, 2, 2, 2))
    qqnorm.zresid(zres_hnb_zero, irep = i, main.title = "HNB, Zero")
    qqnorm.zresid(zres_hnb_count, irep = i, main.title = "HNB, Count")
    qqnorm.zresid(zres_hnb_hurdle, irep = i, main.title = "HNB, Hurdle")

    plot.zresid(zres_hnb_zero, irep = i, X="fitted.value", outlier.return = T, main.title = NULL)
    plot.zresid(zres_hnb_count, irep = i, X="fitted.value", outlier.return = T, main.title = NULL)
    plot.zresid(zres_hnb_hurdle, irep = i, X="fitted.value", outlier.return = T, main.title = NULL)
  }
Figure 1: QQ Plots and Scatter plots of HNB for logistic, count and hurdle components.

Figure 1: QQ Plots and Scatter plots of HNB for logistic, count and hurdle components.

Figure 2 shows Z-residual diagnostics for the logistic, count, and hurdle components of the HP model. The hurdle component exhibits greater variability and a funnel shape in the residuals versus fitted plot, along with large outliers and deviations from normality in the Q-Q plot, suggesting potential misspecification. In contrast, the logistic component displays more stable residuals and better alignment with theoretical quantiles. These observations are supported by the SW test, which yields a significant p-value for the hurdle component and a non-significant result for the logistic component.

  for(i in 1:50){
    par(mfrow = c(2,3), mar = c(2, 2, 2, 2))
    qqnorm.zresid(zres_hp_zero, irep = i, main.title = "HP, Zero")
    qqnorm.zresid(zres_hp_count, irep = i, main.title = "HP, Count")
    qqnorm.zresid(zres_hp_hurdle, irep = i, main.title = "HP, Hurdle")

    plot.zresid(zres_hp_zero, irep = i, X="fitted.value", outlier.return = T, main.title = NULL)
    plot.zresid(zres_hp_count, irep = i, X="fitted.value", outlier.return = T, main.title = NULL)
    plot.zresid(zres_hp_hurdle, irep = i, X="fitted.value", outlier.return = T, main.title = NULL)
  }
QQ Plots and Scatter plots of HP for logistic, count and hurdle components.

QQ Plots and Scatter plots of HP for logistic, count and hurdle components.

Other Functions

In addition to Z-residual computation and visualization, the Zresidual package provides several utility functions to support deeper model diagnostics and probabilistic analysis including functions for calculating the logarithmic predictive p-values (post_logrpp(), iscv_logrpp()). The package also includes dedicated functions to compute the logarithmic PDFs and CDFs for supported distributions. These can be used to manually inspect likelihood components or to derive custom model evaluation metrics. The log-scale calculations offer improved numerical stability, especially when dealing with small probabilities. These tools integrate seamlessly with outputs from Bayesian models fitted using brms, maintaining compatibility and flexibility. Together, they extend the package’s functionality beyond residual analysis, supporting a comprehensive and rigorous approach to Bayesian model checking.

References

Bürkner, Paul-Christian. 2017. brms: An R Package for Bayesian Multilevel Models Using Stan.” Journal of Statistical Software 80 (1): 1–28. https://doi.org/10.18637/jss.v080.i01.
Feng, Cindy, Longhai Li, and Alireza Sadeghpour. 2020. “A Comparison of Residual Diagnosis Tools for Diagnosing Regression Models for Count Data.” BMC Medical Research Methodology 20 (1): 175. https://doi.org/10.1186/s12874-020-01055-2.
Mullahy, John. 1986. “Specification and Testing of Some Modified Count Data Models.” J. Econom. 33 (3): 341–65.