use crate::utilities::Classification;
use crate::utilities::{breaks_to_classification, to_vec_f64};
use num_traits::ToPrimitive;
pub fn get_hinge_classification<T: ToPrimitive, S: ToPrimitive>(
hinge_coefficient: S,
data: &[T],
) -> Classification {
let breaks: Vec<f64> = get_hinge_breaks(hinge_coefficient, data);
breaks_to_classification(&breaks, data)
}
pub fn get_hinge_breaks<T: ToPrimitive, S: ToPrimitive>(
hinge_coefficient: S,
data: &[T],
) -> Vec<f64> {
let hinge_coefficient = hinge_coefficient.to_f64().unwrap();
let data = to_vec_f64(data);
let num_vals = data.len();
let mut sorted_data: Vec<f64> = vec![];
for item in data.iter().take(num_vals) {
sorted_data.push(*item);
}
sorted_data.sort_by(|a, b| a.partial_cmp(b).unwrap());
let min_val = sorted_data[0];
let max_val = sorted_data[num_vals - 1];
let perc_25 = percentile(25, &sorted_data);
let perc_50 = percentile(50, &sorted_data);
let perc_75 = percentile(75, &sorted_data);
let iqr = perc_75 - perc_25;
let hinge = iqr * hinge_coefficient;
let mut breaks: Vec<f64> = vec![];
if perc_25 - hinge > min_val {
breaks.push(perc_25 - hinge);
}
breaks.push(perc_25);
breaks.push(perc_50);
breaks.push(perc_75);
if perc_75 + hinge < max_val {
breaks.push(perc_75 + hinge);
}
breaks
}
pub fn percentile(perc: u8, data: &Vec<f64>) -> f64 {
let num_vals = data.len();
let mut sorted_data: Vec<f64> = vec![];
for item in data.iter().take(num_vals) {
sorted_data.push(*item);
}
sorted_data.sort_by(|a, b| a.partial_cmp(b).unwrap());
let rank = (perc as f64 / 100.0) * (num_vals as f64 - 1.0);
if rank as usize == num_vals - 1 {
sorted_data[num_vals - 1]
} else {
let rank_int = rank as usize;
let rank_dec = rank - rank_int as f64;
sorted_data[rank_int] + rank_dec * (sorted_data[rank_int + 1] - sorted_data[rank_int])
}
}