ConvexPSpline

Shape-constrained P-spline: convex or concave.

Usage

Source

ConvexPSpline(
    k=20,
    degree=3,
    m=2,
    concave=False,
)

Uses the same B-spline basis and difference penalty as ~whittaker.smooths.pspline.PSpline, but additionally requires the fitted curve f(x) = \sum_j \beta_j B_j(x) to be convex (or, with concave=True, concave) over the whole domain. As with MonotonePSpline, this is enforced as a linear inequality on the coefficients: for an equally-spaced B-spline basis, the curve is convex whenever the second differences of the coefficients, \Delta^2 \beta_j = \beta_j - 2\beta_{j-1} + \beta_{j-2}, are all non-negative. Use ConvexPSpline (via s(x, bs="cx") for convex or s(x, bs="cv") for concave in a formula) when the relationship is known to have a single bend of consistent curvature — e.g. a cost curve, a learning curve, or a concave production function — and an unconstrained smooth would otherwise produce spurious inflection points from noise.

Parameters

k: int = 20

Number of B-spline basis functions. The default is 20.

degree: int = 3

B-spline polynomial degree. The default is 3 (cubic).

m: int = 2

Difference penalty order. The default is 2.

concave: bool = False
If True, enforce concavity. The default is False (convex).

Notes

As with MonotonePSpline, the constraint is enforced during P-IRLS fitting by projecting the ordinary coefficient update onto the convex (or concave) cone after each iteration: smooth terms whose basis is a ConvexPSpline have their coefficient block passed through project_convex before the next iteration’s linear predictor is formed (see whittaker.fitting.pirls). The projection extends the monotone PAVA projection by one order of differencing: convexity requires the first differences of the coefficients, d_j = \beta_j - \beta_{j-1}, to form a non-decreasing sequence (equivalently, that the second differences of \beta are non-negative), so project_convex computes the first differences, projects them onto the monotone cone with PAVA (see the Notes on MonotonePSpline for the algorithm), and then reconstructs \beta by cumulatively summing the projected differences back up from \beta_0. Concavity is handled by negating the differences before and after the PAVA projection, mirroring decreasing=True for MonotonePSpline.

Examples

import numpy as np
import whittaker as wt

rng = np.random.default_rng(0)
x = np.sort(rng.uniform(-1, 1, 200))
y = x**2 + rng.normal(scale=0.1, size=200)

model = wt.GAM("y ~ s(x, bs='cx')").fit({"x": x, "y": y})

new_x = np.linspace(-1, 1, 50)
fitted = model.predict({"x": new_x}).values
second_diff = np.diff(fitted, n=2)
# Second differences are non-negative up to fitting/projection tolerance.
np.all(second_diff >= -1e-2)
np.True_

Attributes

Name Description
constraint_direction Sign convention used by the second-difference PAVA projection.
constraint_order Order of the difference constraint enforced by projection.

constraint_direction

Sign convention used by the second-difference PAVA projection.

constraint_direction: int

Returns -1 when concave=True (the first differences of the coefficients are negated before and after the PAVA projection, yielding non-positive second differences) or 1 for the default convex case. Consulted by project_convex and by whittaker.fitting.pirls when projecting this term’s coefficient block each iteration.


constraint_order

Order of the difference constraint enforced by projection.

constraint_order: int

Always 2: convexity/concavity is a constraint on the second differences of the coefficients (equivalently, the first differences must form a monotone sequence), as opposed to MonotonePSpline’s first-order (1) constraint.

Methods

Name Description
null_space_dimension() Return the dimension of the basis’s unpenalized null space.

null_space_dimension()

Return the dimension of the basis’s unpenalized null space.

Usage

Source

null_space_dimension()

As with MonotonePSpline, the shape constraint is enforced by post-hoc projection of the coefficients rather than by removing degrees of freedom from the penalty, so this basis reports 0 unpenalized dimensions.

Returns

int
Always 0.