Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

datarust

Scikit-Learn Preprocessing in Rust — a modular, dependency-free machine-learning preprocessing and modeling library built on a lightweight Matrix type.

crates.io docs.rs CI License: MIT

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

let x = Matrix::new(vec![
    vec![1.0, 10.0],
    vec![2.0, 20.0],
    vec![3.0, 30.0],
    vec![4.0, 40.0],
])?;

// Standardize: (x - mean) / std (population, ddof=0)
let mut scaler = StandardScaler::new();
let standardized = scaler.fit_transform(&x)?;
}

Default build has zero external dependencies. All linear algebra (eigenvalue decomposition, covariance, Cholesky factorization, coordinate descent) is implemented in pure Rust — no system BLAS/LAPACK, no Python runtime, no GIL.


What’s included

CategoryComponents
ScalersStandardScaler, MinMaxScaler, RobustScaler, MaxAbsScaler, Normalizer (L1/L2/Max), Binarizer
DiscretizersKBinsDiscretizer (Uniform / Quantile / KMeans), Binarizer
Distribution TransformersQuantileTransformer (Uniform / Normal output), PowerTransformer (Yeo-Johnson / Box-Cox)
EncodersLabelEncoder, OneHotEncoder (+ CSR sparse output), OrdinalEncoder, TargetEncoder, FrequencyEncoder
ImputersSimpleImputer (mean / median / most_frequent / constant), KnnImputer (uniform / distance)
PolynomialPolynomialFeatures (degree, interaction_only, include_bias)
SelectionVarianceThreshold, SelectKBest (ANOVA F / Chi2 / Mutual Information)
DecompositionPCA (whiten, inverse_transform, randomized SVD), TruncatedSVD
Linear ModelsLinearRegression (Cholesky & SVD), Ridge (L2), Lasso (L1, coordinate descent, sparse)
ClassificationLogisticRegression (binary IRLS + multiclass softmax, Cholesky & SVD)
MetricsRegression: MSE/RMSE, MAE, R², max_error, explained_variance. Classification: accuracy, explicit precision/recall/F1 averaging, labeled confusion matrices, log_loss
Model Selectiontrain_test_split, KFold, StratifiedKFold, cross_val_score
PipelineSequential Pipeline (serde-serializable), ColumnTransformer (numeric + categorical)
Feature NamesFeatureNames trait on all transformers for output column names
SerializationJSON save/load via optional serde feature
ParallelismRayon-backed column operations via optional rayon feature
SparseCSR SparseMatrix type for memory-efficient one-hot output

Why datarust?

Zero dependencies by default

cargo add datarust pulls in nothing. No BLAS, no LAPACK, no numpy, no Python runtime. The default build has a completely empty dependency tree — every algorithm (Jacobi eigendecomposition, Cholesky factorization, one-sided Jacobi SVD, coordinate descent, IRLS) is pure Rust. Opt in to serde, rayon, or a tuned pure-Rust GEMM via feature flags when you need them.

Rust-native type safety

sklearn’s single duck-typed fit/transform API becomes four separate traits enforced by the type system:

You cannot accidentally pass categorical strings to a numeric scaler — the compiler catches it.

Panic-free public API

Every fallible public method returns Result<T, DatarustError>. No hidden panics on bad input, no unwrap() in the API surface.

JSON serialization (not pickle)

Fitted models serialize to plain JSON via the serde feature — human-readable, language-agnostic, and diff-friendly. No binary pickle blobs.

Measured speedups vs scikit-learn

On heterogeneous ColumnTransformer composition, categorical encoding, and numeric scaling, datarust is 1.5–620× faster than scikit-learn. See the Performance page for the full benchmark tables and methodology.


A taste: end-to-end pipeline

#![allow(unused)]
fn main() {
use datarust::compose::{ColumnTransformer, Table};
use datarust::encoder::OneHotEncoder;
use datarust::categorical_kind::CategoricalTransformerKind;
use datarust::scaler::StandardScaler;
use datarust::transformer_kind::TransformerKind;
use datarust::Matrix;

// Mixed numeric + categorical table
let numeric = Matrix::new(vec![vec![1.0, 2.0], vec![3.0, 4.0]])?;
let table = Table::new(numeric, /* categorical StrMatrix */ /* ... */ /* ) */;

// Build a column transformer: scale numeric, one-hot encode categorical
let mut ct = ColumnTransformer::new()
    .add_numeric("num", vec![0, 1], TransformerKind::StandardScaler(StandardScaler::new()));
    // .add_categorical("cat", vec![2, 3], CategoricalTransformerKind::OneHotEncoder(OneHotEncoder::new()));

let out = ct.fit_transform_to_table(&table)?;
// out.numeric and out.categorical hold the transformed columns
}

Next steps