nemos.basis.BSplineConv#
- class nemos.basis.BSplineConv(n_basis_funcs, window_size, order=4, label='BSplineConv', conv_kwargs=None)[source]#
Bases:
ConvBasisMixin
,BSplineBasis
B-spline 1-dimensional basis functions.
Implementation of the one-dimensional BSpline basis [1].
- Parameters:
n_basis_funcs (
int
) – Number of basis functions.window_size (
int
) – The window size for convolution in number of samples.order (
int
) – Order of the splines used in basis functions. Must lie within[1, n_basis_funcs]
. The B-splines have (order-2) continuous derivatives at each interior knot. The higher this number, the smoother the basis representation will be.label (
Optional
[str
]) – The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts.conv_kwargs (
Optional
[dict
]) – Additional keyword arguments passed tonemos.convolve.create_convolutional_predictor()
; These arguments are used to change the default behavior of the convolution. For example, changing thepredictor_causality
, which by default is set to"causal"
. Note that one cannot change the default value for theaxis
parameter. Basis assumes that the convolution axis isaxis=0
.
References
Examples
>>> from numpy import linspace >>> from nemos.basis import BSplineConv >>> n_basis_funcs = 5 >>> order = 3 >>> bspline_basis = BSplineConv(n_basis_funcs, order=order, window_size=10) >>> bspline_basis BSplineConv(n_basis_funcs=5, window_size=10, order=3) >>> sample_points = linspace(0, 1, 100) >>> features = bspline_basis.compute_features(sample_points)
Attributes
The convolutional kwargs.
Label for the basis.
Mode of operation, either
"conv"
or"eval"
.Number of basis functions.
Number of features returned by the basis.
Spline order.
Duration of the convolutional kernel in number of samples.
- __init__(n_basis_funcs, window_size, order=4, label='BSplineConv', conv_kwargs=None)[source]#
- Parameters:
n_basis_funcs (int)
window_size (int)
order (int)
label (str | None)
conv_kwargs (dict | None)
Methods
__init__
(n_basis_funcs, window_size[, ...])compute_features
(xi)Convolve basis functions with input time series.
evaluate_on_grid
(n_samples)Evaluate the B-spline basis set on a grid of equi-spaced sample points.
get_params
([deep])From scikit-learn, get parameters by inspecting init.
set_input_shape
(xi)Set the expected input shape for the basis object.
Prepare or compute the convolutional kernel for the basis functions.
set_params
(**params)Set the parameters of this estimator.
setup_basis
(*xi)Set all basis states.
split_by_feature
(x[, axis])Decompose an array along a specified axis into sub-arrays based on the number of expected inputs.
Turn the Basis into a TransformerBasis for use with scikit-learn.
- __add__(other)#
Add two Basis objects together.
- Parameters:
other (
Basis
) – The other Basis object to add.- Returns:
The resulting Basis object.
- Return type:
- __iter__()#
Makes basis iterable. Re-implemented for additive.
- __mul__(other)#
Multiply two Basis objects together.
- Parameters:
other (
Basis
) – The other Basis object to multiply.- Return type:
- Returns:
The resulting Basis object.
- __pow__(exponent)#
Exponentiation of a Basis object.
Define the power of a basis by repeatedly applying the method __multiply__. The exponent must be a positive integer.
- Parameters:
exponent (
int
) – Positive integer exponent- Return type:
- Returns:
The product of the basis with itself “exponent” times. Equivalent to
self * self * ... * self
.- Raises:
TypeError – If the provided exponent is not an integer.
ValueError – If the integer is zero or negative.
- __sklearn_clone__()#
Clone the basis while preserving attributes related to input shapes.
This method ensures that input shape attributes (e.g., _input_shape_product, _input_shape_) are preserved during cloning. Reinitializing the class as in the regular sklearn clone would drop these attributes, rendering cross-validation unusable.
- Return type:
- compute_features(xi)[source]#
Convolve basis functions with input time series.
A bank of basis filters is convolved with the input data. All the dimensions except for the sample-axis are flattened, so that the method always returns a matrix.
For example, if inputs are of shape (num_samples, 2, 3), the output will be
(num_samples, num_basis_funcs * 2 * 3)
.- Parameters:
*xi (ArrayLike) – The input data over which to apply the basis transformation. The samples can be passed as multiple arguments, each representing a different dimension for multivariate inputs.
- Return type:
TsdFrame
|ndarray
[Any
,dtype
[TypeVar
(_ScalarType_co
, bound=generic
, covariant=True)]]
Notes
This method is intended to be 1-to-1 mappable to sklearn
transform
method of transformer. This means that for the method to be callable, all the state attributes have to be pre-computed in a method that is mappable tofit
, which for us is_fit_basis
. It is fundamental that both methods behaves like the corresponding transformer method, with the only difference being the input structure: a single (X, y) pair for the transformer, a number of time series for the Basis.Examples
>>> import numpy as np >>> from nemos.basis import BSplineConv
>>> # Generate data >>> num_samples = 1000 >>> X = np.random.normal(size=(num_samples, )) # raw time series >>> basis = BSplineConv(10, window_size=11) >>> features = basis.compute_features(X) # basis transformed time series >>> features.shape (1000, 10)
- property conv_kwargs#
The convolutional kwargs.
Keyword arguments passed to
nemos.convolve.create_convolutional_predictor()
.
- evaluate_on_grid(n_samples)[source]#
Evaluate the B-spline basis set on a grid of equi-spaced sample points.
- Parameters:
n_samples (
int
) – The number of points in the uniformly spaced grid. A higher number of samples will result in a more detailed visualization of the basis functions.- Return type:
Tuple
[NDArray, NDArray]- Returns:
X – Array of shape
(n_samples,)
containing the equi-spaced sample points where we’ve evaluated the basis.basis_funcs – Raised cosine basis functions, shape
(n_samples, n_basis_funcs)
Notes
The evaluation is performed by looping over each element and using
splev
from SciPy to compute the basis values.Examples
Evaluate and visualize 4 B-spline basis functions of order 3:
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> from nemos.basis import BSplineConv >>> bspline_basis = BSplineConv(n_basis_funcs=4, order=3, window_size=10) >>> sample_points, basis_values = bspline_basis.evaluate_on_grid(100) >>> for i in range(4): ... p = plt.plot(sample_points, basis_values[:, i], label=f'Function {i+1}') >>> plt.title('B-Spline Basis Functions') Text(0.5, 1.0, 'B-Spline Basis Functions') >>> plt.xlabel('Domain') Text(0.5, 0, 'Domain') >>> plt.ylabel('Basis Function Value') Text(0, 0.5, 'Basis Function Value') >>> l = plt.legend()
- get_params(deep=True)#
From scikit-learn, get parameters by inspecting init.
- Parameters:
deep
- Return type:
dict
- Returns:
- out:
A dictionary containing the parameters. Key is the parameter name, value is the parameter value.
- property input_shape: NDArray#
- property label: str#
Label for the basis.
- property mode#
Mode of operation, either
"conv"
or"eval"
.
- property n_basis_funcs#
Number of basis functions.
- property n_output_features: int | None#
Number of features returned by the basis.
Notes
The number of output features can be determined only when the number of inputs provided to the basis is known. Therefore, before the first call to
compute_features
, this property will returnNone
. After that call, or after setting the input shape withset_input_shape
,n_output_features
will be available.
- property order#
Spline order.
Spline order, i.e. the polynomial degree of the spline plus one.
- set_input_shape(xi)[source]#
Set the expected input shape for the basis object.
This method configures the shape of the input data that the basis object expects.
xi
can be specified as an integer, a tuple of integers, or derived from an array. The method also calculates the total number of input features and output features based on the number of basis functions.- Parameters:
xi (int | tuple[int, …] | NDArray) –
The input shape specification. - An integer: Represents the dimensionality of the input. A value of
1
is treated as scalar input. - A tuple: Represents the exact input shape excluding the first axis (sample axis).All elements must be integers.
An array: The shape is extracted, excluding the first axis (assumed to be the sample axis).
- Raises:
ValueError – If a tuple is provided and it contains non-integer elements.
- Returns:
Returns the instance itself to allow method chaining.
- Return type:
self
Notes
All state attributes that depends on the input must be set in this method in order for the API of basis to work correctly. In particular, this method is called by
setup_basis
, which is equivalent tofit
for a transformer. If any input dependent state is not set in this method, thencompute_features
(equivalent tofit_transform
) will break.Examples
>>> import nemos as nmo >>> import numpy as np >>> basis = nmo.basis.BSplineConv(5, 10) >>> # Configure with an integer input: >>> _ = basis.set_input_shape(3) >>> basis.n_output_features 15 >>> # Configure with a tuple: >>> _ = basis.set_input_shape((4, 5)) >>> basis.n_output_features 100 >>> # Configure with an array: >>> x = np.ones((10, 4, 5)) >>> _ = basis.set_input_shape(x) >>> basis.n_output_features 100
- set_kernel()#
Prepare or compute the convolutional kernel for the basis functions.
This method is called to prepare the basis functions for convolution operations in subclasses. It computes a kernel based on the basis functions that will be used for convolution with the input data. The specifics of kernel computation depend on the subclass implementation and the nature of the basis functions.
- Returns:
The instance itself, modified to include the computed kernel. This allows for method chaining and integration into transformation pipelines.
- Return type:
self
Notes
Subclasses implementing this method should detail the specifics of how the kernel is computed and how the input parameters are utilized.
- set_params(**params)#
Set the parameters of this estimator.
The method works on simple estimators as well as on nested objects (such as
Pipeline
). The latter have parameters of the form<component>__<parameter>
so that it’s possible to update each component of a nested object.- Parameters:
**params (dict) – Estimator parameters.
- Returns:
self – Estimator instance.
- Return type:
estimator instance
- setup_basis(*xi)#
Set all basis states.
This method corresponds sklearn transformer
fit
. As fit, it must receive the input and it must set all basis states, i.e.kernel_
and all the states relative to the input shape. The difference between this method and the transformerfit
is in the expected input structure, where the transformerfit
method requires the inputs to be concatenated in a 2D array, while here each input is provided as a separate time series for each basis element.- Parameters:
xi (NDArray) – Input arrays.
- Return type:
- Returns:
The basis with ready for evaluation.
- split_by_feature(x, axis=1)[source]#
Decompose an array along a specified axis into sub-arrays based on the number of expected inputs.
This function takes an array (e.g., a design matrix or model coefficients) and splits it along a designated axis.
How it works:
If the basis expects an input shape
(n_samples, n_inputs)
, then the feature axis length will betotal_n_features = n_inputs * n_basis_funcs
. This axis is reshaped into dimensions(n_inputs, n_basis_funcs)
.If the basis expects an input of shape
(n_samples,)
, then the feature axis length will betotal_n_features = n_basis_funcs
. This axis is reshaped into(1, n_basis_funcs)
.
For example, if the input array
x
has shape(1, 2, total_n_features, 4, 5)
, then after applying this method, it will be reshaped into(1, 2, n_inputs, n_basis_funcs, 4, 5)
.The specified axis (
axis
) determines where the split occurs, and all other dimensions remain unchanged. See the example section below for the most common use cases.- Parameters:
x (NDArray) –
The input array to be split, representing concatenated features, coefficients, or other data. The shape of
x
along the specified axis must match the total number of features generated by the basis, i.e.,self.n_output_features
.Examples:
For a design matrix:
(n_samples, total_n_features)
For model coefficients:
(total_n_features,)
or(total_n_features, n_neurons)
.
axis (int, optional) – The axis along which to split the features. Defaults to 1. Use
axis=1
for design matrices (features along columns) andaxis=0
for coefficient arrays (features along rows). All other dimensions are preserved.
- Raises:
ValueError – If the shape of
x
along the specified axis does not matchself.n_output_features
.- Returns:
A dictionary where:
Key: Label of the basis.
Value: the array reshaped to:
(..., n_inputs, n_basis_funcs, ...)
- Return type:
dict
Examples
>>> import numpy as np >>> from nemos.basis import BSplineConv >>> from nemos.glm import GLM >>> basis = BSplineConv(n_basis_funcs=6, window_size=10, label="two_inputs") >>> X_multi = basis.compute_features(np.random.randn(20, 2)) >>> split_features_multi = basis.split_by_feature(X_multi, axis=1) >>> for feature, sub_dict in split_features_multi.items(): ... print(f"{feature}, shape {sub_dict.shape}") two_inputs, shape (20, 2, 6)
- to_transformer()#
Turn the Basis into a TransformerBasis for use with scikit-learn.
- Return type:
Examples
Jointly cross-validating basis and GLM parameters with scikit-learn.
>>> import nemos as nmo >>> from sklearn.pipeline import Pipeline >>> from sklearn.model_selection import GridSearchCV >>> # load some data >>> X, y = np.random.normal(size=(30, 1)), np.random.poisson(size=30) >>> basis = nmo.basis.RaisedCosineLinearEval(10).set_input_shape(1).to_transformer() >>> glm = nmo.glm.GLM(regularizer="Ridge", regularizer_strength=1.) >>> pipeline = Pipeline([("basis", basis), ("glm", glm)]) >>> param_grid = dict( ... glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), ... basis__n_basis_funcs=(3, 5, 10, 20, 100), ... ) >>> gridsearch = GridSearchCV( ... pipeline, ... param_grid=param_grid, ... cv=5, ... ) >>> gridsearch = gridsearch.fit(X, y)
- property window_size#
Duration of the convolutional kernel in number of samples.