use num_traits::{Float, FromPrimitive};
use crate::{Jackknife, Re, Variance};
use super::Statistic;
#[derive(Debug, Clone, Copy, Default)]
pub struct SEMean {
variance: Variance,
}
impl SEMean {
pub fn with_variance(variance: Variance) -> Self {
Self { variance }
}
}
impl<D, T> Statistic<D, T> for SEMean
where
D: AsRef<[T]>,
T: Float + FromPrimitive,
{
fn compute(&self, data: &D) -> T {
let slice = data.as_ref();
if slice.is_empty() {
return T::nan();
}
let var_est = self.variance.compute(data);
if var_est.is_nan() {
return T::nan();
}
let n = T::from_usize(slice.len()).expect("usize-to-float conversion failed");
let se_sq = var_est / n;
if se_sq < T::zero() {
let tolerance = T::epsilon() * T::from_f64(10.0).unwrap_or(T::one());
if se_sq >= -tolerance {
T::zero()
} else {
T::nan()
}
} else {
se_sq.sqrt()
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct SE<Stat, Resampler> {
statistic: Stat,
resampler: Resampler,
samples: usize,
}
impl<Stat> SE<Stat, Jackknife> {
pub fn jackknife(statistic: Stat) -> Self {
Self {
statistic,
resampler: Jackknife,
samples: usize::MAX,
}
}
}
impl<Stat, Resampler> SE<Stat, Resampler> {
pub fn new(statistic: Stat, resampler: Resampler, samples: usize) -> Self {
Self {
statistic,
resampler,
samples,
}
}
}
impl<D, T, Stat, Resampler> Statistic<D, T> for SE<Stat, Resampler>
where
D: AsRef<[T]>,
T: Float + FromPrimitive,
Resampler: Re<D, Item = D>,
Stat: Statistic<D, T>,
{
fn compute(&self, data: &D) -> T {
let estimates: Vec<T> = self
.resampler
.re(data)
.take(self.samples)
.map(|resample| self.statistic.compute(&resample))
.collect();
Variance::default()
.compute(&estimates)
.sqrt()
}
}