Minor changes and fixes.

This commit is contained in:
Ryan Curtin
2024-01-13 12:39:36 -05:00
parent 3ee57fdeca
commit 6edd1104b5
4 changed files with 492 additions and 281 deletions
+54 -75
View File
@@ -1,4 +1,5 @@
# Documentation for mlpack
## A fast, flexible machine learning library
mlpack is an intuitive, fast, and flexible header-only C++ machine learning
@@ -18,22 +19,21 @@ _If you use mlpack, please [cite the software](citation.md)._
Installing mlpack can be done using the
[instructions in the README](README.md#3-installing-and-using-mlpack-in-c);
or the [Windows build guide](user/build_windows.md). Then, the following
simple guides are good places to get started:
or the [Windows build guide](user/build_windows.md).
The following basic guides are *highly recommended* before using mlpack.
* [mlpack C++ quickstart](quickstart/cpp.md): create a couple simple C++
programs that use mlpack
* [Sample Windows mlpack C++ application](user/sample_ml_app.md): create a
working mlpack Windows program using Visual Studio
* ***First steps***:
- [mlpack C++ quickstart](quickstart/cpp.md): create a couple simple C++
programs that use mlpack
- [Sample Windows mlpack C++ application](user/sample_ml_app.md): create a
working mlpack Windows program using Visual Studio
After that, it's a good idea to familiarize yourself with the basics of the
library. The documentation for mlpack's algorithms depends on the concepts in
the pages below.
* ***Basics of matrices and data in mlpack***:
- [Matrices and data in mlpack](user/matrices.md)
- [Loading and saving mlpack objects](user/load_save.md)
* [Matrices and data in mlpack](user/matrices.md)
* [Loading and saving mlpack objects](user/load_save.md)
* [Core mlpack documentation](user/core.md): reference documentation for all
core classes and functions that are used in mlpack.
* ***Reference for mlpack core classes***:
- [Core mlpack documentation](user/core.md)
## mlpack algorithm documentation
@@ -53,68 +53,6 @@ detailed in the sections below.
* [Modeling utilities](#modeling-utilities): cross-validation, hyperparameter
tuning, etc.
## Bindings to other languages
mlpack's bindings to other languages have less complete functionality than
mlpack in C++, but almost all of the same algorithms are available.
***Python***:
* [Python quickstart](quickstart/python.md)
* [Python reference documentation](https://www.mlpack.org/doc/python_documentation.html)
***Julia***:
* [Julia quickstart](quickstart/julia.md)
* [Julia reference documentation](https://www.mlpack.org/doc/julia_documentation.html)
***R***:
* [R quickstart](quickstart/r.md)
* [R reference documentation](https://www.mlpack.org/doc/r_documentation.html)
***Command-line programs***:
* [Command-line quickstart](quickstart/cli.md)
* [Command-line reference documentation](https://www.mlpack.org/doc/cli_documentation.html)
***Go***:
* [Go quickstart](quickstart/go.md)
* [Go reference documentation](https://www.mlpack.org/doc/go_documentation.html)
## Examples and further documentation
* [mlpack examples repository](https://github.com/mlpack/examples/): numerous
fully-working example applications of mlpack, in C++ and other languages.
* [mlpack models repository](https://github.com/mlpack/models/): complex models
in C++ built with mlpack
For additional documentation beyond what is covered in all the resources above,
the source code should be consulted. Each method is fully documented.
## Developer documentation
Throughout the codebase, mlpack uses some common template parameter policies.
These are documented below.
* [The `ElemType` policy](developer/elemtype.md): element types for data
* [The `MetricType` policy](developer/metrics.md): distance metrics
* [The `KernelType` policy](developer/kernels.md): kernel functions
* [The `TreeType` policy](developer/trees.md): space trees (ball trees,
KD-trees, etc.)
In addition, the following documentation may be useful when developing bindings
for other languages:
* [Timers](developer/timer.md): timing parts of bindings
* [Writing an mlpack binding](developer/iodoc.md): simple examples of mlpack
bindings
* [Automatic bindings](developer/bindings.md): details on mlpack's automatic
binding generator system.
## Algorithm documentation
### Classification algorithms
Classify points as discrete labels (`0`, `1`, `2`, ...).
@@ -164,3 +102,44 @@ Transform data from one space to another.
Cross-validation, hyperparameter tuning, etc.
<!-- TODO: add some -->
## Bindings to other languages
mlpack's bindings to other languages have less complete functionality than
mlpack in C++, but almost all the same algorithms are available.
| ***Python*** | -- | [quickstart](quickstart/python.md) | -- | [reference](https://www.mlpack.org/doc/python_documentation.html) |
| ***Julia*** | -- | [quickstart](quickstart/julia.md) | -- | [reference](https://www.mlpack.org/doc/julia_documentation.html) |
| ***R*** | -- | [quickstart](quickstart/r.md) | -- | [reference](https://www.mlpack.org/doc/r_documentation.html)
| ***Command-line programs*** | -- | [quickstart](quickstart/cli.md) | -- | [reference](https://www.mlpack.org/doc/cli_documentation.html) |
| ***Go*** | -- | [quickstart](quickstart/go.md) | -- | [reference](https://www.mlpack.org/doc/go_documentation.html) |
## Examples and further documentation
* [mlpack examples repository](https://github.com/mlpack/examples/): numerous
fully-working example applications of mlpack, in C++ and other languages.
* [mlpack models repository](https://github.com/mlpack/models/): complex models
in C++ built with mlpack
For additional documentation beyond what is covered in all the resources above,
the source code should be consulted. Each method is fully documented.
## Developer documentation
Throughout the codebase, mlpack uses some common template parameter policies.
These are documented below.
* [The `ElemType` policy](developer/elemtype.md): element types for data
* [The `MetricType` policy](developer/metrics.md): distance metrics
* [The `KernelType` policy](developer/kernels.md): kernel functions
* [The `TreeType` policy](developer/trees.md): space trees (ball trees,
KD-trees, etc.)
In addition, the following documentation may be useful when developing bindings
for other languages:
* [Timers](developer/timer.md): timing parts of bindings
* [Writing an mlpack binding](developer/iodoc.md): simple examples of mlpack
bindings
* [Automatic bindings](developer/bindings.md): details on mlpack's automatic
binding generator system.
+156 -30
View File
@@ -4,24 +4,42 @@ Underlying the implementations of [mlpack's machine learning
algorithms](index.md#mlpack-algorithm-documentation) are mlpack core support
classes, each of which are documented on this page.
* [Core math utilities](#core-math-utilities): utility classes for mathematical
purposes
* [Distributions](#distributions): probability distributions
* [Metrics](#metrics): distance metrics for geometric algorithms
* [Kernels](#kernels): Mercer kernels for kernel-based algorithms
## Core math utilities
Utilities in the `mlpack::math::` namespace are meant to provide additional
mathematical support on top of Armadillo.
* [`math::Range`](#mathrange): simple mathematical range (i.e. `[0, 3]`)
---
### `math::Range`
The `math::Range` class represents a simple mathematical range (i.e. `[0, 3]`),
with each value represented as a `double`.
with the bounds represented as `double`s.
---
#### Constructors
* `r = math::Range()`
- Construct an empty range.
* `r = math::Range(p)`
- Construct the range `[p, p]`.
* `r = math::Range(lo, hi)`
- Construct a range. If no value is specified, the range is empty; if `p` is
specified, the range is `[p, p]`; if `lo` and `hi` are specified, the range
is `[lo, hi]`.
- Construct the range `[lo, hi]`.
---
#### Accessing and modifying range properties
* `r.Lo()` and `r.Hi()` return the lower and upper bounds of the range as
`double`s.
@@ -33,6 +51,10 @@ with each value represented as a `double`.
* `r.Mid()` returns the midpoint of the range as a `double`.
---
#### Working with ranges
* Given two ranges `r1` and `r2`,
- `r1 | r2` returns the union of the ranges,
- `r1 |= r2` expands `r1` to include the range `r2`,
@@ -50,24 +72,34 @@ with each value represented as a `double`.
- `r *= d` scales `r.Lo()` and `r.Hi()` by `d`, and
- `r.Contains(d)` returns `true` if `d` is contained in the range.
---
* To use ranges with different element types (e.g. `float`), use the type
`math::RangeType<float>` or similar.
---
Example:
```c++
math::Range r1(5.0, 6.0); // [5, 6]
math::Range r2(7.0, 8.0); // [7, 8]
mlpack::math::Range r1(5.0, 6.0); // [5, 6]
mlpack::math::Range r2(7.0, 8.0); // [7, 8]
math::Range r3 = r1 | r2; // [5, 8]
math::Range r4 = r1 & r2; // empty range
mlpack::math::Range r3 = r1 | r2; // [5, 8]
mlpack::math::Range r4 = r1 & r2; // empty range
bool b1 = r1.Contains(r2); // false
bool b2 = r1.Contains(5.5); // true
bool b3 = r1.Contains(r3); // true
bool b4 = r3.Contains(r4); // false
// Create a range of `float`s and a range of `int`s.
mlpack::math::RangeType<float> r5(1.0f, 1.5f); // [1.0, 1.5]
mlpack::math::RangeType<int> r6(3, 4); // [3, 4]
```
---
`math::Range` is used by:
* [`RangeSearch`](range_search.md)
@@ -80,11 +112,16 @@ bool b4 = r3.Contains(r4); // false
mlpack has support for a number of different distributions, each supporting the
same API. These can be used with, for instance, the [`HMM`](hmm.md) class.
* [`DiscreteDistribution`](#discretedistribution): multidimensional categorical
distribution (generalized Bernoulli distribution)
* [`GaussianDistribution`](#gaussiandistribution): multidimensional Gaussian
distribution
### `DiscreteDistribution`
`DiscreteDistribution` represents a multidimensional categorical distribution
(or generalized Bernoulli distribution) where integer-valued vectors (e.g. `[0,
3, 4]`) are associated with specific probabilities in each dimension.
(or generalized Bernoulli distribution) where integer-valued vectors (e.g.
`[0, 3, 4]`) are associated with specific probabilities in each dimension.
*Example:* a 3-dimensional `DiscreteDistribution` will have a specific
probability value associated with each integer value in each dimension. So, for
@@ -92,6 +129,10 @@ the vector `[0, 3, 4]`, `P(0)` in dimension 0 could be, e.g., `0.3`, `P(3)` in
dimension 1 could be, e.g., `0.4`, and `P(4)` in dimension 2 could be, e.g.,
`0.6`. Then, `P([0, 3, 4])` would be `0.3 * 0.4 * 0.6 = 0.072`.
---
#### Constructors
* `d = DiscreteDistribution(numObservations)`
- Create a one-dimensional discrete distribution with `numObservations`
different observations in the one and only dimension. `numObservations` is
@@ -112,10 +153,14 @@ dimension 1 could be, e.g., `0.4`, and `P(4)` in dimension 2 could be, e.g.,
- `probabilities[i]` is a vector such that `probabilities[i][j]` contains the
probability of `j` in dimension `i`.
---
#### Access and modify properties of distribution
* `d.Dimensionality()` returns a `size_t` indicating the number of dimensions
in the multidimensional discrete distribution.
* `d.Probabilities(i)` returns an `arma::vec` containing the probabilities of
* `d.Probabilities(i)` returns an `arma::vec&` containing the probabilities of
each observation in dimension `i`.
- `d.Probabilities(i)[j]` is the probability of `j` in dimension `i`.
- This can be used to modify probabilities: `d.Probabilities(0)[1] = 0.7`
@@ -123,6 +168,10 @@ dimension 1 could be, e.g., `0.4`, and `P(4)` in dimension 2 could be, e.g.,
- *Note:* when setting probabilities manually, be sure that the sum of
probabilities in a dimension is 1!
---
#### Compute probabilities of points
* `d.Probability(observation)` returns the probability of the given
observation as a `double`.
- `observation` should be an `arma::vec` of size `d.Dimensionality()`.
@@ -142,9 +191,17 @@ dimension 1 could be, e.g., `0.4`, and `P(4)` in dimension 2 could be, e.g.,
* `d.LogProbability(observations, probabilities)` computes the
log-probabilities of many observations.
---
#### Sample from the distribution
* `d.Random()` returns an `arma::vec` with a random sample from the
multidimensional discrete distribution.
---
#### Fit the distribution to observations
* `d.Train(observations)`
- Fit the distribution to the given observations.
- `observations` should be an `arma::mat` with number of rows equal to
@@ -160,11 +217,13 @@ dimension 1 could be, e.g., `0.4`, and `P(4)` in dimension 2 could be, e.g.,
- `observationProbabilities[i]` should be equal to the probability that
`observations.col(i)` is from `d`.
---
*Example usage:*
```c++
// Create a single-dimension Bernoulli distribution: P([0]) = 0.3, P([1]) = 0.7.
DiscreteDistribution bernoulli(2);
mlpack::DiscreteDistribution bernoulli(2);
bernoulli.Probabilities(0)[0] = 0.3;
bernoulli.Probabilities(0)[1] = 0.7;
@@ -177,7 +236,7 @@ arma::vec probDim0 = arma::vec("0.1 0.3 0.5 0.1"); // 4 possible values.
arma::vec probDim1 = arma::vec("0.7 0.3"); // 2 possible values.
arma::vec probDim2 = arma::vec("0.4 0.4 0.2"); // 3 possible values.
std::vector<arma::vec> probs { probDim0, probDim1, probDim2 };
DiscreteDistribution d(probs);
mlpack::DiscreteDistribution d(probs);
arma::vec obs("2 0 1");
const double p3 = d.Probability(obs); // p3 = 0.5 * 0.7 * 0.4 = 0.14.
@@ -185,11 +244,12 @@ const double p3 = d.Probability(obs); // p3 = 0.5 * 0.7 * 0.4 = 0.14.
// Estimate a 10-dimensional discrete distribution.
// Each dimension takes values between 0 and 9.
arma::mat observations = arma::randi<arma::mat>(10, 1000,
arma::distr_param(0, 10));
arma::distr_param(0, 9));
// Create a distribution with 10 observations in each of the 10 dimensions.
DiscreteDistribution d2(arma::Col<size_t>("10 10 10 10 10 10 10 10 10 10"));
d2.Estimate(observations);
mlpack::DiscreteDistribution d2(
arma::Col<size_t>("10 10 10 10 10 10 10 10 10 10"));
d2.Train(observations);
// Compute the probabilities of each point.
arma::vec probabilities;
@@ -205,6 +265,10 @@ std::cout << "Average probability: " << arma::mean(probabilities) << "."
`GaussianDistribution` is a standard multivariate Gaussian distribution with
parameterized mean and covariance.
---
#### Constructors
* `g = GaussianDistribution(dimensionality)`
- Create the distribution with the given dimensionality.
- The distribution will have a zero mean and unit diagonal covariance matrix.
@@ -216,6 +280,10 @@ parameterized mean and covariance.
- `covariance` is of type `arma::mat`, and should be symmetric and square,
with rows and columns equal to the dimensionality of the distribution.
---
#### Access and modify properties of distribution
* `g.Dimensionality()` returns the dimensionality of the distribution as a
`size_t`.
@@ -232,6 +300,10 @@ parameterized mean and covariance.
* `g.LogDetCov()` returns a `double` holding the log-determinant of the
covariance.
---
#### Compute probabilities of points
* `g.Probability(observation)` returns the probability of the given
observation as a `double`.
- `observation` should be an `arma::vec` of size `d.Dimensionality()`.
@@ -249,9 +321,17 @@ parameterized mean and covariance.
* `g.LogProbability(observations, probabilities)` computes the
log-probabilities of many observations.
---
#### Sample from the distribution
* `g.Random()` returns an `arma::vec` with a random sample from the
multidimensional discrete distribution.
---
#### Fit the distribution to observations
* `g.Train(observations)`
- Fit the distribution to the given observations.
- `observations` should be an `arma::mat` with number of rows equal to
@@ -272,7 +352,7 @@ parameterized mean and covariance.
```c++
// Create a Gaussian distribution in 3 dimensions with zero mean and unit
// covariance.
GaussianDistribution g(3);
mlpack::GaussianDistribution g(3);
// Compute the probability of the point [0, 0.5, 0.25].
const double p = g.Probability(arma::vec("0 0.5 0.25"));
@@ -292,7 +372,7 @@ const double p2 = g.Probability(arma::vec("0 0.5 0.25"));
// dimensions.
arma::mat samples(50, 10000, arma::fill::randn); // Normally distributed.
GaussianDistribution g2(50);
mlpack::GaussianDistribution g2(50);
g2.Train(samples);
// Compute the probability of all of the samples.
@@ -320,6 +400,12 @@ including:
* [`RANN`](rann.md)
* [`KMeans`](kmeans.md)
Supported metrics:
* [`LMetric`](#lmetric): generalized L-metric/Lp-metric, including
Manhattan/Euclidean/Chebyshev distances
* [Implement a custom metric](../developer/metrics.md)
### `LMetric`
The `LMetric` template class implements a [generalized
@@ -341,6 +427,8 @@ LMetric<Power, TakeRoot>
- If set to `false`, the metric will no longer satisfy the triangle
inequality.
---
Several convenient typedefs are available:
* `ManhattanDistance` (defined as `LMetric<1>`)
@@ -348,6 +436,8 @@ Several convenient typedefs are available:
* `SquaredEuclideanDistance` (defined as `LMetric<2, false>`)
* `ChebyshevDistance` (defined as `LMetric<INT_MAX>`)
---
The static `Evaluate()` method can be used to compute the distance between two
vectors.
@@ -363,23 +453,36 @@ implements the Armadillo API (e.g. `arma::fvec`, `arma::sp_fvec`, etc.).
arma::vec a("0.0 1.0 5.0");
arma::vec b("1.0 3.0 5.0");
const double d1 = ManhattanDistance::Evaluate(a, b); // d1 = 3.0
const double d2 = EuclideanDistance::Evaluate(a, b); // d2 = 2.236
const double d3 = SquaredEuclideanDistance::Evaluate(a, b); // d3 = 5.0
const double d4 = ChebyshevDistance::Evaluate(a, b); // d4 = 2.0
const double d5 = LMetric<4>::Evaluate(a, b); // d5 = 2.0305
const double d6 = LMetric<3, false>::Evaluate(a, b); // d6 = 9.0
const double d1 = mlpack::ManhattanDistance::Evaluate(a, b); // d1 = 3.0
const double d2 = mlpack::EuclideanDistance::Evaluate(a, b); // d2 = 2.24
const double d3 = mlpack::SquaredEuclideanDistance::Evaluate(a, b); // d3 = 5.0
const double d4 = mlpack::ChebyshevDistance::Evaluate(a, b); // d4 = 2.0
const double d5 = mlpack::LMetric<4>::Evaluate(a, b); // d5 = 2.03
const double d6 = mlpack::LMetric<3, false>::Evaluate(a, b); // d6 = 9.0
std::cout << "Manhattan distance: " << d1 << "." << std::endl;
std::cout << "Euclidean distance: " << d2 << "." << std::endl;
std::cout << "Squared Euclidean distance: " << d3 << "." << std::endl;
std::cout << "Chebyshev distance: " << d4 << "." << std::endl;
std::cout << "L4-distance: " << d5 << "." << std::endl;
std::cout << "Cubed L3-distance: " << d6 << "." << std::endl;
// Compute the distance between two random 10-dimensional vectors in a matrix.
arma::mat m(10, 100, arma::fill::randu);
const double d7 = EuclideanDistance::Evaluate(m.col(0), m.col(7));
const double d7 = mlpack::EuclideanDistance::Evaluate(m.col(0), m.col(7));
std::cout << std::endl;
std::cout << "Distance between two random vectors: " << d7 << "." << std::endl;
std::cout << std::endl;
// Compute the distance between two 32-bit precision `float` vectors.
arma::fvec fa("0.0 1.0 5.0");
arma::fvec fb("1.0 3.0 5.0");
const double d8 = EuclideanDistance::Evaluate(fa, fb); // d8 = 2.236
const double d8 = mlpack::EuclideanDistance::Evaluate(fa, fb); // d8 = 2.236
std::cout << "Euclidean distance (fvec): " << d8 << "." << std::endl;
```
## Kernels
@@ -397,6 +500,12 @@ including:
* [`FastMKS`](fastmks.md)
* [`NystroemMethod`](nystroem_method.md)
Supported kernels:
* [`GaussianKernel`](#gaussiankernel): standard Gaussian/radial basis
function/RBF kernel
* [Implement a custom kernel](../developer/kernels.md)
### `GaussianKernel`
The `GaussianKernel` class implements the standard [Gaussian
@@ -407,12 +516,20 @@ The Gaussian kernel is defined as:
`k(x1, x2) = exp(-|| x1 - x2 ||^2 / (2 * bw^2))`
where `bw` is the bandwidth parameter of the kernel.
---
#### Constructors and properties
* `g = GaussianKernel(bw=1.0)`
- Create a `GaussianKernel` with the given bandwidth `bw`.
* `g.Bandwidth()` returns the bandwidth of the kernel as a `double`.
- To set the bandwidth, use `g.Bandwidth(newBandwidth)`.
---
#### Kernel evaluation
* `g.Evaluate(x1, x2)`
- Compute the kernel value between two vectors `x1` and `x2`.
- `x1` and `x2` should be vector types that implement the Armadillo API
@@ -423,6 +540,10 @@ where `bw` is the bandwidth parameter of the kernel.
between those two vectors (`distance`) is already known.
- `distance` should have type `double`.
---
#### Other utilities
* `g.Gradient(distance)`
- Compute the (one-dimensional) gradient of the kernel function with respect
to the distance between two points, evaluated at `distance`.
@@ -438,16 +559,18 @@ where `bw` is the bandwidth parameter of the kernel.
```c++
// Create a Gaussian kernel with default bandwidth.
GaussianKernel g;
mlpack::GaussianKernel g;
// Create a Gaussian kernel with bandwidth 5.0.
GaussianKernel g2(5.0);
mlpack::GaussianKernel g2(5.0);
// Evaluate the kernel value between two 3-dimensional points.
arma::vec x1("0.5 1.0 1.5");
arma::vec x2("1.5 1.0 0.5");
const double k1 = g.Evaluate(x1, x2);
const double k2 = g2.Evaluate(x1, x2);
std::cout << "Kernel values: " << k1 << " (bw=1.0), " << k2 << " (bw=5.0)."
<< std::endl;
// Evaluate the kernel value when the distance between two points is already
// computed.
@@ -457,16 +580,19 @@ const double k3 = g.Evaluate(distance);
// Change the bandwidth of the kernel to 2.5.
g.Bandwidth(2.5);
const double k4 = g.Evaluate(x1, x2);
std::cout << "Kernel value with bw=2.5: " << k4 << "." << std::endl;
// Evaluate the kernel value between x1 and all points in a random matrix.
arma::mat r(3, 100, arma::fill::randu);
arma::vec kernelValues(100);
for (size_t i = 0; i < r.n_cols; ++i)
kernelValues[i] = g.Evaluate(x1, r.col(i));
std::cout << "Average kernel value for random points: "
<< arma::mean(kernelValues) << "." << std::endl;
// Compute the kernel value between two 32-bit floating-point vectors.
arma::fvec fx1("0.5 1.0 1.5");
arma::fvec fx2("1.5 1.0 0.5");
const double k4 = g.Evaluate(fx1, fx2);
const double k5 = g2.Evaluate(fx1, fx2);
const double k5 = g.Evaluate(fx1, fx2);
const double k6 = g2.Evaluate(fx1, fx2);
```
+242 -139
View File
@@ -6,26 +6,41 @@ any mlpack object via the [cereal](https://uscilab.github.io/cereal/)
serialization toolkit. A number of other utilities related to loading and
saving data and objects are also available.
* [Numeric data](#numeric-data)
* [Mixed categorical data](#mixed-categorical-data)
- [`data::DatasetInfo`](#datadatasetinfo)
- [Loading categorical data](#loading-categorical-data)
* [Image data](#image-data)
- [`data::ImageInfo`](#dataimageinfo)
- [Loading images](#loading-images)
* [mlpack objects](#mlpack-objects): load or save any mlpack object
* [Normalizing labels](#normalizing-labels): convert labels to ranges required
by mlpack classifiers
* [Formats](#formats): supported formats for each load/save variant
## Numeric data
Numeric data or general numeric matrices can be loaded or saved with the
following functions.
- `data::Load(filename, matrix, fatal=false, transpose=true,
format=FileType::AutoDetect)`
- `data::Save(filename, matrix, fatal=false, transpose=true,
format=FileType::AutoDetect)`
- `data::Load(filename, matrix, fatal=false, transpose=true, format=FileType::AutoDetect)`
- `data::Save(filename, matrix, fatal=false, transpose=true, format=FileType::AutoDetect)`
* `filename` is a `std::string` with a path to the file to be loaded.
* By default the format is auto-detected based on the file extension, but can
be explicitly specified with `format`; see [Formats](#formats).
* `matrix` is an `arma::mat&`, `arma::Mat<size_t>&`, or similar (e.g., a
reference to an Armadillo object that data will be loaded into or saved
from).
* If `fatal` is `true`, a `std::runtime_error` will be thrown on failure.
* If `transpose` is `true`, then for plaintext formats (CSV/TSV/ASCII), the
matrix will be transposed on save. (Keep this `true` if you want a
column-major matrix to be saved with points as rows and dimensions as
columns; that is generally what is desired.)
* A `bool` is returned indicating whether the operation was successful.
---
@@ -48,8 +63,8 @@ std::cout << " - " << dataset.n_rows << " dimensions." << std::endl;
std::cout << "The labels in 'satellite.train.labels.csv' have: " << std::endl;
std::cout << " - " << labels.n_elem << " labels." << std::endl;
std::cout << " - A maximum label of " << labels.max() << std::endl;
std::cout << " - A minimum label of " << labels.min() << std::endl;
std::cout << " - A maximum label of " << labels.max() << "." << std::endl;
std::cout << " - A minimum label of " << labels.min() << "." << std::endl;
// Modify and save the data. Add 2 to the data and drop the last column.
dataset += 2;
@@ -70,7 +85,7 @@ mlpack, string data and other non-numerical data must be mapped to categorical
values and represented as part of an `arma::mat`. Category information is
stored in an auxiliary `data::DatasetInfo` object.
### `DatasetInfo`
### `data::DatasetInfo`
<!-- TODO: also document in core.md? -->
@@ -79,15 +94,23 @@ mlpack represents categorical data via the use of the auxiliary
numeric or categorical and allows conversion from the original category values
to the numeric values used to represent those categories.
---
#### Constructors
- `info = data::DatasetInfo()`
* Create an empty `DatasetInfo` object.
* Use this constructor if you intend to populate the `DatasetInfo` via a
`data::Load()` call.
* Create an empty `data::DatasetInfo` object.
* Use this constructor if you intend to populate the `data::DatasetInfo` via
a `data::Load()` call.
- `info = data::DatasetInfo(dimensionality)`
* Create a `DatasetInfo` object with the given dimensionality
* Create a `data::DatasetInfo` object with the given dimensionality
* All dimensions are assumed to be numeric (not categorical).
---
#### Accessing and setting properties
- `info.Type(d)`
* Get the type (categorical or numeric) of dimension `d`.
* Returns a `data::Datatype`, either `data::Datatype::numeric` or
@@ -103,9 +126,13 @@ to the numeric values used to represent those categories.
- `info.Dimensionality()`
* Return the dimensionality of the object as a `size_t`.
- `info.MapString(value, d)`
* Given `value` (a `std::string`), return the `size_t` representing the
categorical mapping of `value` in dimension `d`.
---
#### Map to and from numeric values
- `info.MapString<double>(value, d)`
* Given `value` (a `std::string`), return the `double` representing the
categorical mapping (an integer value) of `value` in dimension `d`.
* If a mapping for `value` does not exist in dimension `d`, a new mapping is
created, and `info.NumMappings(d)` is increased by one.
* If dimension `d` is numeric and `value` cannot be parsed as a numeric
@@ -119,10 +146,13 @@ to the numeric values used to represent those categories.
---
With a `DatasetInfo` object, categorical data can be loaded:
### Loading categorical data
With a `data::DatasetInfo` object, categorical data can be loaded:
- `data::Load(filename, matrix, info, fatal=false, transpose=true)`
* `filename` is a `std::string` with a path to the file to be loaded.
* The format is auto-detected based on the extension of the filename and the
contents of the file:
- `.csv`, `.tsv`, or `.txt` for CSV/TSV (tab-separated)/ASCII
@@ -132,14 +162,18 @@ With a `DatasetInfo` object, categorical data can be loaded:
* `matrix` is an `arma::mat&`, `arma::Mat<size_t>&`, or similar (e.g., a
reference to an Armadillo object that data will be loaded into or saved
from).
* `info` is a `data::DatasetInfo&` object. This will be populated with the
category information of the file when loading, and used to unmap values
when saving.
* If `fatal` is `true`, a `std::runtime_error` will be thrown on failure.
* If `transpose` is `true`, then for plaintext formats (CSV/TSV/ASCII), the
matrix will be transposed on save. (Keep this `true` if you want a
column-major matrix to be saved with points as rows and dimensions as
columns; that is generally what is desired.)
* A `bool` is returned indicating whether the operation was successful.
Saving should be performed with the [numeric](#numeric-data) `data::Load()`
@@ -187,7 +221,7 @@ for (size_t d = 0; d < info.Dimensionality(); ++d)
{
// This will create a new mapping if the string "hooray!" does not already
// exist as a category for dimension d..
dataset(d, 4) = info.MapString("hooray!", d);
dataset(d, 4) = info.MapString<double>("hooray!", d);
}
else
{
@@ -198,7 +232,7 @@ for (size_t d = 0; d < info.Dimensionality(); ++d)
---
Example usage to manually create a `DatasetInfo` object.
Example usage to manually create a `data::DatasetInfo` object.
```c++
// This will manually create the following data matrix (shown as it would appear
@@ -232,20 +266,20 @@ dataset(0, 4) = 5;
dataset(0, 5) = 6;
// The second dimension is categorical.
dataset(1, 0) = info.MapString("TRUE", 1);
dataset(1, 1) = info.MapString("FALSE", 1);
dataset(1, 2) = info.MapString("FALSE", 1);
dataset(1, 3) = info.MapString("TRUE", 1);
dataset(1, 4) = info.MapString("TRUE", 1);
dataset(1, 5) = info.MapString("FALSE", 1);
dataset(1, 0) = info.MapString<double>("TRUE", 1);
dataset(1, 1) = info.MapString<double>("FALSE", 1);
dataset(1, 2) = info.MapString<double>("FALSE", 1);
dataset(1, 3) = info.MapString<double>("TRUE", 1);
dataset(1, 4) = info.MapString<double>("TRUE", 1);
dataset(1, 5) = info.MapString<double>("FALSE", 1);
// The third dimension is categorical.
dataset(2, 0) = info.MapString("good", 2);
dataset(2, 1) = info.MapString("good", 2);
dataset(2, 2) = info.MapString("bad", 2);
dataset(2, 3) = info.MapString("bad", 2);
dataset(2, 4) = info.MapString("unknown", 2);
dataset(2, 5) = info.MapString("unknown", 2);
dataset(2, 0) = info.MapString<double>("good", 2);
dataset(2, 1) = info.MapString<double>("good", 2);
dataset(2, 2) = info.MapString<double>("bad", 2);
dataset(2, 3) = info.MapString<double>("bad", 2);
dataset(2, 4) = info.MapString<double>("unknown", 2);
dataset(2, 5) = info.MapString<double>("unknown", 2);
// The fourth dimension is numeric.
dataset(3, 0) = 7.0;
@@ -259,12 +293,12 @@ dataset(3, 5) = 5.1;
// category values in the order they are seen, even if the category can be
// parsed as a number. So, here, the value '4' will be assigned category '0',
// since it is seen first.
dataset(4, 0) = info.MapString("4", 4);
dataset(4, 1) = info.MapString("3", 4);
dataset(4, 2) = info.MapString("4", 4);
dataset(4, 3) = info.MapString("1", 4);
dataset(4, 4) = info.MapString("0", 4);
dataset(4, 5) = info.MapString("2", 4);
dataset(4, 0) = info.MapString<double>("4", 4);
dataset(4, 1) = info.MapString<double>("3", 4);
dataset(4, 2) = info.MapString<double>("4", 4);
dataset(4, 3) = info.MapString<double>("1", 4);
dataset(4, 4) = info.MapString<double>("0", 4);
dataset(4, 5) = info.MapString<double>("2", 4);
// Print the dataset with mapped categories.
dataset.print("Dataset with mapped categories");
@@ -277,10 +311,8 @@ for (size_t i = 0; i < info.NumMappings(2); ++i)
<< std::endl;
}
// Save as a CSV. Note that this will look the same as the comment at the start
// of this example!
mlpack::data::Save("manual_categorical_data.csv", dataset, info);
// Now `dataset` is ready for use with an mlpack algorithm that supports
// categorical data.
```
---
@@ -298,31 +330,39 @@ Supported formats for saving are `jpg`, `png`, `tga`, `bmp`, and `hdr`.
When loading images, each image is represented as a flattened single column
vector in a data matrix; each row of the resulting vector will correspond to a
single pixel value in a single channel. An auxiliary `ImageInfo` class is used
to store information about the images.
single pixel value in a single channel. An auxiliary `data::ImageInfo` class is
used to store information about the images.
### `ImageInfo`
### `data::ImageInfo`
The `ImageInfo` class contains the metadata of the images.
The `data::ImageInfo` class contains the metadata of the images.
- `info = ImageInfo()`
* Create an `ImageInfo` object with no data.
* Use this constructor if you intend to populate the `DatasetInfo` via a
---
#### Constructors
- `info = data::ImageInfo()`
* Create a `data::ImageInfo` object with no data.
* Use this constructor if you intend to populate the `data::ImageInfo` via a
`data::Load()` call.
- `info = ImageInfo(width, height, channels)`
* Create an `ImageInfo` object with the given image specifications.
- `info = data::ImageInfo(width, height, channels)`
* Create a `data::ImageInfo` object with the given image specifications.
* `width` and `height` are specified as pixels.
- `info.Quality(q)` will set the compression quality (e.g. for saving JPEGs) to
`q`.
---
#### Accessing and modifying image metadata
- `info.Quality() = q` will set the compression quality (e.g. for saving JPEGs)
to `q`.
* `q` should take values between `0` and `100`.
* The quality value is ignored unless calling `data::Save()` with `info`.
- Calling `info.Channels(1)` before loading will cause images to be loaded in
grayscale.
- Calling `info.Channels() = 1` before loading will cause images to be loaded
in grayscale.
- Metadata stored in the `ImageInfo()` can be accessed with the following
- Metadata stored in the `data::ImageInfo` can be accessed with the following
members:
* `info.Width()` returns the image width in pixels.
* `info.Height()` returns the image height in pixels.
@@ -332,53 +372,76 @@ The `ImageInfo` class contains the metadata of the images.
---
With an `ImageInfo` object, image data can be loaded or saved, handling either
one or multiple images at a time:
### Loading images
With a `data::ImageInfo` object, image data can be loaded or saved, handling
either one or multiple images at a time:
<!-- TODO: add parameter to force use of what's in `info` -->
- `data::Load(filename, matrix, info, fatal=false)`
* Load a *single image* from `filename` into `matrix`.
* Format is chosen by extension (e.g. `image.png` will load as PNG).
* Load a ***single image*** from `filename` into `matrix`.
- Format is chosen by extension (e.g. `image.png` will load as PNG).
* `matrix` will have one column representing the image as a flattened vector.
* `info` will be populated with information from the image in `filename`.
* If `fatal` is `true`, a `std::runtime_error` will be thrown upon load
failure.
* Returns a `bool` indicating the success of the operation.
---
- `data::Load(files, matrix, info, fatal=false)`
* Load *multiple images* from `files` into `matrix`.
* `files` is of type `std::vector<std::string>` and should contain the list
of images to be loaded.
* `matrix` will have `files.size()` columns, each representing the
corresponding image as a flattened vector.
* Load ***multiple images*** from `files` into `matrix`.
- `files` is of type `std::vector<std::string>` and should contain the list
of images to be loaded.
- `matrix` will have `files.size()` columns, each representing the
corresponding image as a flattened vector.
* `info` will be populated with information from the images in `files`.
* If `fatal` is `true`, a `std::runtime_error` will be thrown if any files
fail to load.
* Returns a `bool` indicating the success of the operation.
---
- `data::Save(filename, matrix, info, fatal=false)`
* Save a *single image* from `matrix` into the file `filename`.
* Format is chosen by extension (e.g. `image.png` will save as PNG).
* Save a ***single image*** from `matrix` into the file `filename`.
- Format is chosen by extension (e.g. `image.png` will save as PNG).
* `matrix` is expected to have only one column representing the image as a
flattened vector.
* If `fatal` is `true`, a `std::runtime_error` will be thrown in the event of
save failure.
* Returns a `bool` indicating the success of the operation.
---
- `data::Save(files, matrix, info, fatal=false)`
* Save *multiple images* from `matrix` into `files`.
* `files` is of type `std::vector<std::string>` and should contain the list
of files to save to.
* The format of each file is chosen by extension (e.g. `image.png` will save
as PNG); it is allowed for filenames in `files` to have different
extensions.
* Save ***multiple images*** from `matrix` into `files`.
- `files` is of type `std::vector<std::string>` and should contain the list
of files to save to.
- The format of each file is chosen by extension (e.g. `image.png` will
save as PNG); it is allowed for filenames in `files` to have different
extensions.
* `matrix` is expected to have `files.size()` columns representing images as
flattened vectors.
* If `fatal` is `true`, a `std::runtime_error` will be thrown if any images
fail to save.
* Returns a `bool` indicating the success of the operation.
---
Images are flattened along rows, with channel values interleaved, starting from
the top left. Thus, the value of the pixel at position `(x, y)` in channel `c`
will be contained in element/row `y * (width * channels) + x * (channels) + c`
@@ -412,7 +475,7 @@ std::cout << matrix[index] << "." << std::endl;
// Increment each pixel value, but make sure they are still within the bounds.
matrix += 1;
matrix.clamp(0, 255);
matrix = arma::clamp(matrix, 0, 255);
mlpack::data::Save("numfocus-logo-mod.png", matrix, info);
```
@@ -434,7 +497,7 @@ images.push_back("ensmallen-favicon.png");
images.push_back("armadillo-favicon.png");
images.push_back("bandicoot-favicon.png");
ImageInfo info;
mlpack::data::ImageInfo info;
info.Channels(1); // Force loading in grayscale.
arma::mat matrix;
@@ -449,7 +512,7 @@ std::cout << "Loaded " << matrix.n_cols << " images. Images are of size "
matrix = (255.0 - matrix);
// Save as compressed JPEGs with low quality.
info.Quality(75);
info.Quality() = 75;
std::vector<std::string> outImages;
outImages.push_back("mlpack-favicon-inv.jpeg");
outImages.push_back("ensmallen-favicon-inv.jpeg");
@@ -469,21 +532,25 @@ Each object must be given a logical name.
- `data::Load(filename, name, object, fatal=false, format=data::format::autodetect)`
- `data::Save(filename, name, object, fatal=false, format=data::format::autodetect)`
* Load/save `object` to/from `filename` with the logical name `name`.
* If `fatal` is `true`, a `std::runtime_error` will be thrown in the event of
load or save failure.
* The format is autodetected based on extension (`.bin`, `.json`, or `.xml`),
but can be manually specified:
- `data::format::binary`: binary blob (smallest and fastest). No checks;
assumes all data is correct.
- `data::format::json`: JSON.
- `data::format::xml`: XML (largest and slowest).
* For JSON and XML types, when loading, `name` must match the name used to
save the object.
* Returns a `bool` indicating the success of the operation.
***Note:*** when loading an object that was saved as a binary blob, the C++ type
of the object must be *exactly the same* (including template parameters) as the
type used to save the object. If not, undefined behavior will occur---most
of the object must be ***exactly the same*** (including template parameters) as
the type used to save the object. If not, undefined behavior will occur---most
likely a crash.
---
@@ -526,19 +593,26 @@ mlpack classifiers and other algorithms require labels to be in the range `0` to
`numClasses - 1`. A vector of labels with arbitrary (`size_t`) values can be
normalized to the required range with the `NormalizeLabels()` function.
* `NormalizeLabels(labelsIn, labelsOut, mappings)`
---
* `data::NormalizeLabels(labelsIn, labelsOut, mappings)`
- Map vector `labelsIn` into the range `0` to `numClasses - 1`, storing as
`labelsOut` (of type `arma::Row<size_t>`).
- `numClasses` is automatically detected using the number of unique values
in `labelsIn`.
* `numClasses` is automatically detected using the number of unique values
in `labelsIn`.
- The column vector `mappings` will be filled with the reverse mappings to
convert back to the old labels; this can be used by `RevertLabels()`.
- `mappings[i]` contains the original class label for the mapped label `i`.
* `RevertLabels(labelsIn, mappings, labelsOut)`
---
* `data::RevertLabels(labelsIn, mappings, labelsOut)`
- Unmap normalized labels `labelsIn` using `mappings` into `labelsOut`.
- Performs the reverse operation of `NormalizeLabels()`.
- `mappings` should be the same vector output by `NormalizeLabels()`.
- Performs the reverse operation of `NormalizeLabels()`; `mappings` should
be the same vector output by `NormalizeLabels()`.
---
@@ -557,18 +631,18 @@ arma::Row<size_t> labels = { 3, 7, 3, 3, 5 };
// We will map them to that range using NormalizeLabels().
arma::Row<size_t> mappedLabels;
arma::Col<size_t> mappings;
NormalizeLabels(labels, mappedLabels, mapping);
mlpack::data::NormalizeLabels(labels, mappedLabels, mappings);
const size_t numClasses = mappedLabels.max() + 1;
// Print the mapped values:
// [3, 7, 3, 3, 5] maps to [0, 1, 0, 0, 2].
// The `mappings` vector will be [3, 7, 5].
std::cout << "Original labels: " << labels;
std::cout << "Mapped labels: " << mappedLabels;
std::cout << "Mapped labels: " << mappedLabels;
std::cout << "Mappings: " << mappings;
// Learn a model with the mapped labels.
DecisionTree d(dataset, mappedLabels, numClasses);
mlpack::DecisionTree d(dataset, mappedLabels, numClasses, 1 /* leaf size */);
// Make predictions on the training dataset.
arma::Row<size_t> mappedPredictions;
@@ -577,13 +651,13 @@ d.Classify(dataset, mappedPredictions);
// The predictions use mapped labels (0, 1, 2), which we will need to map back
// to the original labels using RevertLabels().
arma::Row<size_t> predictions;
RevertLabels(mappedPredictions, mappings, predictions);
mlpack::data::RevertLabels(mappedPredictions, mappings, predictions);
// Print the predictions before and after unmapping.
// The mapped predictions will take values 0, 1, or 2; the predictions will take
// values 3, 7, or 5 (like the original data).
std::cout << "Mapped predictions: " << mappedPredictions;
std::cout << "Predictions: " << predictions;
std::cout << "Predictions: " << predictions;
```
## Formats
@@ -591,34 +665,49 @@ std::cout << "Predictions: " << predictions;
mlpack's `data::Load()` and `data::Save()` functions support a variety of
different formats in different contexts.
* [Numeric data](#numeric-data)
- By default, load/save format is autodetected, but can be manually specified
with the `format` parameter using one of the options below:
* `FileType::AutoDetect` (default): auto-detects the format as one of the
formats below using the extension of the filename and inspecting the file
contents.
* `FileType::CSVASCII` (autodetect extensions `.csv`, `.tsv`): CSV format
with no header.
* `FileType::RawASCII` (autodetect extensions `.csv`, `.txt`):
space-separated values or tab-separated values (TSV) with no header.
* `FileType::ArmaASCII` (autodetect extension `.txt`): space-separated
values as saved by Armadillo with the
[`arma_ascii`](https://arma.sourceforge.net/docs.html#save_load_mat)
format.
* `FileType::CoordASCII` (not autodetected, must be manually specified):
coordinate list format for sparse data (see
[`coord_ascii`](https://arma.sourceforge.net/docs.html#save_load_mat)).
* `FileType::ArmaBinary` (autodetect extension `.bin`): Armadillo's
efficient binary matrix format
([`arma_binary`](https://arma.sourceforge.net/docs.html#save_load_mat)).
* `FileType::HDF5Binary` (autodetect extensions `.h5`, `.hdf5`, `.hdf`,
`.he5`): [HDF5](https://en.wikipedia.org/wiki/Hierarchical_Data_Format)
binary format; only available if Armadillo is configured with
[HDF5 support](https://arma.sourceforge.net/docs.html#config_hpp).
* `FileType::RawBinary` (autodetect extension `.bin`): packed binary data
with no header and no size information; data will be loaded as a single
column vector _(not recommended)_.
* `FileType::PGMBinary` (autodetect extension `.pgm`): PGM image format
---
#### [Numeric data](#numeric-data)
By default, load/save format is ***autodetected***, but can be manually
specified with the `format` parameter using one of the options below:
- `FileType::AutoDetect` (default): auto-detects the format as one of the
formats below using the extension of the filename and inspecting the file
contents.
- `FileType::CSVASCII` (autodetect extensions `.csv`, `.tsv`): CSV format
with no header.
- `FileType::RawASCII` (autodetect extensions `.csv`, `.txt`):
space-separated values or tab-separated values (TSV) with no header.
- `FileType::ArmaASCII` (autodetect extension `.txt`): space-separated
values as saved by Armadillo with the
[`arma_ascii`](https://arma.sourceforge.net/docs.html#save_load_mat)
format.
- `FileType::CoordASCII` (not autodetected, must be manually specified):
coordinate list format for sparse data (see
[`coord_ascii`](https://arma.sourceforge.net/docs.html#save_load_mat)).
- `FileType::ArmaBinary` (autodetect extension `.bin`): Armadillo's
efficient binary matrix format
([`arma_binary`](https://arma.sourceforge.net/docs.html#save_load_mat)).
- `FileType::HDF5Binary` (autodetect extensions `.h5`, `.hdf5`, `.hdf`,
`.he5`): [HDF5](https://en.wikipedia.org/wiki/Hierarchical_Data_Format)
binary format; only available if Armadillo is configured with
[HDF5 support](https://arma.sourceforge.net/docs.html#config_hpp).
- `FileType::RawBinary` (autodetect extension `.bin`): packed binary data
with no header and no size information; data will be loaded as a single
column vector _(not recommended)_.
- `FileType::PGMBinary` (autodetect extension `.pgm`): PGM image format
***Notes:***
- ASCII formats (`CSVASCII`, `RawASCII`, `ArmaASCII`) are human-readable but
large; to reduce dataset size, consider a binary format such as
`ArmaBinary` or `HDF5Binary`.
@@ -626,30 +715,44 @@ different formats in different contexts.
binary format (`ArmaBinary` or `HDF5Binary`) or as a coordinate list
(`CoordASCII`).
* [Mixed categorical data](#mixed-categorical-data)
- The format of mixed categorical data is detected automatically based on the
file extension and inspecting the file contents:
* `.csv`, `.txt`, or `.tsv` indicates CSV/TSV/ASCII format
* `.arff` indicates [ARFF](https://www.cs.waikato.ac.nz/~ml/weka/arff.html)
---
* [Image data](#image-data)
- The format of images are detected automatically based on the file
extension.
- The following formats are supported for loading: `.jpg`, `.jpeg`, `.png`,
`.tga`, `.bmp`, `.psd`, `.gif`, `.hdr`, `.pic`, `.pnm`
- The following formats are supported for saving: `.jpg`, `.png`, `.tga`,
`.bmp`, `.hdr`
#### [Mixed categorical data](#mixed-categorical-data)
* [mlpack objects](#mlpack-objects)
- By default, load/save format for mlpack objects is autodetected, but can be
manually specified with the `format` parameter using one of the options
below:
* `format::autodetect` (default): auto-detects the format as one of the
formats below using the extension of the filename
* `format::json` (autodetect extension `.json`)
* `format::xml` (autodetect extension `.xml`)
* `format::binary` (autodetect extension `.bin`)
- `format::json` (`.json`) and `format::xml` (`.xml`) produce human-readable
files, but they may be quite large.
- `format::binary` (`.bin`) is recommended for the sake of size; objects in
binary format may be an order of magnitude or more smaller than JSON!
The format of mixed categorical data is detected automatically based on the
file extension and inspecting the file contents:
- `.csv`, `.txt`, or `.tsv` indicates CSV/TSV/ASCII format
- `.arff` indicates [ARFF](https://www.cs.waikato.ac.nz/~ml/weka/arff.html)
---
#### [Image data](#image-data)
The format of images are detected automatically based on the file extension.
- The following formats are supported for loading: `.jpg`, `.jpeg`, `.png`,
`.tga`, `.bmp`, `.psd`, `.gif`, `.hdr`, `.pic`, `.pnm`
- The following formats are supported for saving: `.jpg`, `.png`, `.tga`,
`.bmp`, `.hdr`
---
#### [mlpack objects](#mlpack-objects)
By default, load/save format for mlpack objects is autodetected, but can be
manually specified with the `format` parameter using one of the options below:
- `format::autodetect` (default): auto-detects the format as one of the
formats below using the extension of the filename
- `format::json` (autodetect extension `.json`)
- `format::xml` (autodetect extension `.xml`)
- `format::binary` (autodetect extension `.bin`)
***Notes:***
- `format::json` (`.json`) and `format::xml` (`.xml`) produce human-readable
files, but they may be quite large.
- `format::binary` (`.bin`) is recommended for the sake of size; objects in
binary format may be an order of magnitude or more smaller than JSON!
+40 -37
View File
@@ -1,14 +1,23 @@
# Matrices in mlpack
mlpack uses Armadillo matrices for matrix support. Armadillo is a fast C++
matrix library which makes use of advanced template metaprogramming techniques
to provide the fastest possible linear algebra operations.
mlpack uses Armadillo matrices for linear algebra support. Armadillo is a fast
C++ matrix library which uses advanced template metaprogramming techniques to
provide the fastest possible linear algebra operations.
Documentation on Armadillo can be found on [the Armadillo
<center><p><img src="https://arma.sourceforge.net/img/armadillo_logo2.png" alt="Armadillo logo"></p></center>
Detailed documentation on Armadillo can be found on [the Armadillo
website](http://arma.sourceforge.net/docs.html).
Nonetheless, there are a few further caveats for mlpack Armadillo usage.
* [An Armadillo primer](#an-armadillo-primer)
* [Representing data in mlpack](#representing-data-in-mlpack)
* [Loading data](#loading-data)
* [Loading and using categorical data](#loading-and-using-categorical-data)
* [Alternate matrix types](#alternate-matrix-types)
* [Adapting from other toolkits (Eigen, etc.)](#adapting-from-other-toolkits-eigen-etc)
## An Armadillo primer
The Armadillo syntax is straightforward and is aimed at ease-of-use and
@@ -20,15 +29,15 @@ matrix operations.
// Create a 10x15 matrix with random elements.
arma::mat m(10, 15, arma::fill::randu);
std::cout << "Size of m: " << x.n_rows << " x " << x.n_cols << "." << std::endl;
std::cout << "Size of m: " << m.n_rows << " x " << m.n_cols << "." << std::endl;
// Sum all elements in the matrix.
const double sumVal = arma::accu(m);
std::cout << "Sum of all elements: " << sumVal << "." << std::endl;
// Sum the elements in each column.
arma::vec sums = arma::sum(m, 0);
std::cout << "Sums in each column: " << sums.t();
arma::rowvec sums = arma::sum(m, 0);
std::cout << "Sums in each column: " << sums;
// Add 1 to all elements.
m += 1;
@@ -50,16 +59,16 @@ For more information on Armadillo, see the following resources:
## Representing data in mlpack
Armadillo matrices, unlike numpy and some other toolkits, stores data in a
*column-major* format. This means that each column is located in contiguous
Armadillo matrices, unlike numpy and some other toolkits, store data in a
***column-major*** format. This means that each column is located in contiguous
memory; i.e., `x(0, 0)` is adjacent to `x(1, 0)` in memory.
This means that, for the vast majority of machine learning methods, it is faster
to store _observations as columns_ and _dimensions as rows_. This is counter to
most standard machine learning texts! It also has some implications for linear
algebra operations; for instance, computing the Gram matrix of a matrix `X` is
typically expressed as `X^T X`, but when using column-major matrices, the
expression must be `X X^T`.
to store ***observations as columns*** and ***dimensions as rows***. This is
counter to most standard machine learning texts! It also has some implications
for linear algebra operations; for instance, computing the Gram matrix of a
matrix `X` is typically expressed as `X^T X`, but when using column-major
matrices, the expression must be `X X^T`.
In general, the following Armadillo types are commonly used inside mlpack:
@@ -77,11 +86,8 @@ In general, the following Armadillo types are commonly used inside mlpack:
mlpack provides two simple functions for loading and saving data matrices in a
column-major form:
* `data::Load(filename, matrix, fatal=false, transpose=true,
type=FileType::AutoDetect)` ([full documentation](load_save.md#numeric_data))
* `data::Save(filename, matrix, fatal=false, transpose=true,
type=FileType::AutoDetect)` ([full documentation](load_save.md#numeric_data))
* `data::Load(filename, matrix, fatal=false, transpose=true, type=FileType::AutoDetect)` ([full documentation](load_save.md#numeric_data))
* `data::Save(filename, matrix, fatal=false, transpose=true, type=FileType::AutoDetect)` ([full documentation](load_save.md#numeric_data))
As an example, consider the following CSV file:
@@ -117,11 +123,11 @@ mlpack::data::Load("data.csv", m, true);
// - each row corresponds to a dimension!
//
std::cout << "The matrix in 'data.csv' has: " << std::endl;
std::cout << " - " << data.n_cols << " points." << std::endl;
std::cout << " - " << data.n_rows << " dimensions." << std::endl;
std::cout << " - " << m.n_cols << " points." << std::endl;
std::cout << " - " << m.n_rows << " dimensions." << std::endl;
std::cout << "The second point in the dataset: " << std::endl;
std::cout << data.col(1).t();
std::cout << m.col(1).t();
// Now modify the matrix and save to a different format (space-separated
// values).
@@ -131,25 +137,21 @@ mlpack::data::Save("data-mod.txt", m);
Although Armadillo does provide a `.load()` and `.save()` member function for
matrices, the `data::Load()` and `data::Save()` functions offer additional
flexibility, and ensure that data is loaded in a column-major format.
flexibility, and ensure that data is saved and loaded in a column-major format.
## Loading and using categorical data
Some mlpack techniques support mixed categorical data, e.g., data where some
dimensions take only categorical values (e.g. `0`, `1`, `2`, etc.). String data
and other non-numerical data can be represented as categorical values, and
mlpack has support to load and save mixed categorical data:
mlpack has support to load mixed categorical data:
* The `data::DatasetInfo` auxiliary class stores information about whether each
dimension is numeric or categorical. ([full
documentation](load_save.md#dataset_info))
* `data::Load(filename, matrix, info, fatal=false, transpose=true)` ([full
documentation](load_save.md#load_categorical))
* `data::Save(filename, matrix, info, fatal=false, transpose=true)` ([full
documentation](load_save.md#save_categorical))
For example, consider the following CSV file that contains strings:
```sh
@@ -170,7 +172,8 @@ $ cat mixed_string_data.csv
```
The following program will load the data file, print information about
categorical dimensions, then save categorical data back to disk.
categorical dimensions, and prepare the data for use with an mlpack algorithm
that supports mixed categorical data.
```c++
// Load data from `mixed_string_data.csv` into `m`. Throw an exception on
@@ -181,7 +184,7 @@ mlpack::data::Load("mixed_string_data.csv", m, info, true);
// Print information about the data.
std::cout << "The matrix in 'mixed_string_data.csv' has: " << std::endl;
std::cout << " - " << data.n_cols << " points." << std::endl;
std::cout << " - " << m.n_cols << " points." << std::endl;
std::cout << " - " << info.Dimensionality() << " dimensions." << std::endl;
// Print which dimensions are categorical.
@@ -198,14 +201,12 @@ for (size_t d = 0; d < info.Dimensionality(); ++d)
// Note that we manually map the string values; MapString() returns the category
// for a given value.
m(0, 2) = 4;
m(1, 2) = info.MapString("wonderful", 1); // Creates a new third category.
m(1, 2) = info.MapString<double>("wonderful", 1); // Create new third category.
m(2, 2) = 1;
m(3, 2) = info.MapString("c", 1);
m(3, 2) = info.MapString<double>("c", 1);
m(4, 2) = 0;
// Save the modified matrix. Note that "wonderful" will be automatically
// unmapped by `data::Save()`, as well as all other categorical values.
mlpack::data::Save("mixed_string_data_mod.csv", m, info);
// `m` can now be used with any mlpack algorithm that supports categorical data.
```
Not every mlpack method supports categorical data. Below are the list of
@@ -255,8 +256,10 @@ arma::Row<size_t> labels =
// Train in the constructor, using floating-point data.
// The weak learner type is now a floating-point Perceptron.
typedef Perceptron<SimpleWeightUpdate, ZeroInitialization, arma::fmat>
PerceptronType;
typedef mlpack::Perceptron<
mlpack::SimpleWeightUpdate,
mlpack::ZeroInitialization,
arma::fmat> PerceptronType;
mlpack::AdaBoost<PerceptronType, arma::fmat> ab(dataset, labels, 5);
// Create test data (500 points).