1 Ecological Motivation
Some species have environmental tolerances that are not only asymmetric but also heavy-tailed: they can persist at extreme environmental values with higher probability than a Gaussian or skew-normal model would predict. This is common for generalist species or species at range edges where occasional extreme events (heat waves, droughts) are tolerated.
The skew-t model extends the skew-normal (Model 4) by adding a degrees-of-freedom parameter that controls tail heaviness:
- As , the skew-t converges to the skew-normal.
- For small (e.g. –), the tails are substantially heavier than Gaussian.
The distribution follows the noncentral skew-t (NCST) of Branco and Dey (2001).
2 Mathematical Specification
2.1 Density
The skew-t density is derived as a scale mixture of skew-normals:
The resulting density at is:
where:
and collects the normalisation constants.
2.2 The Integral
The integral in Eq. (5) does not have a closed form for and must be evaluated numerically. The integrand has the form , where . The factor is exactly the kernel of a Gamma distribution, which makes Gauss–Laguerre quadrature the natural choice:
where are the standard Gauss–Laguerre nodes and weights (i.e. the quadrature rule for ), and in the implementation.
2.3 Why ?
The choice
was validated by parity tests against R’s
stats::integrate(rel.tol = 1e-12) for
and
. For
,
the quadrature error is below
across the tested range. For higher dimensions
(),
the exponent
increases and additional nodes may be needed; users should verify with
the parity test suite.
3 Parameterisation
The unconstrained parameter vector has length :
| Block | Length | Constraint | Meaning |
|---|---|---|---|
| Unconstrained | Niche centroid | ||
| Marginal standard deviations | |||
| Unconstrained | C-vine partial correlations | ||
| Unconstrained | Skewness parameters | ||
| 1 | via | Degrees of freedom |
The degrees-of-freedom parameter is stored as at position to enforce positivity.
4 Implementation Call Chain
optimize_niche(likelihood = "skew_t")
└─ niche_obj.cpp::create_niche_obj_ptr()
└─ loglik_niche_math_skew_t_eigen() [C++, lines 760–823]
├─ build_L_cov() [theta → mu, sigma, L_cov]
├─ alpha = Map(theta + 2*p + n_v, p) [line 776]
├─ log_r = theta[3*p + n_v]; r = exp() [lines 777–778]
├─ Mahalanobis q via forward solve [lines 785–786]
├─ z_vec = skew_z(diff, sigma, alpha) [line 789]
├─ log_det = 2 * sum log L_cov(k,k) [lines 791–793]
├─ For each i:
│ A_i = 1 + q_i/r [line 801]
│ sum_log_A += log(A_i) [line 802]
│ sum_log_I += log_skew_t_integral() [line 803]
├─ prior_penalty_value(has_alpha=true) [lines 812–813]
└─ neg_log = 0.5*n*log_det + 0.5*n*p*log_r
+ n*lgamma(r/2)
+ half_kpr*sum_log_A
- sum_log_I + penalty [lines 814–819]
4.1 The Quadrature Engine (lines 725–752)
The function log_skew_t_integral(q, z, r, k) evaluates
for a single point:
- Computes and the exponent (lines 727–728).
- Loops over
Gauss–Laguerre nodes
(lines 733–744):
- Argument to : (line 740).
- Log-term: (line 742).
- Applies the max-shift logsumexp trick across all terms (lines 746–751).
The nodes and weights are hard-coded as constexpr double
arrays (kGLNodes, kGLWeights, lines 677–715),
generated by numpy.polynomial.laguerre.laggauss(32).
4.2 R Entry Point
optimize_niche(env_occ, likelihood = "skew_t",
prior_log_sigma_lambda = 1.0,
prior_alpha_lambda = 1.0)5 Analytical Properties
| Property | Value |
|---|---|
| Parameters | |
| Special case | Skew-normal (Model 4) |
| Special case | (Non-skewed) multivariate |
| Special case | Multivariate normal (Model 1) |
| Quadrature nodes | (Gauss–Laguerre) |
| Background data | Not used |
6 When To Use
- When the species may have heavy-tailed environmental tolerances (survives extreme conditions more than a Gaussian predicts).
- As a model-selection candidate: compare AIC/BIC
with
"skew_normal"and"presence_only". If , the skew-t is not adding value over the skew-normal. - For species at range margins where extreme environmental events are ecologically relevant.
7 Limitations
Computational cost. Each log-likelihood evaluation requires evaluations per data point, making this model approximately slower than the skew-normal per evaluation.
Quadrature accuracy for . The parity tests validate for . For higher dimensions, the exponent increases, potentially requiring more nodes. Users should run the parity test suite (
test-loglik_math_cpp_parity.R) for their specific .No background correction. This is a presence-only model. For background-corrected skew-t, use
"skew_t_weighted"(Model 7).Parameter identifiability. With parameters, the model requires large . For , this is 8 parameters; for , it is 26 parameters.