use crate::statistics::mean;
pub fn covariance(x: &[f64], y: &[f64]) -> f64 {
assert_eq!(x.len(), y.len());
let mean_x = mean(x);
let mean_y = mean(y);
let n = x.len();
(0..n)
.into_iter()
.map(|i| (x[i] - mean_x) * (y[i] - mean_y))
.sum::<f64>()
/ n as f64
}
pub fn sample_covariance(x: &[f64], y: &[f64]) -> f64 {
assert_eq!(x.len(), y.len());
let mean_x = mean(x);
let mean_y = mean(y);
let n = x.len();
(0..n)
.into_iter()
.map(|i| (x[i] - mean_x) * (y[i] - mean_y))
.sum::<f64>()
/ (n - 1) as f64
}
pub fn sample_covariance_onepass(x: &[f64], y: &[f64]) -> f64 {
assert_eq!(x.len(), y.len());
let n = x.len();
(0..n)
.into_iter()
.map(|i| (x[i] - x[0]) * (y[i] - y[0]))
.sum::<f64>()
/ (n - 1) as f64
}
pub fn sample_covariance_online(x: &[f64], y: &[f64]) -> f64 {
assert_eq!(x.len(), y.len());
let mut meanx = 0.;
let mut meany = 0.;
let mut c = 0.;
let mut n = 0.;
for (i, j) in x.iter().zip(y.iter()) {
n += 1.;
let dx = i - meanx;
let dy = j - meany;
meanx += dx / n;
meany += dy / n;
c += dx * dy;
}
c / n
}
#[cfg(test)]
mod tests {
use super::*;
use approx_eq::assert_approx_eq;
#[test]
fn test_covariance() {
let x1: Vec<f64> = vec![-2.1, -1., 4.3];
let y1: Vec<f64> = vec![3., 1.1, 0.12];
assert_approx_eq!(covariance(&x1, &y1), -2.8573333);
assert_approx_eq!(sample_covariance(&x1, &y1), -4.286);
let x2: Vec<f64> = vec![1.1, 1.7, 2.1, 1.4, 0.2];
let y2: Vec<f64> = vec![3.0, 4.2, 4.9, 4.1, 2.5];
assert_approx_eq!(covariance(&x2, &y2), 0.532);
assert_approx_eq!(sample_covariance(&x2, &y2), 0.665);
}
}