| 376 | } |
| 377 | x[0][col] = last; |
| 378 | } |
| 379 | |
| 380 | fn pack_stats(feature_names: &[String], values: &[Vec<f64>]) -> BTreeMap<String, ImportanceStats> { |
| 381 | let mut out = BTreeMap::new(); |
| 382 | for (j, name) in feature_names.iter().enumerate() { |
| 383 | let (m, s) = mean_std(&values[j]); |
| 384 | let mean = if m.is_finite() { m } else { 0.0 }; |
| 385 | let std = if s.is_finite() { s * (values[j].len() as f64).powf(-0.5) } else { 0.0 }; |
| 386 | out.insert(name.clone(), ImportanceStats { mean, std }); |
| 387 | } |
| 388 | out |
| 389 | } |
| 390 | |
| 391 | fn nan_mean_std(v: &[f64]) -> (f64, f64) { |
| 392 | let vals: Vec<f64> = v.iter().copied().filter(|x| x.is_finite()).collect(); |
| 393 | mean_std(&vals) |
| 394 | } |
| 395 | |
| 396 | fn mean_std(v: &[f64]) -> (f64, f64) { |
| 397 | if v.is_empty() { |
| 398 | return (0.0, 0.0); |
| 399 | } |
| 400 | let mean = v.iter().sum::<f64>() / v.len() as f64; |
| 401 | let var = v.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / v.len() as f64; |
| 402 | (mean, var.sqrt()) |
| 403 | } |
| 404 | |
| 405 | fn standardize(rows: &[Vec<f64>]) -> Vec<Vec<f64>> { |
| 406 | let n = rows.len(); |
| 407 | let m = rows[0].len(); |
| 408 | let mut means = vec![0.0; m]; |