Skip to main content

sklears_python/metrics/
common.rs

1//! Common functionality for metrics Python bindings
2//!
3//! This module contains shared imports, types, and utilities used
4//! across all metric implementations.
5
6// Re-export commonly used types and traits
7pub use numpy::PyReadonlyArray1;
8pub use pyo3::exceptions::PyValueError;
9pub use pyo3::prelude::*;
10pub use scirs2_core::ndarray::Array1;
11
12/// Common error type for metric operations
13pub type MetricResult<T> = Result<T, PyValueError>;
14
15/// Validate that prediction and true value arrays have the same length
16pub fn validate_arrays_same_length(y_true: &Array1<f64>, y_pred: &Array1<f64>) -> PyResult<()> {
17    if y_true.len() != y_pred.len() {
18        return Err(PyValueError::new_err(format!(
19            "y_true and y_pred must have the same length: {} vs {}",
20            y_true.len(),
21            y_pred.len()
22        )));
23    }
24
25    if y_true.is_empty() {
26        return Err(PyValueError::new_err("y_true and y_pred must not be empty"));
27    }
28
29    Ok(())
30}
31
32/// Validate that prediction and true value arrays have the same length for integer arrays
33pub fn validate_int_arrays_same_length(y_true: &[i32], y_pred: &[i32]) -> PyResult<()> {
34    if y_true.len() != y_pred.len() {
35        return Err(PyValueError::new_err(format!(
36            "y_true and y_pred must have the same length: {} vs {}",
37            y_true.len(),
38            y_pred.len()
39        )));
40    }
41
42    if y_true.is_empty() {
43        return Err(PyValueError::new_err("y_true and y_pred must not be empty"));
44    }
45
46    Ok(())
47}
48
49/// Validate sample weights if provided
50pub fn validate_sample_weight(
51    sample_weight: &Option<Array1<f64>>,
52    n_samples: usize,
53) -> PyResult<()> {
54    if let Some(weights) = sample_weight {
55        if weights.len() != n_samples {
56            return Err(PyValueError::new_err(format!(
57                "sample_weight must have the same length as y_true: {} vs {}",
58                weights.len(),
59                n_samples
60            )));
61        }
62
63        if weights.iter().any(|&w| w < 0.0 || !w.is_finite()) {
64            return Err(PyValueError::new_err(
65                "sample_weight must contain non-negative finite values",
66            ));
67        }
68    }
69
70    Ok(())
71}
72
73/// Apply sample weights to values if provided
74pub fn apply_sample_weight(
75    values: &Array1<f64>,
76    sample_weight: &Option<Array1<f64>>,
77) -> Array1<f64> {
78    match sample_weight {
79        Some(weights) => values * weights,
80        None => values.clone(),
81    }
82}