use crate::util::dataframe_utils::check_window_size;
use polars::prelude::*;
pub fn calculate_stddev(df: &DataFrame, window: usize, column: &str) -> PolarsResult<Series> {
check_window_size(df, window, "StdDev")?;
if !df.schema().contains(column) {
return Err(PolarsError::ShapeMismatch(
format!(
"DataFrame must contain '{}' column for StdDev calculation",
column
)
.into(),
));
}
let col = df.column(column)?.f64()?;
let mut stddev_values = Vec::with_capacity(df.height());
for _ in 0..(window - 1) {
stddev_values.push(f64::NAN);
}
for i in (window - 1)..df.height() {
let mut sum = 0.0;
let mut sum_sq = 0.0;
let mut count = 0;
for j in (i - window + 1)..=i {
let val = col.get(j).unwrap_or(f64::NAN);
if !val.is_nan() {
sum += val;
sum_sq += val * val;
count += 1;
}
}
if count > 1 {
let mean = sum / count as f64;
let variance = sum_sq / count as f64 - mean * mean;
let stddev = if variance > 0.0 { variance.sqrt() } else { 0.0 };
stddev_values.push(stddev);
} else {
stddev_values.push(f64::NAN);
}
}
Ok(Series::new("stddev".into(), stddev_values))
}