Skip to main content

Digits

Struct Digits 

Source
pub struct Digits { /* private fields */ }
Expand description

This struct represents the Digits dataset and loads data lazily.

You do not load the dataset until you call one of the data accessor methods. After that, the dataset caches the data for later calls.

§About Dataset

The Optical Recognition of Handwritten Digits dataset contains 8×8 grayscale images of handwritten digits. Each image is flattened into 64 pixel intensities in the range 0..=16, and the target is the digit (09) the image depicts.

This is the same data scikit-learn exposes through load_digits: it uses the test partition (optdigits.tes) of the UCI archive, with 1797 samples.

§Feature columns

The 64 features are the pixels of an 8×8 grayscale image, flattened in row-major order. Each pixel holds an integer intensity in 0..=16 stored as f64. By 0-based column index:

ColumnsAttributesUnit
0..=7row 0 pixels (pixel_0_0 .. pixel_0_7)intensity (0..=16)
8..=15row 1 pixels (pixel_1_0 .. pixel_1_7)intensity (0..=16)
16..=23row 2 pixels (pixel_2_0 .. pixel_2_7)intensity (0..=16)
24..=31row 3 pixels (pixel_3_0 .. pixel_3_7)intensity (0..=16)
32..=39row 4 pixels (pixel_4_0 .. pixel_4_7)intensity (0..=16)
40..=47row 5 pixels (pixel_5_0 .. pixel_5_7)intensity (0..=16)
48..=55row 6 pixels (pixel_6_0 .. pixel_6_7)intensity (0..=16)
56..=63row 7 pixels (pixel_7_0 .. pixel_7_7)intensity (0..=16)

§Labels

  • digit (in u8): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

See more information at https://archive.ics.uci.edu/dataset/80/optical+recognition+of+handwritten+digits

§Citation

E. Alpaydin and C. Kaynak. “Optical Recognition of Handwritten Digits,” UCI Machine Learning Repository, [Online]. Available: https://doi.org/10.24432/C50P49

§Thread Safety

This struct implements Send and Sync automatically, because every field does. This makes it safe to share across threads. The internal Dataset keeps lazy initialization thread-safe.

§Example

use dataset_ml::digits::Digits;

let download_dir = "./digits"; // the code creates the directory if it does not exist

let mut dataset = Digits::new(download_dir);
let features = dataset.features().unwrap();
let labels = dataset.labels().unwrap();

let (features, labels) = dataset.data().unwrap(); // this is also a way to get features and labels
assert_eq!(features.shape(), &[1797, 64]);
assert_eq!(labels.len(), 1797);

// `get_data()` borrows the cached arrays without reloading. `get_data_mut()`
// edits them in place: no clone, no reload, and the change stays cached.
// Prefer this over cloning with `.to_owned()` when you only need to tweak
// values.
if let Some((features, labels)) = dataset.get_data_mut() {
    features[[0, 0]] = 5.0;
    labels[0] = 7;
}
assert!(dataset.get_data().is_some());

// `take_data()` moves owned arrays out (no `to_owned()` clone) and leaves the
// instance reusable. The next access reloads from the cached file.
let (owned_features, owned_labels) = dataset.take_data().unwrap();
assert_eq!(owned_features.shape(), &[1797, 64]);
assert_eq!(owned_labels.len(), 1797);

// `into_data()` also returns owned arrays with no clone, but consumes the
// instance (use it when you are done with the dataset).
let (owned_features, owned_labels) = dataset.into_data().unwrap();
assert_eq!(owned_features.shape(), &[1797, 64]);
assert_eq!(owned_labels.len(), 1797);

Implementations§

Source§

impl Digits

Source

pub fn new(storage_dir: &str) -> Self

Create a new Digits instance without loading data.

The dataset loads lazily, on your first call to a data accessor method. This function only stores the storage directory.

§Parameters
  • storage_dir - Directory where the dataset will be stored.
§Returns
  • Self - Digits instance ready for lazy loading.
Source

pub fn features(&self) -> Result<&Array2<f64>, DatasetError>

Get a reference to the feature matrix.

This method triggers lazy loading on first call. Later calls return the cached data instantly.

§Returns
  • &Array2<f64> - Reference to feature matrix with shape (1797, 64) containing the 64 pixel intensities (pixel_0_0pixel_7_7, each in 0..=16) of each flattened 8×8 image.
§Errors

Returns DatasetError if:

  • Download fails due to network issues
  • File extraction or I/O operations fail
  • Data format is invalid (wrong number of columns, unparseable values, or invalid labels)
  • Dataset size does not match expected dimensions (1797 samples, 64 features)
Source

pub fn labels(&self) -> Result<&Array1<u8>, DatasetError>

Get a reference to the labels vector.

This method triggers lazy loading on first call. Later calls return the cached data instantly.

§Returns
  • &Array1<u8> - Reference to labels vector with shape (1797,) containing the digit classes (09).
§Errors

Returns DatasetError if:

  • Download fails due to network issues
  • File extraction or I/O operations fail
  • Data format is invalid (wrong number of columns, unparseable values, or invalid labels)
  • Dataset size does not match expected dimensions (1797 samples)
Source

pub fn data(&self) -> Result<&(Array2<f64>, Array1<u8>), DatasetError>

Get both features and labels as references.

This method triggers lazy loading on first call. Later calls return the cached data instantly.

