Skip to contents

Hurdle model where zero vs positive counts are modelled as separate processes.

$$P(Y = 0) = 1 - \theta$$ $$P(Y = y | Y > 0) = P_{NB}^+(y), \quad y > 0$$

where \(\theta\) is the probability of a positive count and \(P_{NB}^+\) is the truncated-at-zero negative binomial.

Usage

ratiod_hurdle_negbin(
  link_num = "log",
  link_denom = "log",
  link_hurdle = "logit",
  denom_family = "negbin"
)

Arguments

Link function for count mean (default: "log")

Link function for denominator mean (default: "log")

Link function for hurdle probability (default: "logit")

denom_family

Denominator distribution: "negbin" (default) or "fixed"

Value

A ratiod_family object with hurdle structure

Details

The hurdle model differs from zero-inflation in interpretation:

Zero-inflated: Zeros come from two sources (structural + sampling)

  • \(\pi\): probability of structural zero

  • Some zeros also come from the count process

Hurdle: Zeros are all from one source (the "hurdle" process)

  • \(1 - \theta\): probability of zero

  • All positive counts from truncated count process

Choose hurdle when zeros represent a distinct biological/sampling state.

Examples

# Create family object
fam <- ratiod_hurdle_negbin()
print(fam)
#> tulpaRatio family: hurdle_negbin_negbin 
#> [Hurdle model]
#> Hurdle negative binomial numerator, negative binomial denominator 
#> 
#> Numerator:  neg_binomial_2(log)
#> Hurdle:     bernoulli(logit)
#> Denominator: neg_binomial_2 (log) 

# Simulate hurdle data (presence/absence + abundance)
set.seed(123)
n <- 60
presence_prob <- 0.7
df <- data.frame(
  count = ifelse(runif(n) > presence_prob, 0,
                 rnbinom(n, size = 3, mu = 10) + 1),
  total = rnbinom(n, size = 5, mu = 50),
  habitat = factor(rep(c("forest", "grassland"), each = n/2)),
  site = factor(rep(1:10, each = n/10))
)

if (FALSE) { # \dontrun{
# Fit model (not run - hurdle models require specialized backend support)
fit <- tratio(
  count | total ~ habitat + (1 | site),
  data = df,
  family = ratiod_hurdle_negbin(),
  control = list(iter = 200, warmup = 100, chains = 1)
)
} # }