I needed this as well, thanks all for your answers. I wrote a function that takes a vector (v) and a window (w). The function iteratively applies the w at each element of v. Two constraints are checked at each iteration. First, the total number of missing values. Second, the sum of the weights (elements in the moving window) that correspond to the missing values. If any of the 2 exceeds its threshold, NAN is pushed into the resulting vector, and the function continues to the next iteration. On the contrary, if enough information is present to determine the value, a simple weighted moving average is the result. Note that the code quality can surely be improved, I'm not a programmer and this is still work in progress.
pub fn mavg(v: &[f64], w: &[f64], max_missing_v: usize, max_missing_wpct: f64) -> Vec<f64> {
let len_v: i32 = v.len() as i32;
let len_w: i32 = w.len() as i32;
assert!(
len_w < len_v,
"length of moving average window > length vector"
);
assert!(
len_w % 2 == 1,
"the moving average window has an even number of element, it should be odd"
);
let side: i32 = (len_w - 1) / 2;
let sum_all_w: f64 = w.iter().sum();
let max_missing_w: f64 = sum_all_w / 100. * (100. - max_missing_wpct);
let mut vout: Vec<f64> = Vec::with_capacity(len_v as usize);
for i in 0..len_v {
let mut missing_v = 0;
let mut missing_w = 0.;
let mut sum_ve_we = 0.;
let mut sum_we = 0.;
let mut ve: f64;
let vl = i - side;
let vr = i + side + 1;
for (j, we) in (vl..vr).zip(w.iter()) {
if (j < 0) || (j >= len_v) {
missing_v += 1;
missing_w += we;
} else {
ve = v[j as usize];
if ve.is_nan() {
missing_v += 1;
missing_w += we;
} else {
sum_ve_we += ve * we;
sum_we += we;
}
}
if missing_v > max_missing_v {
sum_ve_we = f64::NAN;
println!(
"setting to NAN: {} missing data, limit is {}",
missing_v, max_missing_v
);
break;
} else if missing_w > max_missing_w {
sum_ve_we = f64::NAN;
println!(
"setting to NAN: {} missed window weight, limit is {}",
missing_w, max_missing_w
);
break;
}
}
vout.push(sum_ve_we / sum_we);
}
vout
}