| 250 | } |
| 251 | |
| 252 | pub fn fit_svr(x: &[f64], y: &[f64]) -> anyhow::Result<(Vec<f64>, Vec<f64>)> { |
| 253 | let n = x.len(); |
| 254 | if n == 0 { |
| 255 | return Ok((vec![], vec![])); |
| 256 | } |
| 257 | |
| 258 | let x_min = x.iter().fold(f64::INFINITY, |a, &b| a.min(b)); |
| 259 | let x_max = x.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)); |
| 260 | let x_norm: Vec<f64> = x.iter().map(|&xi| (xi - x_min) / (x_max - x_min)).collect(); |
| 261 | |
| 262 | let gamma = 1.0 / n as f64; |
| 263 | let mut kernel = vec![vec![0.0; n]; n]; |
| 264 | for i in 0..n { |
| 265 | for j in 0..n { |
| 266 | let diff = x_norm[i] - x_norm[j]; |
| 267 | kernel[j][i] = (-gamma * diff.powi(2)).exp(); |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | let lambda = 1.0; // Regularization parameter |
| 272 | let mut alpha = vec![0.0; n]; |
| 273 | |
| 274 | // Solve (K + λI)α = y using simple iterative method |
| 275 | for _ in 0..100 { |
| 276 | for i in 0..n { |
| 277 | let mut sum = 0.0; |
| 278 | for j in 0..n { |
| 279 | if i != j { |
| 280 | sum += kernel[j][i] * alpha[j]; |
| 281 | } |
| 282 | } |
| 283 | alpha[i] = (y[i] - sum) / (kernel[i][i] + lambda); |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | let mut y_pred = vec![0.0; n]; |
| 288 | for i in 0..n { |
| 289 | #[allow(clippy::needless_range_loop)] |
| 290 | for j in 0..n { |
| 291 | y_pred[i] += alpha[j] * kernel[i][j]; |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | let residuals: Vec<f64> = y |
| 296 | .iter() |
| 297 | .zip(y_pred.iter()) |
| 298 | .map(|(&yi, &yp)| yi - yp) |
| 299 | .collect(); |
| 300 | |
| 301 | Ok((residuals, y_pred)) |
| 302 | } |
| 303 | |
| 304 | pub fn _get_mean_bins( |
| 305 | log_means: &[f64], |