use statrs::distribution::{ContinuousCDF, FisherSnedecor};
use super::total_sum_of_squares;
use crate::OlsFit;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FStatistic {
pub statistic: f64,
pub df_model: f64,
pub df_residual: f64,
pub p_value: f64,
}
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,
}
}