Shrinkage

Multivariate regression

A multivariate Gaussian model estimates qq responses from the same design:

min⁡β0,β  ∥Y−1β0T−X~β∥F22n+Raxis(β). \min_{\beta_0,\beta}\;\frac{\|Y - \mathbf{1}\beta_0^\mathsf{T} - \widetilde X\beta\|_F^2}{2n} + R_{\mathrm{axis}}(\beta).

Here β\beta is a p×qp \times q coefficient matrix, and β0\beta_0 is a vector of qq intercepts. Use an explicit pp-feature, qq-response coefficient layout and choose which vectors the penalty sees. The loss sums over responses, so adding responses does not divide either the loss or the penalty strengths by qq.

Fit two responses

use faer::{Col, Mat};
use shrinkage::{
    AxisPenalty, CoefficientLayout, MultivariateGaussian, PenaltyAxis, Problem, ProximalGradient,
    Ridge, Termination,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let x = Mat::from_fn(4, 2, |i, j| {
        [[-1.0, 0.0], [1.0, 0.0], [0.0, -1.0], [0.0, 1.0]][i][j]
    });
    let y = [1.0, 5.0, 4.0, 2.0, -6.0, 2.0, -3.0, -1.0];
    let layout = CoefficientLayout::new(2, 2)?;
    let penalty = AxisPenalty::new(layout, PenaltyAxis::Features, Ridge::new(0.5));
    let fit = Problem::new(&x, MultivariateGaussian::new(&y, 4, 2), penalty)
        .fit_with(&ProximalGradient::<Col<f64>>::new())?;
    assert_eq!(fit.termination(), Termination::Converged);
    println!("First response: {:?}", fit.coefficients_for_response(0));
    println!("Intercepts: {:?}", fit.intercepts());
    println!("Response-major predictions: {:?}", fit.predict(&x)?);
    Ok(())
}

Observations, coefficients, and predictions store each response column contiguously. The model shares feature preprocessing and fits a separate unpenalized intercept per response.

PenaltyAxis::Features applies the vector penalty independently to every response. To select a feature jointly across responses, use PenaltyAxis::Responses with an inner Group LASSO containing one group covering all response coordinates. PenaltyAxis::All applies one complete penalty to the flattened coefficient matrix. See AxisPenalty.

Only proximal gradient currently fits this layout. Typed and runtime multivariate problems share the same iteration.