Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Core Concepts

Understanding seven concepts unlocks the entire crate.

1. Matrix — the data container

All numeric data flows through Matrix: a row-major dense matrix backed by a single contiguous Vec<f64> buffer. The flat layout keeps every numeric hot loop cache-friendly and auto-vectorizable.

#![allow(unused)]
fn main() {
use datarust::Matrix;

let m = Matrix::new(vec![
    vec![1.0, 2.0, 3.0],
    vec![4.0, 5.0, 6.0],
])?;
assert_eq!(m.nrows(), 2);
assert_eq!(m.ncols(), 3);
assert_eq!(m.get(0, 1), 2.0);
}

Companion types:

  • StrMatrix — categorical string input for encoders.
  • SparseMatrix — CSR format for memory-efficient one-hot output.

2. The Transformer trait

All numeric transformers implement Transformer:

#![allow(unused)]
fn main() {
pub trait Transformer {
    fn name(&self) -> &'static str;
    fn fit(&mut self, x: &Matrix) -> Result<()>;
    fn transform(&self, x: &Matrix) -> Result<Matrix>;
    fn fit_transform(&mut self, x: &Matrix) -> Result<Matrix>; // default: fit + transform
    fn inverse_transform(&self, _x: &Matrix) -> Result<Matrix>; // optional
    fn is_fitted(&self) -> bool;
}
}
  • fit learns parameters from training data (takes &mut self).
  • transform applies the learned transformation (takes &self).
  • fit_transform is a convenience that calls both.
  • inverse_transform reverses the transformation where supported.

3. Supervised estimator traits

Regression and classification estimators implement Predictor:

#![allow(unused)]
fn main() {
pub trait Predictor: Estimator {
    fn fit(&mut self, x: &Matrix, y: &[f64]) -> Result<()>;
    fn predict(&self, x: &Matrix) -> Result<Vec<f64>>;
    fn fit_predict(&mut self, x: &Matrix, y: &[f64]) -> Result<Vec<f64>>; // default
    fn is_fitted(&self) -> bool;
}
}
  • LinearRegression, Ridge, Lassopredict returns continuous predictions.
  • LogisticRegression — implements Classifier; predict returns the original hard labels used during fitting. predict_proba returns one column per class in classes() order.

4. The Clusterer trait (unsupervised)

Clustering estimators implement Clusterer — the unsupervised counterpart to Predictor. fit takes only X (no target y), and predict returns cluster indices as Vec<usize> rather than regression targets or class labels:

#![allow(unused)]
fn main() {
pub trait Clusterer: Estimator {
    fn fit(&mut self, x: &Matrix) -> Result<()>;
    fn predict(&self, x: &Matrix) -> Result<Vec<usize>>;
    fn fit_predict(&mut self, x: &Matrix) -> Result<Vec<usize>>; // default
    fn fit_transform(&mut self, x: &Matrix) -> Result<Matrix>;   // default: one-hot labels
    fn n_clusters(&self) -> usize;
    fn is_fitted(&self) -> bool;
}
}
  • KMeansfit_predict returns one cluster index per row; cluster_centers() exposes the learned centroids and inertia() the minimized within-cluster sum of squares.

5. The Params trait (hyperparameter introspection)

Estimators whose hyperparameters should be searchable implement the opt-in Params trait:

#![allow(unused)]
fn main() {
pub trait Params {
    fn get_params(&self) -> Vec<(&'static str, ParamValue)>;
    fn set_params(&mut self, name: &str, value: ParamValue) -> Result<()>;
}
}

KMeans (n_clusters, max_iter, tol, n_init) and LogisticRegression (max_iter, tol, fit_intercept) implement it. Not every estimator needs Params — only those whose hyperparameters should be tuned by an automated search (the foundation for future GridSearchCV).

6. The categorical traits

Categorical data is kept separate at the type level:

This separation means the compiler prevents you from accidentally passing strings to a numeric scaler.

7. Error handling

Every fallible public method returns Result<T, DatarustError>. No hidden panics on bad input. The error variants are ML-domain-specific:

#![allow(unused)]
fn main() {
pub enum DatarustError {
    NotFitted(String),
    InvalidInput(String),
    ShapeMismatch { expected: String, actual: String },
    EmptyInput(String),
    InvalidConfig(String),
    Singular(String),       // e.g. rank-deficient matrix in Cholesky
    UnknownCategory(String),
    // ...
}
}

Typical usage:

#![allow(unused)]
fn main() {
match scaler.transform(&x) {
    Ok(out) => { /* use out */ }
    Err(DatarustError::NotFitted(name)) => eprintln!("call fit() first on {name}"),
    Err(DatarustError::ShapeMismatch { expected, actual }) => eprintln!("{expected} vs {actual}"),
    Err(e) => eprintln!("error: {e}"),
}
}