| Title: | Hybrid Penalized Partial Least Squares for Mixed Data |
|---|---|
| Description: | Fits Penalized Partial Least Squares (PLS) regression when predictors are hybrid objects that combine functional curves (infinite-dimensional 'fda' objects) and scalar covariates (finite-dimensional numeric matrices). The package treats a hybrid predictor as an element of a product Hilbert space formed by the functional and Euclidean components, and implements the arithmetic (addition, scalar multiplication, and inner products, including roughness-penalized inner products) needed to run penalized PLS directly in that space. The algorithm extracts latent components that maximize covariance with a scalar response while penalizing roughness of the estimated functional coefficient curves. Helpers are included for constructing hybrid predictors, two-step within- and between-modality normalization, train/test splitting, synthetic data generation, cross-validated component selection, and prediction. The method is described in Mun and Jang (2026) <doi:10.48550/arXiv.2601.16364>. |
| Authors: | Jongmin Mun [aut, cre, cph] |
| Maintainer: | Jongmin Mun <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-09-23 06:14:02 UTC |
| Source: | https://github.com/cran/FSHybridPLS |
Generate K-Fold Cross-Validation Indices
create_idx_kfold(n_sample, n_fold)create_idx_kfold(n_sample, n_fold)
n_sample |
Integer. Total number of samples. |
n_fold |
Integer. Number of folds (>= 2). |
A list of length n_fold; each element has idx_train and idx_valid.
set.seed(1) folds <- create_idx_kfold(20, 4) length(folds) length(folds[[1]]$idx_valid)set.seed(1) folds <- create_idx_kfold(20, 4) length(folds) length(folds[[1]]$idx_valid)
Fits fit_hybridPLS() on K training folds and records mean validation RMSE
for each number of components. Useful for choosing n_iter.
cv_fit_hybridPLS(W, y, n_iter, lambda, n_fold = 5, seed = NULL)cv_fit_hybridPLS(W, y, n_iter, lambda, n_fold = 5, seed = NULL)
W |
A |
y |
Numeric response vector. |
n_iter |
Maximum number of components to consider. |
lambda |
Numeric smoothing-parameter vector (length |
n_fold |
Number of CV folds (default 5). |
seed |
Optional seed for fold assignment. |
A list with:
Mean validation RMSE for components 1:n_iter.
Component count with smallest mean RMSE.
Matrix of fold-wise RMSE (n_fold x n_iter).
set.seed(1) sim <- simulate_hybrid_data(n = 40, n_basis = 5) cv <- cv_fit_hybridPLS(sim$W, sim$y, n_iter = 3, lambda = 1e-3, n_fold = 3) cv$best_n_iterset.seed(1) sim <- simulate_hybrid_data(n = 40, n_basis = 5) cv <- cv_fit_hybridPLS(sim$W, sim$y, n_iter = 3, lambda = 1e-3, n_fold = 3) cv$best_n_iter
Runs the iterative Hybrid Penalized Partial Least Squares algorithm.
If validation_data is provided, RMSE on the validation set is stored
for each extracted component.
fit.hybridPLS(W, y, n_iter, lambda, validation_data = NULL) fit_hybridPLS(W, y, n_iter, lambda, validation_data = NULL) ## S3 method for class 'hybridPLS' print(x, ...)fit.hybridPLS(W, y, n_iter, lambda, validation_data = NULL) fit_hybridPLS(W, y, n_iter, lambda, validation_data = NULL) ## S3 method for class 'hybridPLS' print(x, ...)
W |
A |
y |
Numeric vector of training responses (length |
n_iter |
Integer number of PLS components to extract (>= 1). |
lambda |
Numeric vector of smoothing parameters, one per functional
predictor ( |
validation_data |
Optional list with elements |
x |
A |
... |
Unused. |
An object of class hybridPLS, a list with:
List of score vectors (length n_iter).
List of weight directions as single-sample predictor_hybrid objects.
List of cumulative regression directions; beta[[L]] uses the
first L components.
List of deflated predictors; W[[1]] is the input, W[[l+1]]
is after extracting component l.
List of predictor loadings.
List of response loadings (scalars).
Fitting settings.
Numeric vector of validation RMSE by component, or NULL.
set.seed(1) sim <- simulate_hybrid_data(n = 40, n_functional = 1, n_scalar = 2, n_basis = 5) fit <- fit_hybridPLS(sim$W, sim$y, n_iter = 2, lambda = 1e-3) fit pred <- predict(fit, sim$W, n_components = 2) cor(pred, sim$y)set.seed(1) sim <- simulate_hybrid_data(n = 40, n_functional = 1, n_scalar = 2, n_basis = 5) fit <- fit_hybridPLS(sim$W, sim$y, n_iter = 2, lambda = 1e-3) fit pred <- predict(fit, sim$W, n_components = 2) cor(pred, sim$y)
Computes the unpenalized hybrid inner product plus roughness penalties
on functional components: .
inprod_pen.predictor_hybrid(xi_1, xi_2 = NULL, lambda) inprod_pen_predictor_hybrid(xi_1, xi_2 = NULL, lambda)inprod_pen.predictor_hybrid(xi_1, xi_2 = NULL, lambda) inprod_pen_predictor_hybrid(xi_1, xi_2 = NULL, lambda)
xi_1 |
A |
xi_2 |
Another |
lambda |
Non-negative numeric vector of length |
A numeric scalar (or vector under broadcasting), the penalized inner product.
set.seed(1) sim <- simulate_hybrid_data(n = 20, n_basis = 5) fit <- fit_hybridPLS(sim$W, sim$y, n_iter = 2, lambda = 1e-3) inprod_pen_predictor_hybrid(fit$xi[[1]], fit$xi[[1]], lambda = 1e-3)set.seed(1) sim <- simulate_hybrid_data(n = 20, n_basis = 5) fit <- fit_hybridPLS(sim$W, sim$y, n_iter = 2, lambda = 1e-3) inprod_pen_predictor_hybrid(fit$xi[[1]], fit$xi[[1]], lambda = 1e-3)
Uses pre-computed Gram matrices to calculate hybrid inner products without numerical integration.
inprod.predictor_hybrid(xi_1, xi_2 = NULL) inprod_predictor_hybrid(xi_1, xi_2 = NULL)inprod.predictor_hybrid(xi_1, xi_2 = NULL) inprod_predictor_hybrid(xi_1, xi_2 = NULL)
xi_1 |
A |
xi_2 |
Another |
A numeric scalar or vector of inner products. When one argument
has a single sample and the other has N samples, returns a length-N
vector (broadcasted projection).
set.seed(1) sim <- simulate_hybrid_data(n = 20, n_basis = 5) fit <- fit_hybridPLS(sim$W, sim$y, n_iter = 1, lambda = 1e-3) scores <- inprod_predictor_hybrid(sim$W, fit$xi[[1]]) length(scores)set.seed(1) sim <- simulate_hybrid_data(n = 20, n_basis = 5) fit <- fit_hybridPLS(sim$W, sim$y, n_iter = 1, lambda = 1e-3) scores <- inprod_predictor_hybrid(sim$W, fit$xi[[1]]) length(scores)
Processes a raw kidney study data frame into a predictor_hybrid object and
a scaled response. The input is expected to contain at least columns
ID, Study, and renogram_value, plus clinical covariates used for the
response and scalar predictors (accessed by the positional columns described
in the paper workflow).
load_and_preprocess_kidney_data(kidney_df, n_basis = 20)load_and_preprocess_kidney_data(kidney_df, n_basis = 20)
kidney_df |
Data frame with kidney study records. |
n_basis |
Integer. Number of B-spline basis functions (default 20). |
This helper is application-specific and requires user-supplied data; it is not needed for the core Hybrid PLS algorithm.
A list with:
A predictor_hybrid object.
Min-max scaled numeric response in .
try(load_and_preprocess_kidney_data(data.frame(x = 1)), silent = TRUE)try(load_and_preprocess_kidney_data(data.frame(x = 1)), silent = TRUE)
Computes fitted or predicted responses using the cumulative coefficient
direction beta[[n_components]].
## S3 method for class 'hybridPLS' predict(object, newdata = NULL, n_components = object$n_iter, ...)## S3 method for class 'hybridPLS' predict(object, newdata = NULL, n_components = object$n_iter, ...)
object |
A |
newdata |
A |
n_components |
Number of components to use (default: all). |
... |
Unused. |
Numeric vector of predictions (length newdata$n_sample).
set.seed(1) sim <- simulate_hybrid_data(n = 30, n_basis = 5) fit <- fit_hybridPLS(sim$W, sim$y, n_iter = 2, lambda = 1e-3) head(predict(fit, sim$W))set.seed(1) sim <- simulate_hybrid_data(n = 30, n_basis = 5) fit <- fit_hybridPLS(sim$W, sim$y, n_iter = 2, lambda = 1e-3) head(predict(fit, sim$W))
Constructs an S3 object of class predictor_hybrid that stores scalar
covariates and functional predictors in a joint representation, along with
precomputed Gram and roughness-penalty matrices used by Hybrid PLS.
predictor_hybrid(Z, functional_list, eval_point, penalty_order = 2)predictor_hybrid(Z, functional_list, eval_point, penalty_order = 2)
Z |
Numeric matrix (n_sample x n_scalar). |
functional_list |
List of 'fd' objects. |
eval_point |
Evaluation points. |
penalty_order |
Integer. Derivative order for roughness penalty (default 2). |
An object of class predictor_hybrid, a named list with:
ZScalar predictor matrix (n_sample x n_scalar).
functional_listList of fd objects for the functional predictors.
gram_listList of Gram (inner-product) matrices for each functional basis.
gram_deriv_listList of roughness-penalty matrices for each functional basis.
eval_pointNumeric vector of evaluation points for the functional domain.
n_basis_listNumber of basis functions for each functional predictor.
n_sampleNumber of samples.
n_functionalNumber of functional predictors.
n_scalarNumber of scalar predictors.
library(fda) # Create basis and functional data fbasis <- create.bspline.basis(c(0, 1), 5) coefs <- matrix(rnorm(15), 5, 3) fd_obj <- fd(coefs, fbasis) # Scalar data Z_mat <- matrix(rnorm(9), 3, 3) # Construct hybrid predictor W <- predictor_hybrid( Z = Z_mat, functional_list = list(fd_obj), eval_point = seq(0, 1, 0.1) ) class(W) W$n_sample W$n_functional W$n_scalarlibrary(fda) # Create basis and functional data fbasis <- create.bspline.basis(c(0, 1), 5) coefs <- matrix(rnorm(15), 5, 3) fd_obj <- fd(coefs, fbasis) # Scalar data Z_mat <- matrix(rnorm(9), 3, 3) # Construct hybrid predictor W <- predictor_hybrid( Z = Z_mat, functional_list = list(fd_obj), eval_point = seq(0, 1, 0.1) ) class(W) W$n_sample W$n_functional W$n_scalar
Generates synthetic hybrid predictors (functional curves + scalar covariates) and a scalar response useful for examples and testing.
simulate_hybrid_data( n = 50, n_functional = 1, n_scalar = 3, n_basis = 7, n_eval = 51, signal_to_noise = 3, seed = NULL )simulate_hybrid_data( n = 50, n_functional = 1, n_scalar = 3, n_basis = 7, n_eval = 51, signal_to_noise = 3, seed = NULL )
n |
Number of samples. |
n_functional |
Number of functional predictors. |
n_scalar |
Number of scalar predictors. |
n_basis |
Number of B-spline basis functions per functional predictor. |
n_eval |
Number of evaluation grid points on |
signal_to_noise |
Approximate signal-to-noise ratio for the response. |
seed |
Optional RNG seed. |
A list with:
A predictor_hybrid object.
Numeric response vector of length n.
Single-sample predictor_hybrid used to generate the linear signal.
set.seed(1) sim <- simulate_hybrid_data(n = 25, n_functional = 1, n_scalar = 2, n_basis = 5) class(sim$W) length(sim$y)set.seed(1) sim <- simulate_hybrid_data(n = 25, n_functional = 1, n_scalar = 2, n_basis = 5) class(sim$W) length(sim$y)
Randomly partitions the hybrid predictor object and response vector into training and testing sets based on a given ratio.
split_all(W_hybrid, response, train_ratio)split_all(W_hybrid, response, train_ratio)
W_hybrid |
A |
response |
A numeric (or factor) vector of length |
train_ratio |
Proportion of samples for training (strictly between 0 and 1). |
A named list with:
predictor_hybrid objects.
Response vectors for each split.
Integer indices used for the split.
set.seed(1) sim <- simulate_hybrid_data(n = 30, n_basis = 5) parts <- split_all(sim$W, sim$y, train_ratio = 0.7) length(parts$response_train) > 0 length(parts$response_test) > 0 inherits(parts$predictor_train, "predictor_hybrid")set.seed(1) sim <- simulate_hybrid_data(n = 30, n_basis = 5) parts <- split_all(sim$W, sim$y, train_ratio = 0.7) length(parts$response_train) > 0 length(parts$response_test) > 0 inherits(parts$predictor_train, "predictor_hybrid")
Full preprocessing pipeline: train/test split, within-modality standardization for functional and scalar predictors, between-modality variance balancing, and response standardization (train statistics applied to test).
split_and_normalize.all(W_hybrid, response, train_ratio) split_and_normalize_all(W_hybrid, response, train_ratio)split_and_normalize.all(W_hybrid, response, train_ratio) split_and_normalize_all(W_hybrid, response, train_ratio)
W_hybrid |
A |
response |
Numeric response vector (length |
train_ratio |
Proportion of samples used for training (strictly between 0 and 1). |
A list with:
Normalized predictor_hybrid objects.
Standardized responses.
Intermediate normalization objects and split indices.
set.seed(1) sim <- simulate_hybrid_data(n = 40, n_basis = 5) prep <- split_and_normalize_all(sim$W, sim$y, train_ratio = 0.7) fit <- fit_hybridPLS( prep$predictor_train, prep$response_train, n_iter = 2, lambda = 1e-3, validation_data = list( W_test = prep$predictor_test, y_test = prep$response_test ) ) fit$validation_rmseset.seed(1) sim <- simulate_hybrid_data(n = 40, n_basis = 5) prep <- split_and_normalize_all(sim$W, sim$y, train_ratio = 0.7) fit <- fit_hybridPLS( prep$predictor_train, prep$response_train, n_iter = 2, lambda = 1e-3, validation_data = list( W_test = prep$predictor_test, y_test = prep$response_test ) ) fit$validation_rmse