kernel-density-estimation 0.1.0

Kernel Density Estimation in Rust
Documentation
#[cfg(feature = "f64")]
pub(crate) type Float = f64;

#[cfg(not(feature = "f64"))]
pub(crate) type Float = f32;

pub(crate) fn variance(data: &[Float]) -> Float {
    let n = data.len() as Float;
    let mean = data.iter().sum::<Float>() / n;
    let squares_sum = data.iter().map(|x| (x - mean).powi(2)).sum::<Float>();
    squares_sum / (n - 1.0)
}

pub(crate) fn quantile(data: &[Float], tau: Float) -> Float {
    assert!((0.0..=1.0).contains(&tau));
    let mut data = data.to_owned();
    data.sort_by(|a, b| a.partial_cmp(b).unwrap());
    let n = data.len() as Float;
    let index = Float::round(tau * (n + 1.0)) as usize;
    data[index - 1]
}

pub(crate) fn interquartile_range(data: &[Float]) -> Float {
    quantile(data, 0.75) - quantile(data, 0.25)
}

pub(crate) fn cumsum(data: &[Float]) -> Vec<Float> {
    (0..data.len())
        .into_iter()
        .map(|i| data[..i + 1].iter().sum())
        .collect()
}

#[cfg(test)]
mod tests {
    use approx::*;

    use super::{cumsum, interquartile_range, quantile, variance};

    #[test]
    fn test_variance() {
        let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let res = variance(&data);
        assert_relative_eq!(res, 2.5);
    }

    #[test]
    fn test_quantile() {
        let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let res = quantile(&data, 0.5);
        assert_relative_eq!(res, 3.0);
    }

    #[test]
    fn test_interquartile_range() {
        let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let res = interquartile_range(&data);
        assert_relative_eq!(res, 3.0);
    }

    #[test]
    fn test_cumsum() {
        let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let res = cumsum(&data);
        let target = vec![1.0, 3.0, 6.0, 10.0, 15.0];
        assert_eq!(res, target);
    }
}