#![warn(missing_docs)]
pub mod algos;
use crate::algos::{w_median,r_median};
use indxvec::{here,Vecops,Printing,printing::{GR,UN}};
#[derive(Default)]
pub struct Med {
pub median: f64,
pub lq: f64,
pub uq: f64,
pub mad: f64
}
impl std::fmt::Display for Med {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"median:\n\tLower Q: {}\n\tMedian: {}\n\tUpper Q: {}\n\tMad: {GR}{}{UN}",
self.lq.gr(),
self.median.gr(),
self.uq.gr(),
self.mad
)
}
}
#[derive(Default)]
pub struct MStats {
pub centre: f64,
pub dispersion: f64
}
impl std::fmt::Display for MStats {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f,"centre: {GR}{}{UN}, dispersion: {GR}{}{UN}",
self.centre, self.dispersion )
}
}
pub trait Median {
fn median(&self) -> f64;
fn mad(self,median:f64) -> f64;
fn medstats(self) -> MStats;
fn medinfo(self) -> Med;
}
impl<T> Median for &[T] where T: Copy+PartialOrd,f64:From<T> {
fn median(&self) -> f64 {
let n = self.len();
if n == 0 { panic!("{} empty vector!",here!()) };
if n < 60 { w_median(self)}
else { r_median(self)}
}
fn mad(self,med:f64) -> f64 {
let diffs:Vec<f64> = self.iter().map(|&s| ((f64::from(s)-med).abs())).collect();
diffs.as_slice().median() }
fn medstats(self) -> MStats {
let centre = self.median();
MStats { centre, dispersion: self.mad(centre) }
}
fn medinfo(self) -> Med {
let mut equals = 0_usize;
let mut posdifs:Vec<f64> = Vec::new();
let mut negdifs:Vec<f64> = Vec::new();
let med = self.median();
for &s in self {
let sf = f64::from(s);
if sf > med { posdifs.push(sf-med) }
else if sf < med { negdifs.push(med-sf) }
else { equals += 1 };
}
if equals > 1 {
let eqhalf = vec!(0.;equals/2);
let eqslice = vec!(0.;equals);
let lq = negdifs.unite_unsorted(&eqhalf).as_slice().median();
let uq = eqhalf.unite_unsorted(&posdifs).as_slice().median();
Med{ median:med,
lq:med-lq,
uq:med+uq,
mad: [negdifs,eqslice,posdifs].concat().as_slice().median()} }
else {
Med { median:med,
lq: med-negdifs.as_slice().median(),
uq: med+posdifs.as_slice().median(),
mad: [negdifs,posdifs].concat().as_slice().median()} }
}
}