§Returns
  • &DigitsData - reference to the cached (features, labels) tuple: the feature matrix has shape (1797, 64) and the label vector has shape (1797,) containing the digit classes (09).
§Errors

Returns DatasetError if:

  • Download fails due to network issues
  • File extraction or I/O operations fail
  • Data format is invalid (wrong number of columns, unparseable values, or invalid labels)
  • Dataset size does not match expected dimensions (1797 samples, 64 features)
Source

pub fn get_data(&self) -> Option<&(Array2<f64>, Array1<u8>)>

Get both features and labels as references without triggering loading.

Unlike Digits::data, which loads the dataset on first call, this never runs the loader. If the data has not been loaded yet, it returns None instead of downloading and parsing. If the data is already cached and you want to avoid the download and parse cost, use this method.

§Returns
  • Some(&DigitsData) - reference to the cached (features, labels) tuple (feature matrix (1797, 64), label vector (1797,)), if loaded.
  • None - if the dataset has not been loaded yet.
Source

pub fn get_data_mut(&mut self) -> Option<&mut (Array2<f64>, Array1<u8>)>

Get mutable references to features and labels for in-place editing.

This lets you change the cached arrays directly (e.g. normalize features, replace label values), with no to_owned() clone. The cache keeps the change: it does not remove the arrays. Later calls to Digits::features, Digits::data, or Digits::get_data observe the change.

Like Digits::get_data, this does not trigger loading: it returns None if the dataset has not been loaded. If you need to make sure the data is present, call a loading accessor first (e.g. Digits::data).

§Returns
  • Some(&mut DigitsData) - mutable reference to the cached (features, labels) tuple (feature matrix (1797, 64), label vector (1797,)), if loaded.
  • None - if the dataset has not been loaded yet.
Source

pub fn into_data(self) -> Result<(Array2<f64>, Array1<u8>), DatasetError>

Consume the dataset and return owned features and labels.

Unlike Digits::data, which borrows the cached data, this moves it out and returns owned arrays directly. It needs no to_owned() clone. If the dataset is not loaded yet, this call loads it.

This consumes self, so you cannot use the instance afterward. If you want owned data but need to keep using the instance, use Digits::take_data instead. It takes &mut self and leaves the instance reusable.

§Returns
  • (Array2<f64>, Array1<u8>) - owned feature matrix with shape (1797, 64) and owned label vector with shape (1797,).
§Errors

Returns DatasetError if loading fails (network, file I/O, parsing, invalid labels, or a dimension mismatch).

Source

pub fn take_data(&mut self) -> Result<(Array2<f64>, Array1<u8>), DatasetError>

Take owned features and labels out of the dataset, leaving it reusable.

Like Digits::into_data, this returns owned arrays with no to_owned() clone. Unlike that method, it takes &mut self instead of consuming the instance. It moves the cached data out and resets the instance to its unloaded state. The next accessor call (e.g. Digits::features or Digits::data) loads the dataset again.

If you are done with the instance, use Digits::into_data instead.

§Returns
  • (Array2<f64>, Array1<u8>) - owned feature matrix with shape (1797, 64) and owned label vector with shape (1797,).
§Errors

Returns DatasetError if loading fails (network, file I/O, parsing, invalid labels, or a dimension mismatch).

Trait Implementations§

Source§

impl Debug for Digits

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl MlDataset for Digits

Source§

const NAME: &'static str = "digits"

The dataset’s identifier, matching the one used in its error messages (for example, "iris", "sms_spam").
Source§

type Data = (ArrayBase<OwnedRepr<f64>, Dim<[usize; 2]>>, ArrayBase<OwnedRepr<u8>, Dim<[usize; 1]>>)

What this loader parses into: the module’s …Data type alias. Read more
Source§

fn dataset(&self) -> &Dataset<Self::Data, DatasetError>

Borrow the underlying container.
Source§

fn dataset_mut(&mut self) -> &mut Dataset<Self::Data, DatasetError>

Borrow the underlying container mutably.
Source§

fn into_dataset(self) -> Dataset<Self::Data, DatasetError>

Consume the loader and return the underlying container.
Source§

fn load(&self) -> Result<&Self::Data, DatasetError>

Load the dataset if needed and borrow the parsed data. Read more
Source§

fn load_mut(&mut self) -> Result<&mut Self::Data, DatasetError>

Load the dataset if needed and borrow the parsed data mutably. Read more
Source§

fn peek(&self) -> Option<&Self::Data>

Borrow the parsed data without triggering loading. Read more
Source§

fn unload(&mut self) -> Option<Self::Data>

Move the parsed data out, leaving the loader reusable and unloaded. Read more
Source§

fn is_loaded(&self) -> bool

Whether the cache currently holds the data. Read more
Source§

fn storage_dir(&self) -> &str

The directory this loader stores its files in.
Source§

fn invalidate(&mut self)

Drop the cached data, keeping the loader usable. Read more
Source§

fn n_samples(&self) -> Result<usize, DatasetError>

The number of samples in the dataset, loading it if needed. Read more

Auto Trait Implementations§

§

impl !Freeze for Digits

§

impl !RefUnwindSafe for Digits

§

impl !UnwindSafe for Digits

§

impl Send for Digits

§

impl Sync for Digits

§

impl Unpin for Digits

§

impl UnsafeUnpin for Digits

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.