Compute Restricted Cubic Spline (RCS) Basis

Description

Computes the nonlinear restricted-cubic-spline basis terms for a numeric vector, following Harrell’s truncated-power parameterization as implemented by the SAS %RCSPLINE macro. With k knots this returns k - 2 nonlinear terms (named rcs1, rcs2, …); the linear term is supplied separately (e.g., the raw time variable in a model formula). Together the linear term and these nonlinear terms form a full-rank basis for the restricted cubic spline (i.e. natural cubic spline) space, avoiding the rank deficiency that arises when a separate linear term is added to a basis (such as splines::ns()) that already spans the linear component.

Usage

compute_rcs_basis(x, rcs_knots)

Arguments

x Numeric vector of values (e.g., follow-up time).
rcs_knots Numeric vector with at least 3 elements: first and last are boundary knots; all intermediate elements are interior knots.

Details

Each term is exactly zero for x at or below the first knot. In the ettbc outcome models this means every spline term vanishes at month 0, so the STOPBASE main effect in fit_outcome_hr() is the arm contrast at baseline.

The basis is used internally by fit_screening_propensity() and the predict_survival_*() functions, and is exported so other packages can reuse the same Harrell parameterization rather than writing it again.

For knots t[1] < … < t[k], term j (for j = 1, …, k - 2) is ((x - t[j])+^3 - (x - t[k-1])+^3 * (t[k] - t[j]) / (t[k] - t[k-1]) + (x - t[k])+^3 * (t[k-1] - t[j]) / (t[k] - t[k-1])) / (t[k] - t[1])^2, where (u)+ = max(u, 0). The n_knots >= 3 guard ensures at least one nonlinear term is produced.

Value

A matrix with length(rcs_knots) - 2 columns named rcs1, rcs2, …, one per nonlinear restricted-cubic-spline degree of freedom. Restricted cubic splines are constrained to be linear beyond the boundary knots.

References

Harrell FE. Regression Modeling Strategies. Springer; 2015.

See Also

fit_outcome_hr() and predict_survival_ipw(), which model time with this basis.

Examples

Code
library("ettbc")

basis <- compute_rcs_basis(0:12, rcs_knots = c(0, 6, 12))
head(basis)
            rcs1
[1,] 0.000000000
[2,] 0.006944444
[3,] 0.055555556
[4,] 0.187500000
[5,] 0.444444444
[6,] 0.868055556
Code
# Terms vanish at or below the first knot
basis[1, ]
rcs1 
   0