r2rs-stats 0.1.1

Statistics programming for Rust based on R's stats package
Documentation
// "Whatever you do, work at it with all your heart, as working for the Lord,
// not for human masters, since you know that you will receive an inheritance
// from the Lord as a reward. It is the Lord Christ you are serving."
// (Col 3:23-24)

use nalgebra::DMatrix;

pub fn linear_regression_qr(x: &DMatrix<f64>, y: &DMatrix<f64>) -> DMatrix<f64> {
    let x_r = x.clone().qr().r();
    x_r.clone().pseudo_inverse(f64::EPSILON).unwrap()
        * x_r.transpose().pseudo_inverse(f64::EPSILON).unwrap()
        * x.transpose()
        * y
}

pub fn linear_regression_sqrt_weighted(
    x: &DMatrix<f64>,
    y: &DMatrix<f64>,
    w: &DMatrix<f64>,
) -> DMatrix<f64> {
    let mut x = x.to_owned();
    let mut y = y.to_owned();
    let mut w = w.to_owned();

    if w.iter().any(|&w_i| w_i == 0.0) {
        let w_0_rows = w
            .iter()
            .enumerate()
            .filter(|(_, &w_i)| w_i == 0.0)
            .map(|(i, _)| i)
            .collect::<Vec<_>>();
        x = x.remove_rows_at(&w_0_rows);
        y = y.remove_rows_at(&w_0_rows);
        w = w.remove_rows_at(&w_0_rows);
    }

    let wts = DMatrix::from_iterator(w.shape().0, 1, w.iter().map(|w_i| w_i.sqrt()));

    let mut weighted_x = x.insert_column(0, 1.0);
    weighted_x
        .column_iter_mut()
        .for_each(|mut row| row.component_mul_assign(&wts));
    let weighted_y = y.component_mul(&wts);

    linear_regression_qr(&weighted_x, &weighted_y)
}

pub fn linear_regression_sqrt_weighted_no_intercept(
    x: &DMatrix<f64>,
    y: &DMatrix<f64>,
    w: &DMatrix<f64>,
) -> DMatrix<f64> {
    let mut x = x.to_owned();
    let mut y = y.to_owned();
    let mut w = w.to_owned();

    if w.iter().any(|&w_i| w_i == 0.0) {
        let w_0_rows = w
            .iter()
            .enumerate()
            .filter(|(_, &w_i)| w_i == 0.0)
            .map(|(i, _)| i)
            .collect::<Vec<_>>();
        x = x.remove_rows_at(&w_0_rows);
        y = y.remove_rows_at(&w_0_rows);
        w = w.remove_rows_at(&w_0_rows);
    }

    let wts = DMatrix::from_iterator(w.shape().0, 1, w.iter().map(|w_i| w_i.sqrt()));

    let mut weighted_x = x;
    weighted_x
        .column_iter_mut()
        .for_each(|mut row| row.component_mul_assign(&wts));
    let weighted_y = y.component_mul(&wts);

    linear_regression_qr(&weighted_x, &weighted_y)
}

pub fn linear_regression_weighted_no_intercept(
    x: &DMatrix<f64>,
    y: &DMatrix<f64>,
    w: &DMatrix<f64>,
) -> DMatrix<f64> {
    let mut x = x.to_owned();
    let mut y = y.to_owned();
    let mut w = w.to_owned();

    if w.iter().any(|&w_i| w_i == 0.0) {
        let w_0_rows = w
            .iter()
            .enumerate()
            .filter(|(_, &w_i)| w_i == 0.0)
            .map(|(i, _)| i)
            .collect::<Vec<_>>();
        x = x.remove_rows_at(&w_0_rows);
        y = y.remove_rows_at(&w_0_rows);
        w = w.remove_rows_at(&w_0_rows);
    }

    let mut weighted_x = x;
    weighted_x
        .column_iter_mut()
        .for_each(|mut row| row.component_mul_assign(&w));
    let weighted_y = y.component_mul(&w);

    linear_regression_qr(&weighted_x, &weighted_y)
}