model_selection_rs/scoring/
smartcore_adapter.rs1use ndarray::Array1;
10use smartcore::metrics::{ClassificationMetrics, Metrics};
11
12use super::Scorer;
13
14#[derive(Debug, Clone, Copy)]
18pub struct SmartcoreF1 {
19 pub beta: f64,
21}
22
23impl Default for SmartcoreF1 {
24 fn default() -> Self {
25 Self { beta: 1.0 }
26 }
27}
28
29impl Scorer for SmartcoreF1 {
30 fn score(&self, y_true: &Array1<f64>, y_pred: &Array1<f64>) -> f64 {
31 let t = y_true.to_vec();
34 let p = y_pred.to_vec();
35 ClassificationMetrics::<f64>::f1(self.beta).get_score(&t, &p)
36 }
37 fn name(&self) -> &str {
38 "f1"
39 }
40}
41
42#[derive(Debug, Clone, Copy, Default)]
47pub struct SmartcoreRocAuc;
48
49impl Scorer for SmartcoreRocAuc {
50 fn score(&self, y_true: &Array1<f64>, y_pred: &Array1<f64>) -> f64 {
51 let t = y_true.to_vec();
52 let p = y_pred.to_vec();
53 ClassificationMetrics::<f64>::roc_auc_score().get_score(&t, &p)
54 }
55 fn name(&self) -> &str {
56 "roc_auc"
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use ndarray::array;
64
65 #[test]
66 fn f1_perfect_prediction_is_one() {
67 let t = array![0.0, 1.0, 1.0, 0.0, 1.0];
68 let f1 = SmartcoreF1::default().score(&t, &t);
69 assert!((f1 - 1.0).abs() < 1e-9, "f1 = {f1}");
70 }
71
72 #[test]
73 fn roc_auc_perfect_ranking_is_one() {
74 let t = array![0.0, 0.0, 1.0, 1.0];
75 let scores = array![0.1, 0.2, 0.8, 0.9];
76 let auc = SmartcoreRocAuc.score(&t, &scores);
77 assert!((auc - 1.0).abs() < 1e-9, "auc = {auc}");
78 }
79
80 #[test]
81 fn matches_calling_smartcore_directly() {
82 let t = array![0.0, 1.0, 1.0, 0.0, 1.0, 0.0];
83 let p = array![0.0, 1.0, 0.0, 0.0, 1.0, 1.0];
84 let via_adapter = SmartcoreF1::default().score(&t, &p);
85 let direct = ClassificationMetrics::<f64>::f1(1.0).get_score(&t.to_vec(), &p.to_vec());
86 assert_eq!(via_adapter, direct);
87 }
88}