TensorProductBasis

Tensor product of marginal smooth bases (te()-style interaction smooth).

Usage

Source

TensorProductBasis(marginals)

A tensor product smooth builds a multivariate smooth function of two or more covariates out of one-dimensional (or otherwise lower-dimensional) marginal smooths, one per covariate, by taking the row-wise outer product of their basis matrices. This is the standard way to represent an interaction between covariates that are measured on very different scales or units (e.g. a spatial coordinate combined with time, or a covariate in meters combined with one in years) — unlike an isotropic basis such as TPRS, which assumes all covariates share a common notion of distance, a tensor product smooth applies a separate marginal penalty (and, in principle, a separate smoothing parameter) to each covariate direction, so that the anisotropic scaling of the covariates does not distort the fitted surface. Choose TensorProductBasis over TPRS whenever the covariates involved are not naturally on comparable scales, and use TensorInteractionBasis instead when a decomposition into separate main-effect and pure-interaction terms (an ANOVA-style model) is wanted.

Parameters

marginals: list[SmoothBasis]
List of (typically unfitted) marginal basis objects, one per covariate dimension to be combined, e.g. [TPRS(k=10), TPRS(k=8)] for a bivariate smooth. Each marginal is fit independently to its own column of x inside fit(). At least 2 marginals are required; for a single covariate, use the marginal basis directly instead of wrapping it in a tensor product.

Notes

Given d marginal bases with basis matrices B_1, \ldots, B_d (each B_j of shape (n, k_j)), the tensor product basis matrix is the row-wise Kronecker product

\mathbf{B}[i, :] = \mathbf{B}_1[i, :] \otimes \mathbf{B}_2[i, :] \otimes \cdots \otimes \mathbf{B}_d[i, :], \qquad i = 1, \ldots, n,

which has k = k_1 k_2 \cdots k_d columns in total — every combination of one marginal basis function from each dimension. This basis represents all smooth functions expressible as sums of products of the marginal bases, including both pure main effects and their interaction, so unlike TensorInteractionBasis, no separate main-effect terms need to be added to the model for identifiability of low-order structure (though it is common practice in mgcv-style formulas to do so anyway for a cleaner ANOVA decomposition). For each marginal direction j with own penalty S_j, the tensor product carries one whole-basis penalty per marginal direction,

\mathbf{S}_j^{\text{tensor}} = \mathbf{I}_{k_1} \otimes \cdots \otimes \mathbf{I}_{k_{j-1}} \otimes \mathbf{S}_j \otimes \mathbf{I}_{k_{j+1}} \otimes \cdots \otimes \mathbf{I}_{k_d},

returned in order by penalty_matrices(); penalty_matrix() sums these into a single matrix only for compatibility with the base SmoothBasis interface — for a proper anisotropic fit (one smoothing parameter per marginal direction), use penalty_matrices() directly rather than penalty_matrix(). The null-space dimension of the combined penalty is the product of the marginal null-space dimensions, M = M_1 \cdot M_2 \cdots M_d (the multivariate polynomials that are simultaneously in the null space of every marginal penalty). Because k grows multiplicatively with the number of marginals and their individual sizes, tensor products become expensive quickly in more than two or three dimensions; for higher-dimensional smooths of covariates on comparable scales, an isotropic basis such as TPRS is usually preferable.

Examples

import numpy as np
from whittaker.smooths.tensor import TensorProductBasis
from whittaker.smooths.tprs import TPRS

rng = np.random.default_rng(0)
x = rng.uniform(0, 1, (100, 2))

basis = TensorProductBasis([TPRS(k=6), TPRS(k=5)]).fit(x)
B = basis.basis_matrix(x)
penalties = basis.penalty_matrices()
B.shape, len(penalties)
((100, 30), 2)

Attributes

Name Description
marginals The list of marginal basis objects, fitted after fit() is called.
n_basis Total number of basis functions.

marginals

