Preprocessing¶
hqnn_forge.preprocessing ¶
hqnn_forge.preprocessing¶
Classical pre-processing pipeline — PCA dimensionality reduction and feature standardisation — implemented in pure NumPy (no scikit-learn runtime dependency).
Exported symbols
PCANormalizer Fits/applies PCA + per-feature standardisation; returns torch.Tensor. stratified_kfold Fold indices that keep class prevalence. smote SMOTE oversampling of a binary minority class. oversample_fold SMOTE one fold's training rows only; validation rows untouched. iter_folds Stratified folds with fold-safe oversampling. Fold, SmoteResult Result types of the above.
Fold ¶
Bases: NamedTuple
One cross-validation fold with an oversampled training split.
sources
instance-attribute
¶
sources: IntArray
Original-row indices (into the full X) of each synthetic sample's pair.
SmoteResult ¶
Bases: NamedTuple
Oversampled data.
Attributes:
| Name | Type | Description |
|---|---|---|
X, y |
The input rows first, in their original order, followed by the synthetic minority rows. |
|
sources |
IntArray
|
Shape |
PCANormalizer ¶
Fit/apply PCA + per-feature standardisation without scikit-learn.
The fitted arrays (mean_, components_, explained_variance_ and
std_) are set by fit and absent until then, as in scikit-learn;
is_fitted_ exists from construction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_components
|
int | integer
|
Number of principal components to retain. Must be an integer ≥ 1
( |
8
|
scale_to_pi
|
bool
|
If |
True
|
Attributes:
| Name | Type | Description |
|---|---|---|
mean_ |
(ndarray, shape(n_features))
|
Per-feature mean computed during |
components_ |
(ndarray, shape(n_components, n_features))
|
Principal component matrix (rows = eigenvectors, sorted by descending
explained variance). Each row's sign is canonicalised so its
largest-magnitude entry is positive, making |
explained_variance_ |
(ndarray, shape(n_components))
|
Eigenvalues corresponding to retained components. |
std_ |
(ndarray, shape(n_components))
|
Per-component standard deviation (computed on training projections). |
is_fitted_ |
bool
|
|
Notes
Input is converted with np.asarray, so float64 input is used without
copying and fit/transform may hold a view of the caller's buffer for
the duration of the call. Neither method writes into it, and no view of it
is kept in the fitted attributes, so the caller is free to modify or discard
the array afterwards.
Examples:
>>> import numpy as np
>>> from hqnn_forge.preprocessing import PCANormalizer
>>> rng = np.random.default_rng(42)
>>> X_train = rng.standard_normal((1000, 30)) # 1000 samples, 30 raw features
>>> pca = PCANormalizer(n_components=8)
>>> pca.fit(X_train) # returns the fitted normaliser
PCANormalizer(n_components=8, scale_to_pi=True, status=fitted)
>>> X_enc = pca.transform(X_train) # torch.Tensor, shape (1000, 8)
>>> X_enc.shape
torch.Size([1000, 8])
explained_variance_ratio_
property
¶
explained_variance_ratio_: NDArray[float64]
Fraction of total variance explained by each retained component.
Returns:
| Type | Description |
|---|---|
(ndarray, shape(n_components))
|
|
fit ¶
fit(X: ArrayLike) -> PCANormalizer
Compute PCA basis and per-component statistics on training data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ArrayLike
|
Training data array-like of shape |
required |
Returns:
| Type | Description |
|---|---|
self
|
The fitted transformer (for method chaining). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Notes
fit is all-or-nothing: every check above raises before the first
fitted attribute is assigned, so a rejected fit leaves the instance
exactly as it found it. An instance that was already fitted keeps that
fit and stays usable; one that was not stays unfitted.
transform ¶
transform(X: ArrayLike) -> torch.Tensor
Project and standardise (and optionally scale to [-π, π]).
Only statistics learned in fit (mean_, components_,
std_) are used, so each row is encoded independently of the other
rows in X. Standardised output has zero mean and unit variance on
the training data; other data keeps its offset from the training
distribution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ArrayLike
|
Data array-like of shape |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
Encoded tensor of shape |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
ValueError
|
If |
fit_transform ¶
fit_transform(X: ArrayLike) -> torch.Tensor
Fit and transform in a single call (convenience method).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ArrayLike
|
Training data, shape |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
Transformed tensor, shape |
iter_folds ¶
iter_folds(X: ArrayLike, y: ArrayLike, n_splits: int = 5, *, shuffle: bool = True, random_state: int | Generator | None = None, oversample: bool = True, **smote_kwargs: object) -> Iterator[Fold]
Stratified folds, each with its training split oversampled in isolation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ArrayLike
|
Full dataset. |
required |
y
|
ArrayLike
|
Full dataset. |
required |
n_splits
|
int
|
Passed to |
5
|
shuffle
|
int
|
Passed to |
5
|
random_state
|
int
|
Passed to |
5
|
oversample
|
bool
|
Set |
True
|
**smote_kwargs
|
object
|
Passed to |
{}
|
Yields:
| Type | Description |
|---|---|
Fold
|
|
oversample_fold ¶
oversample_fold(X: ArrayLike, y: ArrayLike, train_idx: ArrayLike, val_idx: ArrayLike, **smote_kwargs: object) -> Fold
SMOTE the training rows of one fold; return the validation rows as-is.
Only X[train_idx] is ever passed to smote, so no synthetic
sample can be derived from a validation row.
train_idx and val_idx are integer index arrays or boolean masks
over the rows of X. Negative indices are rejected rather than
interpreted the way NumPy would: -1 names the same row as n - 1
but does not collide with it under a set intersection, so a negative
train_idx would pass the overlap check and then train on exactly the
validation rows -- the leak this module exists to prevent, reported as
safe by Fold.sources.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
smote ¶
smote(X: ArrayLike, y: ArrayLike, *, k_neighbors: int = 5, sampling_ratio: float = 1.0, random_state: int | Generator | None = None) -> SmoteResult
Oversample the minority class of a binary problem with SMOTE.
Each synthetic sample is x + u · (x_nn − x), where x is a minority
sample drawn uniformly, x_nn one of its k_neighbors nearest
minority neighbours (Euclidean, excluding itself), and u ~ U(0, 1).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ArrayLike
|
Features, shape |
required |
y
|
ArrayLike
|
Binary labels, shape |
required |
k_neighbors
|
int
|
Neighbours considered per minority sample. Must be smaller than the minority count. Default: 5. |
5
|
sampling_ratio
|
float
|
Target |
1.0
|
random_state
|
int | Generator | None
|
Seed or generator. |
None
|
Returns:
| Type | Description |
|---|---|
SmoteResult
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
On shape mismatches, non-binary |
stratified_kfold ¶
stratified_kfold(y: ArrayLike, n_splits: int = 5, *, shuffle: bool = True, random_state: int | Generator | None = None) -> list[tuple[IntArray, IntArray]]
Split sample indices into n_splits folds with equal class prevalence.
Each class's indices are (optionally) shuffled and dealt into
n_splits chunks whose sizes differ by at most one; fold k
validates on chunk k of every class and trains on the rest. Every
sample is validated exactly once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
ArrayLike
|
Class labels, shape |
required |
n_splits
|
int
|
Number of folds, at least 2. Default: 5. |
5
|
shuffle
|
bool
|
Shuffle within each class before dealing. Default: True. |
True
|
random_state
|
int | Generator | None
|
Seed or generator for the shuffle. |
None
|
Returns:
| Type | Description |
|---|---|
list of (train_idx, val_idx)
|
Sorted index arrays, one pair per fold. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |