(
model: &C,
x_test: &[Vec<f64>],
y_test: &[f64],
sample_weight: Option<&[f64]>,
scoring: Scoring,
)
| 270 | } |
| 271 | |
| 272 | fn score_model<C: SimpleClassifier>( |
| 273 | model: &C, |
| 274 | x_test: &[Vec<f64>], |
| 275 | y_test: &[f64], |
| 276 | sample_weight: Option<&[f64]>, |
| 277 | scoring: Scoring, |
| 278 | ) -> f64 { |
| 279 | match scoring { |
| 280 | Scoring::Accuracy => { |
| 281 | let pred = model.predict(x_test); |
| 282 | let mut num = 0.0; |
| 283 | let mut den = 0.0; |
| 284 | for i in 0..y_test.len() { |
| 285 | let w = sample_weight.map(|sw| sw[i]).unwrap_or(1.0); |
| 286 | den += w; |
| 287 | if (pred[i] - y_test[i]).abs() < 1e-12 { |
| 288 | num += w; |
| 289 | } |
| 290 | } |
| 291 | if den > 0.0 { |
| 292 | num / den |
| 293 | } else { |
| 294 | 0.0 |
| 295 | } |
| 296 | } |
| 297 | Scoring::NegLogLoss => { |
| 298 | let probs = model.predict_proba(x_test); |
| 299 | let mut loss = 0.0; |
| 300 | let mut den = 0.0; |
| 301 | let eps = 1e-15; |
| 302 | for i in 0..y_test.len() { |
| 303 | let w = sample_weight.map(|sw| sw[i]).unwrap_or(1.0); |
| 304 | let p = probs[i].clamp(eps, 1.0 - eps); |
| 305 | loss += w * (-(y_test[i] * p.ln() + (1.0 - y_test[i]) * (1.0 - p).ln())); |
| 306 | den += w; |
| 307 | } |
| 308 | if den > 0.0 { |
| 309 | -(loss / den) |
| 310 | } else { |
| 311 | 0.0 |
| 312 | } |
| 313 | } |
| 314 | Scoring::F1 => { |
| 315 | let pred = model.predict(x_test); |
| 316 | let mut tp = 0.0; |
| 317 | let mut fp = 0.0; |
| 318 | let mut fnn = 0.0; |
| 319 | for i in 0..y_test.len() { |
| 320 | let w = sample_weight.map(|sw| sw[i]).unwrap_or(1.0); |
| 321 | let p_pos = pred[i] > 0.5; |
| 322 | let y_pos = y_test[i] > 0.5; |
| 323 | if p_pos && y_pos { |
| 324 | tp += w; |
| 325 | } else if p_pos && !y_pos { |
| 326 | fp += w; |
| 327 | } else if !p_pos && y_pos { |
| 328 | fnn += w; |
| 329 | } |
no test coverage detected