Main types used in the package.

source

Spectra

def Spectra(
    wavenumbers:numpy.ndarray, spectra:numpy.ndarray, measurement_type:str, sample_ids:numpy.ndarray,
    source:object=None
)->None:

Spectra of several samples, measured at the same wavenumbers

Exported source
from dataclasses import dataclass, field, fields
import numpy as np
import pandas as pd
from fastcore.basics import patch, listify
from typing import Union, List, Tuple
Exported source
@dataclass
class Spectra:
    "Spectra of several samples, measured at the same wavenumbers"
    wavenumbers:np.ndarray # Wavenumbers in cm⁻¹, in increasing order
    spectra:np.ndarray # One row per sample, one column per wavenumber
    measurement_type:str # `abs` (absorbance) or `ref` (reflectance)
    sample_ids:np.ndarray # Sample ID of each row of `spectra`
    source:object=field(default=None, repr=False, compare=False) # Object holding the sample properties, such as an `OSSL`

    def __str__(self):
        'Pretty print the Spectra object'
        sections = [
            ("Spectra attributes", f"Available attributes: {', '.join(f.name for f in fields(self) if f.repr)}"),
            
            ("Wavenumbers", 
                f"{np.array2string(self.wavenumbers[:10], precision=2, separator=', ')}\n"
                f"Shape: {self.wavenumbers.shape}"),
            
            ("Spectra", 
                f"{np.array2string(self.spectra[:5,:5], precision=4, separator=', ')}\n"
                f"Shape: {self.spectra.shape}"),
            
            ("Measurement type (Reflectance or Absorbance)", self.measurement_type),
            
            ("Sample IDs", 
                f"{np.array2string(self.sample_ids[:10], separator=', ')}\n"
                f"Total samples: {len(self.sample_ids)}")]
        
        return '\n\n'.join(f"{title}:\n{'-'*len(title)}\n{content}" 
            for title, content in sections)

OSSL.mir, OSSL.visnir and load_spa return a Spectra. Row i of spectra is the spectrum of sample sample_ids[i], measured at wavenumbers. Printing a Spectra shows the start of each field and its shape. Two MIR spectra at three wavenumbers:

sd = Spectra(np.array([600, 602, 604]), np.array([[0.11, 0.12, 0.13], [0.21, 0.22, 0.23]]), 'abs', np.array(['s1', 's2']))
print(sd)
Spectra attributes:
------------------
Available attributes: wavenumbers, spectra, measurement_type, sample_ids

Wavenumbers:
-----------
[600, 602, 604]
Shape: (3,)

Spectra:
-------
[[0.11, 0.12, 0.13],
 [0.21, 0.22, 0.23]]
Shape: (2, 3)

Measurement type (Reflectance or Absorbance):
--------------------------------------------
abs

Sample IDs:
----------
['s1', 's2']
Total samples: 2

Spectra and targets


source

Spectra.xy

def xy(
    target_cols:Union[str, List], # Target column name or names
)->Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]: # Spectra, targets and sample IDs, row by row

Spectra and targets of the samples that have both, for machine learning

Exported source
@patch
def xy(
    self:Spectra,
    target_cols:Union[str, List] # Target column name or names
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: # Spectra, targets and sample IDs, row by row
    "Spectra and targets of the samples that have both, for machine learning"
    targets = self.source[listify(target_cols)].dropna()
    aligned = pd.DataFrame(self.spectra, index=self.sample_ids).join(targets, how='inner')
    n = self.spectra.shape[1]
    return aligned.iloc[:, :n].to_numpy(copy=True), aligned.iloc[:, n:].to_numpy(copy=True), aligned.index.to_numpy()

xy reads the targets from source, which returns a DataFrame indexed by sample ID when indexed with a list of column names. An OSSL and a pd.DataFrame both work. xy keeps the samples that have a value for every target. It returns the spectra X, the targets y and the sample IDs ids, in the same row order. Sample s2 has no clay value:

from fastcore.test import *
props = pd.DataFrame({'clay': [12.0, np.nan], 'sand': [40.0, 35.0]}, index=['s1', 's2'])
sdp = Spectra(sd.wavenumbers, sd.spectra, 'abs', sd.sample_ids, source=props)
X, y, ids = sdp.xy('clay')
test_eq(ids, ['s1'])
assert X.flags.writeable and y.flags.writeable
X, y, ids