Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Unsupervised learning

Use clustering to group samples. Use PCA to reduce the number of features.

Enable the machine_learning feature. These examples also require ndarray = "0.17.2".

Prepare inputs

Pass an Array2<f64> with shape (samples, features). Training does not require targets.

Scale features when their units or ranges differ. Apply the same fitted preprocessing to new samples.

Cluster and reduce features

KMeans::new(n_clusters, max_iterations, tolerance) configures clustering. Set a random seed with with_random_state(seed) for repeatable initialization.

KMeans cluster numbers identify groups. They do not indicate rank or meaning.

DBSCAN::new(eps, min_samples) configures neighborhood radius and minimum density. DBSCAN uses -1 for noise.

DBSCAN prediction uses the nearest fitted core point within eps. Otherwise, prediction returns -1.

PCA::new(n_components) selects the output width. Fit PCA before transforming new samples.

use ndarray::array;
use rustyml::prelude::machine_learning::{DBSCAN, KMeans, PCA};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let x = array![[0.0, 0.0], [0.1, 0.1], [5.0, 5.0], [5.1, 5.1]];
    let mut kmeans = KMeans::new(2, 100, 1e-6)?.with_random_state(42);
    let labels = kmeans.fit_predict(&x)?;
    println!("same first pair: {}", labels[0] == labels[1]);
    println!("different groups: {}", labels[0] != labels[2]);
    let queries = array![[0.05, 0.05], [5.05, 5.05]];
    println!("KMeans predictions: {}", kmeans.predict(&queries)?.len());

    let mut dbscan = DBSCAN::new(0.3, 2)?;
    let labels = dbscan.fit_predict(&x)?;
    println!("DBSCAN labels: {:?}", labels.to_vec());
    let noise = dbscan.predict(&array![[20.0, 20.0]])?;
    println!("DBSCAN noise: {}", noise[0]);

    let mut pca = PCA::new(1)?;
    let reduced = pca.fit_transform(&x)?;
    println!("PCA shape: {:?}", reduced.dim());
    println!("PCA query shape: {:?}", pca.transform(&queries)?.dim());
    Ok(())
}

Output:

same first pair: true
different groups: true
KMeans predictions: 2
DBSCAN labels: [0, 0, 1, 1]
DBSCAN noise: -1
PCA shape: (4, 1)
PCA query shape: (2, 1)

Method contracts

The signatures below use owned arrays for clarity. These methods also accept compatible ndarray views.

ModelsCallSuccessful result
KMeans, DBSCAN, PCAfit(&mut self, x: &Array2<f64>)&mut Self
KMeans, DBSCANfit_predict(&mut self, x: &Array2<f64>)Array1<isize>
KMeans, DBSCANpredict(&self, x: &Array2<f64>)Array1<isize>
PCAfit_transform(&mut self, x: &Array2<f64>)Array2<f64>
PCAtransform(&self, x: &Array2<f64>)Array2<f64>

Each call returns Result<_, Error>. Cluster output contains one label per input row.

PCA output has shape (input_samples, n_components). PCA requires at least two training samples.

Choose n_components from one through min(samples, features). Choose no more KMeans clusters than training samples.

Handle errors

Use nonempty, finite inputs and valid constructor parameters. New inputs must have the fitted feature count.

Prediction and transformation require a fitted model. Otherwise, they return Error::NotFitted.

Training can report invalid inputs, numerical failures, or convergence failures. Propagate errors with ? and inspect their messages.

See Model files to save the fitted clustering model or PCA projection.