PCA analysis example

In this example, we perform the PCA dimensionality reduction of a spectra dataset

Import the spectrochempy API package

import spectrochempy as scp

Load and inspect the dataset

dataset = scp.read_omnic("irdata/nh4y-activation.spg")[::5]
dataset
NDDataset [nh4y-activation] — float64, shape: (y:11, x:5549), a.u.
name
:
nh4y-activation
author
:
runner@runnervmvrwv9
created
:
2026-07-26 02:31:47+00:00
description
:
Omnic title: NH4Y-activation.SPG
Omnic filename: /home/runner/.spectrochempy/testdata/irdata/nh4y-activation.spg
history
:
2026-07-26 02:31:47+00:00> Imported from spg file /home/runner/.spectrochempy/testdata/irdata/nh4y-activation.spg.
2026-07-26 02:31:47+00:00> Sorted by date
2026-07-26 02:31:47+00:00> Slice extracted: (slice(None, None, 5))
Data
title
:
absorbance
values
:
[[ 2.057 2.061 ... 2.013 2.012]
[ 1.959 1.957 ... 1.672 1.68]
...
[ 1.759 1.761 ... 1.167 1.165]
[ 1.783 1.781 ... 1.189 1.188]] a.u.
shape
:
(y:11, x:5549)
Dimension `x`
size
:
5549
title
:
wavenumbers
coordinates
:
[ 6000 5999 ... 650.9 649.9] cm⁻¹
Dimension `y`
size
:
11
title
:
acquisition timestamp (GMT)
coordinates
:
[1.468e+09 1.468e+09 ... 1.468e+09 1.468e+09] s
labels
:
[[ 2016-07-06 19:03:14+00:00 2016-07-06 19:53:14+00:00 ... 2016-07-07 02:43:15+00:00 2016-07-07 03:33:17+00:00]
[ vz0466.spa, Wed Jul 06 21:00:38 2016 (GMT+02:00) vz0471.spa, Wed Jul 06 21:50:37 2016 (GMT+02:00) ...
vz0512.spa, Thu Jul 07 04:40:39 2016 (GMT+02:00) vz0517.spa, Thu Jul 07 05:30:41 2016 (GMT+02:00)]]


plot pca spec

PCA on the full spectral range

Create a PCA object and fit the dataset so that the explained variance is greater or equal to 99.9%

pca = scp.PCA(n_components=0.999)
_ = pca.fit(dataset)

The number of fitted components is given by the n_components attribute (We obtain 23 components)

6

Transform the dataset to a lower dimensionality using all the fitted components

NDDataset [nh4y-activation_PCA.transform] — float64, shape: (y:11, k:6)
name
:
nh4y-activation_PCA.transform
author
:
runner@runnervmvrwv9
created
:
2026-07-26 02:31:47+00:00
history
:
2026-07-26 02:31:47+00:00> Created using method PCA.transform
Data
title
:
values
:
[[ 71.56 -16.87 ... -0.006776 0.216]
[ 50.39 8.205 ... 0.5566 -0.03804]
...
[ -26.25 -1.694 ... 0.1281 0.6077]
[ -25.46 -1.456 ... 4.175 -0.7883]]
shape
:
(y:11, k:6)
Dimension `k`
size
:
6
title
:
components
labels
:
[ PC1 PC2 PC3 PC4 PC5 PC6]
Dimension `y`
size
:
11
title
:
acquisition timestamp (GMT)
coordinates
:
[1.468e+09 1.468e+09 ... 1.468e+09 1.468e+09] s
labels
:
[[ 2016-07-06 19:03:14+00:00 2016-07-06 19:53:14+00:00 ... 2016-07-07 02:43:15+00:00 2016-07-07 03:33:17+00:00]
[ vz0466.spa, Wed Jul 06 21:00:38 2016 (GMT+02:00) vz0471.spa, Wed Jul 06 21:50:37 2016 (GMT+02:00) ...
vz0512.spa, Thu Jul 07 04:40:39 2016 (GMT+02:00) vz0517.spa, Thu Jul 07 05:30:41 2016 (GMT+02:00)]]


Display the results graphically

First we can set some preferences for the plot

prefs = scp.preferences
prefs.lines.markersize = 7

# ScreePlot
_ = pca.plot_scree()
Scree plot

Score Plot first we can set some preferences for the plot

plot pca spec

Score Plot for 3 PC’s in 3D

_ = pca.plot_score(components=(1, 2, 3))
plot pca spec

Displays 4 loadings

_ = pca.loadings[:4].plot(legend=True)
plot pca spec

Mask the saturated region and refit

Here we do a masking of the saturated region between 882 and 1280 cm^-1

dataset[
    :, 882.0:1280.0
] = scp.MASKED  # remember: use float numbers for slicing (not integer)
_ = dataset.plot()
plot pca spec

Apply the PCA model

pca = scp.PCA(n_components=0.999)
_ = pca.fit(dataset)
pca.n_components
3

As seen above, now only 4 components instead of 23 are necessary to 99.9% of explained variance.

Scree plot

Displays the loadings

_ = pca.loadings.plot(legend=True)
plot pca spec

Let’s plot the scores

plot pca spec

Label the score plot with custom labels

Our dataset has already two columns of labels for the spectra but there are a bit too long for display on plots.

array([[  2016-07-06 19:03:14+00:00,   vz0466.spa, Wed Jul 06 21:00:38 2016 (GMT+02:00)],
       [  2016-07-06 19:53:14+00:00,   vz0471.spa, Wed Jul 06 21:50:37 2016 (GMT+02:00)],
       ...,
       [  2016-07-07 02:43:15+00:00,   vz0512.spa, Thu Jul 07 04:40:39 2016 (GMT+02:00)],
       [  2016-07-07 03:33:17+00:00,   vz0517.spa, Thu Jul 07 05:30:41 2016 (GMT+02:00)]], shape=(11, 2), dtype=object)

So we define some short labels for each component, and add them as a third column:

labels = [lab[:6] for lab in dataset.y.labels[:, 1]]
scores.y.labels = labels  # Note this does not replace previous labels,
# but adds a column.

Display the labeled score plot

Labels are now placed automatically using the adjustText library, which provides collision avoidance between labels and markers. Install adjustText with pip install adjustText for best results; without it, labels are still shown with a simple offset from markers.

_ = pca.plot_score(scores=scores, show_labels=True, labels_column=2)
plot pca spec

This ends the example ! The following line can be uncommented if no plot shows when running the .py script with python

# scp.show()

Total running time of the script: (0 minutes 1.905 seconds)