简体中文 | English
dataset-ml
dataset-ml provides ready-to-use loaders for classic machine learning datasets, built on dataset-core.
Overview
dataset-ml includes loaders for classic ML datasets. Each loader:
- Downloads the source file on first access with
ureq, and retries transient network failures. - Verifies a pinned SHA-256 hash to detect corruption or upstream changes.
- Parses the source into a
Table: one named, typed column per source column. - Caches the parsed
Tablein memory usingdataset_core::Dataset<T, E>. Later accesses return a&reference with zero I/O.
Each module is also a complete reference implementation of the pattern for wrapping Dataset<T, E> for a concrete data source.
Two modules apply to every dataset rather than to one of them:
preprocessing: seeded train/test and k-fold splits (plain or class-stratified), feature scaling, one-hot encoding, and label encoding.traits: theMlDatasettrait every loader implements, for code written generically over "some dataset".
Installation
[]
= "0.5"
Feature flags
| Feature | Default | What it enables |
|---|---|---|
dataset |
yes | The dataset module and its loaders, the crate-root re-export of every loader struct |
preprocessing |
yes | The preprocessing module: seeded splits, feature scaling, one-hot encoding, and label encoding |
The table and traits modules are always available, whichever features you pick. They hold Table and MlDataset. You can write a loader of your own against the same interface with both features off.
To take only what you need, turn the default off:
[]
= { = "0.5", = false, = ["dataset"] }
With dataset off, the only direct dependencies left are dataset-core and ndarray.
Datasets
See the dataset overview on docs.rs for the full list. It shows the sample count, feature count, and task type of every dataset.
Usage
use Iris;
Every dataset struct exposes the same six methods, whatever it holds:
new(storage_dir): create instance (no I/O). Some datasets addnew_test/new_all/new_fullfor their subsetsdata(): reference to the parsedTableget_data()/get_data_mut(): borrow the cachedTablewithout loadinginto_data()/take_data(): move the ownedTableout, with no clone
The Table
Every loader returns a Table: one Column per source column, each with its own name and its values
in the type the source uses.
Table::new checks its columns, so a loader cannot hand you misaligned data:
- the table holds at least one column
- every column holds the same number of samples
- no two columns share a name
ColumnData |
What one column holds |
|---|---|
Numeric |
one f64 per sample. A missing value is NaN |
Integer |
one i64 per sample |
String |
one String per sample, spelled as the source spells it |
Bytes |
one fixed-width row of u8 per sample, such as the pixels of an image |
Each loader names its columns in associated constants. FEATURE_NAMES lists the columns the source designates as the model inputs, and TARGET names the label column. A source that designates more than one label column uses TARGET_NAMES in place of TARGET. A dataset without a label has neither constant. You reach every other column by its name.
use Iris;
A String column has no numeric reading, so numeric_matrix returns an error if you name one. numeric_matrix allocates on every call, so call it once and keep the result.
The MlDataset trait
Every loader implements dataset_ml::traits::MlDataset, which covers the container operations that are the same whatever the loader parses into. This lets you write a function over "some dataset" instead of one concrete struct:
use MlDataset;
use ;
| Method | Description |
|---|---|
load() / load_mut() |
Load if needed, then borrow the parsed data (load_mut for in-place edits) |
peek() |
Borrow the parsed data without triggering a load |
unload() |
Move the parsed data out, leaving the loader reusable |
n_samples() |
Sample count, uniform whatever shape a loader parses into |
is_loaded() / storage_dir() |
Inspect the loader without touching the data |
invalidate() |
Drop the in-memory cache to free the memory a large dataset holds |
The trait's names deliberately differ from the inherent data() / get_data() / take_data(). This way, neither set ever shadows the other. Both are always available and always agree.
Preprocessing
dataset_ml::preprocessing turns what the loaders return into what a model consumes. Everything is deterministic given a seed and needs no extra crates.
use ;
use Iris;
use Axis;
| Function | Purpose |
|---|---|
train_test_split(n, ratio, seed) |
Shuffled train/test row indices |
stratified_split(labels, ratio, seed) |
The same, but each class keeps its proportion. Use it for imbalanced datasets |
k_fold_indices(n, k, seed) |
k (train, validation) index pairs. Each sample appears in validation once |
shuffled_indices(n, seed) |
A deterministic permutation of 0..n |
standardize / min_max_scale |
Per-column scaling, returning the fitted Scaler |
apply_scaler(features, &scaler) |
Replay a fitted scaler on new data, without refitting |
one_hot_encode(categorical, names) |
Expand the categorical Array2<String> into indicator columns |
label_encode(labels) / class_counts |
Map labels to 0..n_classes codes and count samples per class |
The splitting functions return row indices, not arrays, because a sample spans every column of the table. One index list keeps every sample aligned across them. To get arrays, use ndarray's select(Axis(0), &indices). The scalers compute their statistics over the finite values of each column. As a result, the NaN that marks a missing value in Titanic, PalmerPenguins, and HeartDisease stays missing. It does not skew the column's statistics.
Performance Considerations
- First access: downloads the file (if not on disk), validates SHA-256, parses, caches in memory.
- Later accesses: return a reference to the cached data, with zero allocation and zero I/O.
numeric_matrix(): allocates a new matrix out of the columns you name. Call it once and keep the result.take_data()/into_data(): move the ownedTableout with no clone.get_data_mut()edits it in place.- Offline: after the initial download, datasets stay on disk. Later runs need no network access.
License
This project uses the MIT License. See LICENSE for details.
Author
SomeB1oody: stanyin64@gmail.com