regression-diagnostics 0.2.0

Statistical diagnostics for OLS regression in Rust: VIF, condition number, adjusted R2, F/AIC/BIC, residual tests (Durbin-Watson, Breusch-Pagan, White, Jarque-Bera), influence measures (leverage, Cook's distance, DFFITS), QQ-plot data, and an R/statsmodels-style summary().
Documentation
use statrs::distribution::{ContinuousCDF, FisherSnedecor};

use super::total_sum_of_squares;
use crate::OlsFit;

/// Result of the overall-significance F-test.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FStatistic {
    /// The F statistic.
    pub statistic: f64,
    /// Numerator degrees of freedom (model): `p − 1` with an intercept.
    pub df_model: f64,
    /// Denominator degrees of freedom (residual): `n − p`.
    pub df_residual: f64,
    /// Upper-tail p-value under the F distribution.
    pub p_value: f64,
}

/// Overall model-significance F-test, comparing the fitted model against the
/// intercept-only null.
///
/// `F = (explained / df_model) / (RSS / df_residual)`, with `explained = TSS −
/// RSS`. The p-value is the upper tail of the F distribution with `(df_model,
/// df_residual)` degrees of freedom.
///
/// For a model with no non-intercept predictors (`df_model = 0`) the test is not
/// defined and the statistic/p-value are returned as `NaN`.
pub fn f_statistic(fit: &OlsFit) -> FStatistic {
    let df_model = fit.df_model();
    let df_residual = fit.df_residual();
    let tss = total_sum_of_squares(fit);
    let rss = fit.residual_sum_of_squares();
    let explained = tss - rss;

    if df_model <= 0.0 || df_residual <= 0.0 || rss <= 0.0 {
        return FStatistic {
            statistic: f64::NAN,
            df_model,
            df_residual,
            p_value: f64::NAN,
        };
    }

    let statistic = (explained / df_model) / (rss / df_residual);
    let p_value = match FisherSnedecor::new(df_model, df_residual) {
        Ok(dist) if statistic.is_finite() && statistic >= 0.0 => 1.0 - dist.cdf(statistic),
        _ => f64::NAN,
    };

    FStatistic {
        statistic,
        df_model,
        df_residual,
        p_value,
    }
}