sm::pca

Principal Component Analysis

import sm.pca;

Table of contents

Summary

sm::pca is a Principal Component Analysis namespace. It provides:

sm::pca::compute A function that finds the principal components in a dataset.

sm::pca::transform A function to project your data onto the principal components.

sm::pca::result A class that holds the result returned by pca::compute.

Example usage

To use pca::compute, you need to pack your data either as a ‘vvec of vecs’ or a ‘vec of vvecs’. Suppose you have 3 arrays of data, then first ensure each is an sm::vvec (with a float or double element type) and then pack them in an sm::vec:

sm::vvec<float> d1 = {1,  2,   3,   2};
sm::vvec<float> d2 = {1,  0.9, 0.8, 2};
sm::vvec<float> d3 = {0,  8,   7,   1};

sm::vec<sm::vvec<float>, 3> x;

x[0] = d1;
x[1] = d2;
x[2] = d3;

sm::pca::result<float, 3> my_pca = sm::pca::compute<float, 3> (x);

if (my_pca.error != sm::pca::error_code::no_error) { /* Something went wrong */ }

The return object contains a centered copy of the input data x (but not an original copy of x) along with the principal components, which are stored in

struct result
{
    // ...
    // The principal component unit vectors
    sm::vec<sm::vec<T, N>, N> pc_vectors
    // ...
};

You can output the components like this:

for (std::uint32_t i = 0; i < 3; ++i) {
    std::cout << "PC " << (i + 1) << " = " << my_pca.pc_vectors[i]
              << " accounts for " << my_pca.pc_proportions[i] << " of the variability\n";
}

Note that they are ordered in size; pc_vector[0] is the first principal component, which accounts for the most variability. The magnitude of the component is stored in sm::vec<T, N> pc_magnitudes and the proportions in sm::vec<T, N> pc_proportions.

You use a second function call to project your data onto the principal components. The pca::transform function takes a reference to your result object and computes (and stores, but maybe this design is wrong) the projected points:

sm::pca::transform (my_pca); // Perform the projection

You now have access to the projected data (in my_pca.x_proj).

The result struct

    // Return struct for a principal component analysis with N dimensions of data
    template<typename T, std::uint32_t N> requires std::is_floating_point_v<T>
    struct result
    {
        // A status or error code
        pca::error_code error = pca::error_code::uncomputed; // changes to x_cols_unequal, x_empty or no_error
        // The length of each column of z
        std::uint32_t dsz = 0u;
        // The mean and standard deviation of each dimension of the input data
        sm::vec<sm::vvec<T>, N> mu_sig_x;
        // The input data, after it has been zero-shifted
        sm::vec<sm::vvec<T>, N> z;
        // The covariance matrix of the zero-shifted data
        sm::mat<T, N, N> covariance;
        // The principal component unit vectors
        sm::vec<sm::vec<T, N>, N> pc_vectors;
        // Principal component magnitudes (like the SD of the data in each dimension)
        sm::vec<T, N> pc_magnitudes = {};
        // Principal component proportions (of the variability each component accounts for)
        sm::vec<T, N> pc_proportions = {};
        // This holds the centred input data, projected onto the principal components
        sm::vec<sm::vvec<T>, N> x_proj;
        //... some code omitted
    };

This site uses Just the Docs, a documentation theme for Jekyll.