use super::family::Family;
use super::GlmFit;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct GoodnessOfFit {
pub null_deviance: f64,
pub residual_deviance: f64,
pub df_null: f64,
pub df_residual: f64,
pub dispersion: f64,
pub mcfadden_r2: f64,
pub aic: f64,
pub bic: f64,
}
impl<F: Family> GlmFit<F> {
pub fn goodness_of_fit(&self) -> GoodnessOfFit {
let n = self.n_observations();
let p = self.n_parameters();
let y = self.response();
let mu = self.fitted_means();
let family = self.family();
let dispersion = self.dispersion();
let residual_deviance: f64 = (0..n).map(|i| family.unit_deviance(y[i], mu[i])).sum();
let ybar = y.sum() / n as f64;
let null_deviance: f64 = (0..n).map(|i| family.unit_deviance(y[i], ybar)).sum();
let ll = self.log_likelihood();
let ll_null: f64 = (0..n).map(|i| family.loglik(y[i], ybar, dispersion)).sum();
let mcfadden_r2 = if ll_null != 0.0 {
1.0 - ll / ll_null
} else {
f64::NAN
};
let k = p as f64 + if family.dispersion_known() { 0.0 } else { 1.0 };
let aic = -2.0 * ll + 2.0 * k;
let bic = -2.0 * ll + (n as f64).ln() * k;
GoodnessOfFit {
null_deviance,
residual_deviance,
df_null: (n - 1) as f64,
df_residual: (n - p) as f64,
dispersion,
mcfadden_r2,
aic,
bic,
}
}
}