The list of marginal basis objects, fitted after fit() is called.

marginals: list[SmoothBasis]

Each marginal is fit independently to its own covariate column; their basis matrices are combined via the row-wise Kronecker product to form basis_matrix().


n_basis

Total number of basis functions.

n_basis: int

Equal to the product k_1 * k_2 * ... * k_d of the marginal basis dimensions, since every combination of one marginal basis function from each dimension contributes one column of the tensor product basis matrix.

Methods

Name Description
basis_matrix() Evaluate the tensor product basis at x.
fit() Fit each marginal basis to its corresponding column of x.
identifiability_constraints() Return a sum-to-zero constraint on the tensor product basis, if derivable.
null_space_dimension() Return the product of the marginal null-space dimensions.
penalty_matrices() Return one penalty matrix per marginal direction.
penalty_matrix() Sum of all marginal penalty matrices, for single-penalty compatibility.

basis_matrix()

Evaluate the tensor product basis at x.

Usage

Source

basis_matrix(x)

Builds each marginal’s basis matrix independently and combines them with the row-wise Kronecker (tensor) product, so that column j1 * k_2 * ... * k_d + j2 * k_3 * ... + ... of the result is the product of the corresponding marginal basis function values.

Parameters

x: NDArray
Covariate values, shape (n, d) where d matches the number of marginals.

Returns

NDArray
Design matrix of shape (n, k) where k = self.n_basis is the product of the marginal basis dimensions.

fit()

Fit each marginal basis to its corresponding column of x.

Usage

Source

fit(x)

Parameters

x: NDArray
Training covariates, shape (n, d) where d is the number of marginals. Column j is passed to marginals[j].fit().

Returns

TensorProductBasis
Returns self for method chaining.

Raises

ValueError
If the number of columns in x does not match the number of marginal bases.

identifiability_constraints()

Return a sum-to-zero constraint on the tensor product basis, if derivable.

Usage

Source

identifiability_constraints()

Attempts to recover each marginal’s training covariate values (via a _x_train or _knots attribute) to build a constraint that forces the tensor surface to have mean zero over the training data. If no marginal exposes its training data in a recognized form, no constraint can be derived and None is returned.

Returns

NDArray or None
A (1, k) matrix of the mean basis-function values over the training grid, or None if the training covariates could not be recovered from the marginals.

null_space_dimension()

Return the product of the marginal null-space dimensions.

Usage

Source

null_space_dimension()

The multivariate null space of a tensor product penalty is spanned by the tensor products of each marginal’s own null-space basis functions (e.g. for two thin plate marginals with linear null spaces, the constant, and each marginal’s linear term, giving a bilinear null space), so its dimension multiplies rather than adds across marginals.

Returns

int
M = M_1 * M_2 * ... * M_d.

penalty_matrices()

Return one penalty matrix per marginal direction.

Usage

Source

penalty_matrices()

For d marginals with basis dimensions k_1, ..., k_d and marginal penalties S_1, ..., S_d, penalty j is the Kronecker product I_{k_1} ⊗ ... ⊗ S_j ⊗ ... ⊗ I_{k_d} (the marginal penalty in position j, identity elsewhere), so that penalizing with matrix j alone penalizes exactly the roughness of the tensor surface along covariate direction j, holding the other directions fixed.

Returns

list[NDArray]
List of d matrices, each of shape (k, k) where k is the total basis dimension. Intended to be combined with one smoothing parameter per marginal direction during model fitting.

penalty_matrix()

Sum of all marginal penalty matrices, for single-penalty compatibility.

Usage

Source

penalty_matrix()

This collapses the per-direction penalties returned by penalty_matrices() into one matrix, which is convenient when a caller only supports a single penalty but discards the ability to give each marginal direction its own smoothing parameter. Prefer penalty_matrices() for a proper anisotropic fit.

Returns

NDArray
The (k, k) sum of all per-marginal penalty matrices.