Skip to main content

Module link

Module link 

Source
Expand description

Traits and utilities for link functions.

The link function $g$ maps the expected response $\mu$ to the linear predictor $\omega = \mathbf{x}^\mathsf{T}\boldsymbol{\beta}$. Each family defaults to its canonical link, but an alternative can be selected via the family’s type parameter.

Alternative links are re-exported for convenience: exp_link for exponential regression and logistic_link for logistic regression. Provide a link as the family’s type parameter:

use ndarray_glm::{Exponential, ModelBuilder, array, exp_link::Log};

fn main() -> ndarray_glm::error::RegressionResult<(), f64> {
    let data_y = array![1.0, 2.5, 0.8, 3.1];
    let data_x = array![[0.0], [1.0], [0.5], [1.5]];
    // Use the log link instead of the default negative-reciprocal canonical link.
    let model = ModelBuilder::<Exponential<Log>>::data(&data_y, &data_x).build()?;
    let fit = model.fit()?;
    Ok(())
}

A non-canonical link requires two trait implementations:

  1. Link<M> — the forward map $g(\mu) = \omega$ (Link::func) and its inverse $g^{-1}(\omega) = \mu$ (Link::func_inv).
  2. Transform — the natural-parameter transformation $\eta(\omega) = g_0(g^{-1}(\omega))$ (Transform::nat_param) and its derivative (Transform::d_nat_param), where $g_0$ is the family’s canonical link. The derivative satisfies $\eta'(\omega) = \frac{1}{g'(\mu)\,V(\mu)}$ where $V(\mu)$ is the family’s variance function evaluated at $\mu = g^{-1}(\omega)$.

Example: a square-root link $g(\mu) = \sqrt{\mu}$ for Poisson regression. The canonical link is $\log$ and $V(\mu) = \mu$, so $\eta(\omega) = \log(\omega^2) = 2\log\omega$ and $\eta'(\omega) = 2/\omega$:

use ndarray_glm::{Poisson, link::{Link, Transform}, num::Float};
use ndarray::Array1;

pub struct Sqrt;

impl Link<Poisson<Sqrt>> for Sqrt {
    fn func<F: Float>(mu: F) -> F { num_traits::Float::sqrt(mu) }
    fn func_inv<F: Float>(omega: F) -> F { omega * omega }
}

impl Transform for Sqrt {
    fn nat_param<F: Float>(lin_pred: Array1<F>) -> Array1<F> {
        lin_pred.mapv(|w| F::two() * num_traits::Float::ln(w))
    }
    fn d_nat_param<F: Float>(lin_pred: &Array1<F>) -> Array1<F> {
        lin_pred.mapv(|w| F::two() / w)
    }
}

The TestLink trait (available only in #[cfg(test)] builds) provides canned assertions that every correct link implementation should satisfy. Call them from your test module:

#[cfg(test)]
mod tests {
    use super::*;
    use ndarray_glm::link::TestLink;
    use ndarray::array;

    #[test]
    fn sqrt_link_checks() {
        // Linear-predictor values; must lie in the domain of ω (ω > 0 for sqrt).
        let lin_vals = array![0.25, 1.0, 2.0, 4.0, 9.0];

        // Verify g(g⁻¹(ω)) ≈ ω.
        Sqrt::check_closure(&lin_vals);

        // Verify g⁻¹(g(μ)) ≈ μ; values must lie in the response domain (μ > 0 for Poisson).
        Sqrt::check_closure_y(&array![0.5, 1.0, 3.0, 10.0]);

        // For non-canonical links: verify nat_param(ω) = g₀(g⁻¹(ω)).
        // Pass the *canonical* model variant as `Mc`. `Poisson` without a type parameter
        // defaults to the canonical log link.
        use ndarray_glm::Poisson;
        Sqrt::check_nat_par::<Poisson>(&lin_vals);

        // Verify d_nat_param matches the numerical derivative.
        Sqrt::check_nat_par_d(&lin_vals);
    }
}

Traits§

Canonical
The canonical transformation by definition equates the linear predictor with the natural parameter of the response distribution. Implementing this trait for a link function automatically defines the trivial transformation functions.
Link
Describes the link function $g$ that maps between the expected response $\mu$ and the linear predictor $\omega = \mathbf{x}^\mathsf{T}\boldsymbol{\beta}$:
Transform
Establishes the relationship between the linear predictor $\omega = \mathbf{x}\cdot\boldsymbol\beta$ and the natural parameter $\eta$.