Switching to ndarray
Rust’s standard library does not include built-in numerical computing tools. The ndarray
crate provides efficient n-dimensional arrays and vectorized operations.
This example uses:
Array1<f64>
for 1D arrays.mean()
,.dot()
, and.mapv()
for basic mathematical operations- Broadcasting (
x * beta
) for scalar–array multiplication
Fit function
The impl
of the fit function is shown below. As you can see, we essentially replaced Vec<f64>
by Array1<f64>
here and there. This allows us to rely on .mean
, dot
, or mapv
to perform basic linear algebra. Given that self.beta
is defined as an Option<f64>
, we return Some(num / denom)
, from which Rust can infer the type Some(f64)
.
#![allow(unused)] fn main() { impl RidgeEstimator { /// Creates a new, unfitted Ridge estimator. /// /// # Returns /// A `RidgeEstimator` with `beta` set to `None`. pub fn new() -> Self { Self { beta: None } } /// Fits the Ridge regression model using 1D input and output arrays. /// /// This function computes the coefficient `beta` using the closed-form /// solution with L2 regularization. /// /// # Arguments /// - `x`: Input features as a 1D `Array1<f64>`. /// - `y`: Target values as a 1D `Array1<f64>`. /// - `lambda2`: The regularization strength (λ²). pub fn fit(&mut self, x: &Array1<f64>, y: &Array1<f64>, lambda2: f64) { let n: usize = x.len(); assert!(n > 0); assert_eq!(x.len(), y.len(), "x and y must have the same length"); // mean returns None if the array is empty, so we need to unwrap it let x_mean: f64 = x.mean().unwrap(); let y_mean: f64 = y.mean().unwrap(); let num: f64 = (x - x_mean).dot(&(y - y_mean)); let denom: f64 = (x - x_mean).mapv(|z| z.powi(2)).sum() + lambda2 * (n as f64); self.beta = Some(num / denom); } } }