pub fn variable_selection(
predictors: &[&FdMatrix],
y: &[f64],
argvals_list: &[&[f64]],
scalar_covariates: Option<&FdMatrix>,
config: &VarSelectConfig,
) -> Result<VarSelectResult, FdarError>Expand description
Variable selection for scalar-on-function regression via group-penalised coordinate descent in FPC-score space (GroupLasso).
Each functional predictor predictors[p] is reduced to K_p FPC scores
(one group). Group-lasso coordinate descent then selects which groups are
active.
§Algorithm
- Run
fdata_to_pc_1don each predictor → score groups ξ^0, …, ξ^{P−1}. - Build design X = [μ | ξ^0 | … | ξ^{P−1} | Z] (Z = optional scalar covariates).
- If
config.lambda == 0.0, 5-fold CV-select λ over a geometric grid from0.01·λ_maxtoλ_maxwhereλ_max = max_g ||X_g'y|| / √K_g. Each fold trains on 4/5 of the data and evaluates held-out prediction error. - Coordinate-descent group-lasso: for each group g compute the partial-
residual OLS update β̂_g via
cholesky_solve, then soft-threshold:β_g = β̂_g · max(0, 1 − λ√K_g / ||β̂_g||). - Iterate until
max(|Δβ|) < epsilonormax_itersweeps.
§R Baseline Divergence
R’s refund::fosr.vs is a function-on-scalar model (functional response,
scalar predictors). fdars implements scalar-on-function variable selection
(scalar response, functional predictors). The group-penalty formulation is
analogous but the regression direction is opposite. GroupMCP and GroupSCAD are
documented as future work; only GroupLasso is implemented this phase.
§Errors
Returns FdarError::InvalidParameter for unsupported penalty variants
(GroupMcp, GroupScad).
Returns FdarError::InvalidDimension if:
predictorsis empty,predictors.len() != argvals_list.len(), or- any
predictors[p].nrows() != y.len().
Returns FdarError::ComputationFailed if the OLS sub-step encounters a
singular group design matrix.
§Examples
use fdars_core::matrix::FdMatrix;
use fdars_core::variable_selection;
use fdars_core::scalar_on_function::{VarSelectConfig, VarSelectPenalty};
let n = 20;
let m = 10;
let data = FdMatrix::from_column_major(
(0..n*m).map(|i| (i as f64 * 0.1).sin()).collect(),
n, m,
).unwrap();
let argvals: Vec<f64> = (0..m).map(|j| j as f64 / (m - 1) as f64).collect();
let y: Vec<f64> = (0..n).map(|i| (i as f64 * 0.2).cos()).collect();
let mut config = VarSelectConfig::default();
config.ncomp = 2;
let result = variable_selection(&[&data], &y, &[argvals.as_slice()], None, &config).unwrap();
assert_eq!(result.active_predictors.len(), 1);