dataset_ml/lib.rs
1//! Built-in dataset implementations for machine learning.
2//!
3//! `dataset-ml` provides ready-to-use loaders for classic ML datasets, built on top
4//! of [`dataset_core::Dataset`]. Every loader lives in a module under `dataset`.
5//! Each one is a worked example that shows how to wrap `Dataset<T, E>` for one
6//! data source. The steps are the same each time:
7//!
8//! 1. Download from a URL.
9//! 2. Verify a SHA-256 hash.
10//! 3. Parse the source: CSV records, raw documents from an archive, or binary IDX images.
11//! 4. Return a [`Table`] of named, typed columns.
12//!
13//! # Feature flags
14//!
15//! Both features are on by default. Turn one off to leave out what you do not use.
16//!
17//! | Feature | What it enables |
18//! |-----------------|-----------------|
19//! | `dataset` | The `dataset` module and its loaders, the crate-root re-export of every loader struct, and `DOWNLOAD_RETRIES`. It adds the `csv`, `serde`, and `tempfile` dependencies. |
20//! | `preprocessing` | The `preprocessing` module: seeded train/test and k-fold splits, feature scaling, one-hot encoding, and label encoding. It adds no dependencies. |
21//!
22//! The `table` and `traits` modules are always available, whichever features you
23//! pick. They hold [`Table`] and [`MlDataset`], so you can write a loader of your
24//! own against the same interface with both features off.
25//!
26//! The `dataset` module lists every built-in dataset with its sample count,
27//! feature count, and task type.
28//!
29//! # Example
30//!
31//! This example needs the `dataset` feature.
32//!
33//! ```no_run
34//! use dataset_ml::Iris;
35//!
36//! let iris = Iris::new("./data");
37//! let table = iris.data().unwrap();
38//!
39//! // Every loader returns a `Table`. Name the columns you want in the matrix.
40//! let features = table.numeric_matrix(&Iris::FEATURE_NAMES).unwrap();
41//! assert_eq!(features.shape(), &[150, 4]);
42//!
43//! // Or reach one column by name.
44//! let species = table.column(Iris::TARGET).unwrap().as_string().unwrap();
45//! assert_eq!(species.len(), 150);
46//! ```
47//!
48//! The crate root re-exports every loader struct, so `dataset_ml::Iris` and
49//! `dataset_ml::dataset::iris::Iris` name the same type. Use whichever path reads
50//! better.
51//!
52//! All loaders are lazy. The first call downloads and parses the file. Every
53//! later call returns a cached reference. See the individual module docs for
54//! features, target, sample count, and source.
55//!
56//! # Beyond the loaders
57//!
58//! Two modules apply to every dataset here rather than to one of them:
59//!
60//! - `preprocessing`: seeded train/test and k-fold splits (plain or
61//! class-stratified), feature scaling, one-hot encoding, and label encoding. You
62//! can feed the arrays a loader returns straight to a model, without writing
63//! that glue code by hand.
64//! - [`table`]: the [`Table`] every loader returns, and the `Column` and
65//! `ColumnData` types it holds.
66//! - [`traits`]: the [`MlDataset`] trait every loader implements. It lets you
67//! write code generically over "some dataset": cache inspection and
68//! invalidation, plus a uniform `n_samples()`.
69//!
70//! This example needs the `dataset` and `preprocessing` features.
71//!
72//! ```no_run
73//! use dataset_ml::preprocessing::{standardize, stratified_split};
74//! use dataset_ml::traits::MlDataset;
75//! use dataset_ml::Iris;
76//! use ndarray::Axis;
77//!
78//! let iris = Iris::new("./data");
79//! let table = iris.data().unwrap();
80//!
81//! let features = table.numeric_matrix(&Iris::FEATURE_NAMES).unwrap();
82//! let species = table.column(Iris::TARGET).unwrap().as_string().unwrap();
83//!
84//! // Split with each species proportionally represented on both sides.
85//! let (train, test) = stratified_split(species.as_slice().unwrap(), 0.2, 42).unwrap();
86//! let (scaled_train, scaler) = standardize(&features.select(Axis(0), &train)).unwrap();
87//!
88//! assert_eq!(scaled_train.nrows(), 120);
89//! assert_eq!(iris.n_samples().unwrap(), 150); // from the `MlDataset` trait
90//! ```
91
92/// How many extra download tries every loader in this crate makes before it
93/// stops retrying.
94///
95/// The datasets are hosted on university archives and personal pages that
96/// intermittently time out or reset a connection. A run that fails for that
97/// reason is not a bug in the data. Every loader therefore fetches through
98/// [`download_to_with_retries`](dataset_core::download_to_with_retries) with
99/// this many retries. It waits 500 ms, then 1 s, between tries. A single blip
100/// does not surface as a `DownloadError`.
101///
102/// The loader returns errors that retrying cannot fix right away. A genuinely
103/// unreachable host costs at most 1.5 s of waiting before it fails.
104#[cfg(feature = "dataset")]
105pub const DOWNLOAD_RETRIES: u32 = 2;
106
107/// Every built-in dataset loader, one module per data source.
108///
109/// The modules run from [`iris`](dataset::iris), the smallest, to
110/// [`kddcup99`](dataset::kddcup99), the largest. Each one documents its features,
111/// target, sample count, and source.
112///
113/// The crate root re-exports every loader struct, so `dataset_ml::Iris` is a
114/// shorter name for `dataset_ml::dataset::iris::Iris`.
115///
116/// Needs the `dataset` feature, which is on by default.
117#[cfg(feature = "dataset")]
118pub mod dataset;
119
120/// Preprocessing helpers.
121///
122/// Turns what the loaders return into what a model consumes. It covers seeded
123/// train/test and k-fold splits (plain or class-stratified), feature scaling,
124/// one-hot encoding of the categorical matrices, and label encoding. Everything
125/// is deterministic given a seed and depends on no extra crates.
126///
127/// Needs the `preprocessing` feature, which is on by default.
128#[cfg(feature = "preprocessing")]
129pub mod preprocessing;
130
131/// The [`Table`](table::Table) every loader parses into.
132///
133/// A `Table` holds one named, typed `Column` per source column. It materializes
134/// a matrix out of the columns the caller names.
135///
136/// This module is always available, whichever features you pick.
137pub mod table;
138
139/// The [`traits::MlDataset`] trait implemented by every loader in this crate.
140///
141/// Provides the container operations that stay the same whatever a loader parses
142/// into: lazy access, cache inspection, cache invalidation, and a uniform sample
143/// count. With it, you can write code generically over "some dataset" instead of
144/// one concrete struct.
145pub mod traits;
146
147#[cfg(feature = "dataset")]
148pub use dataset::{
149 abalone::Abalone, adult::Adult, bank_marketing::BankMarketing,
150 banknote_authentication::BanknoteAuthentication,
151 bike_sharing::bike_sharing_daily::BikeSharingDaily,
152 bike_sharing::bike_sharing_hourly::BikeSharingHourly, boston_housing::BostonHousing,
153 breast_cancer::BreastCancer, california_housing::CaliforniaHousing,
154 car_evaluation::CarEvaluation, covtype::Covtype, diabetes::Diabetes, digits::Digits,
155 fashion_mnist::FashionMnist, heart_disease::HeartDisease, ionosphere::Ionosphere, iris::Iris,
156 kddcup99::Kddcup99, letter_recognition::LetterRecognition, linnerud::Linnerud, mnist::Mnist,
157 movie_review_polarity::MovieReviewPolarity, movielens_100k::MovieLens100k, mushroom::Mushroom,
158 newsgroups20::Newsgroups20, palmer_penguins::PalmerPenguins,
159 sentiment_sentences::SentimentSentences, sms_spam::SmsSpam, spambase::Spambase,
160 titanic::Titanic, wholesale_customers::WholesaleCustomers,
161 wine_quality::red_wine_quality::RedWineQuality,
162 wine_quality::white_wine_quality::WhiteWineQuality, wine_recognition::WineRecognition,
163 youtube_spam::YoutubeSpam,
164};
165pub use table::{Column, ColumnData, Table};
166pub use traits::MlDataset;