From 74bb44b60fdef20555816a255824dc784f1ff288 Mon Sep 17 00:00:00 2001 From: Jodie Li Date: Thu, 15 Oct 2026 23:07:45 -0500 Subject: [PATCH 1/4] Add weighted multiple sources, separate penalties, and example data --- .Rbuildignore | 1 + .gitignore | 3 + DESCRIPTION | 13 +- NEWS.md | 9 + R/RcppExports.R | 8 +- R/data-multisource.R | 43 ++ R/dlearner.R | 128 ++++-- R/input-validation.R | 76 ++++ R/learner.R | 402 +++++++++++++------ data-raw/gen-data.R | 35 ++ data/dat_multisource.rda | Bin 0 -> 212592 bytes inst/examples/multiple-sources.R | 60 +++ man/cv.learner.Rd | 110 ++++- man/dat_multisource.Rd | 54 +++ man/dlearner.Rd | 68 +++- man/learner.Rd | 145 +++++-- src/RcppExports.cpp | 31 +- src/kernels.cpp | 213 +++++----- tests/testthat/fixtures/README.md | 54 +++ tests/testthat/fixtures/generate-reference.R | 87 ++++ tests/testthat/fixtures/multisource-v030.rds | Bin 0 -> 6238 bytes tests/testthat/test-cv-multisource.R | 135 +++++++ tests/testthat/test-main.R | 4 +- tests/testthat/test-multisource-data.R | 31 ++ tests/testthat/test-reference-regression.R | 51 +++ tests/testthat/test-separate-penalties.R | 144 +++++++ tests/testthat/test-stopping-behavior.R | 51 +++ 27 files changed, 1625 insertions(+), 331 deletions(-) create mode 100644 R/data-multisource.R create mode 100644 R/input-validation.R create mode 100644 data/dat_multisource.rda create mode 100644 inst/examples/multiple-sources.R create mode 100644 man/dat_multisource.Rd create mode 100644 tests/testthat/fixtures/README.md create mode 100644 tests/testthat/fixtures/generate-reference.R create mode 100644 tests/testthat/fixtures/multisource-v030.rds create mode 100644 tests/testthat/test-cv-multisource.R create mode 100644 tests/testthat/test-multisource-data.R create mode 100644 tests/testthat/test-reference-regression.R create mode 100644 tests/testthat/test-separate-penalties.R create mode 100644 tests/testthat/test-stopping-behavior.R diff --git a/.Rbuildignore b/.Rbuildignore index d96d2f7..42bec2f 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -4,3 +4,4 @@ ^\.github$ ^data-raw$ ^README_files/ +^\.Rprofile$ diff --git a/.gitignore b/.gitignore index 5b6a065..7234786 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ .Rhistory .RData .Ruserdata + +.Rprofile +.DS_Store diff --git a/DESCRIPTION b/DESCRIPTION index ec868aa..d7b4663 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,10 +1,12 @@ Package: learner Type: Package Title: Latent Space-Based Transfer Learning -Version: 1.0.1 +Version: 1.1.0 Authors@R: c(person("Sean", "McGrath", role = c("aut", "cre"), email = "sean.mcgrath514@gmail.com", comment = c(ORCID = "0000-0002-7281-3516")), + person("Jodie", "Li", role = "aut", + email = "ljuanshuo@gmail.com"), person("Ryan", "ODea", role = c("aut"), email = "ryanodea@hsph.harvard.edu"), person("Cenhao", "Zhu", role = c("aut"), @@ -14,14 +16,16 @@ Authors@R: c(person("Sean", "McGrath", role = c("aut", "cre"), Maintainer: Sean McGrath Description: Implements transfer learning methods for low-rank matrix estimation. These methods leverage similarity in the latent row and column - spaces between the source and target populations to improve estimation in - the target population. The methods include the LatEnt spAce-based tRaNsfer + spaces between one or more source populations and a target population to + improve estimation in the target population. The methods include the + LatEnt spAce-based tRaNsfer lEaRning (LEARNER) method and the direct projection LEARNER (D-LEARNER) method described by McGrath et al. (2024) . + Supports weighted combinations of source spaces, separate row- and + column-space penalties, and cross-validation for penalty selection. License: GPL (>=3) Encoding: UTF-8 LazyData: true -RoxygenNote: 7.3.2 URL: https://github.com/stmcg/learner BugReports: https://github.com/stmcg/learner/issues Imports: ScreeNOT, @@ -33,3 +37,4 @@ Suggests: Config/testthat/edition: 3 Depends: R (>= 2.10) +RoxygenNote: 7.3.2 diff --git a/NEWS.md b/NEWS.md index a538a8b..e9ac59c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,12 @@ +### learner version 1.1.0 (unreleased) + +* Add support for multiple source populations and optional source weights in + `learner()`, `dlearner()`, and `cv.learner()`. +* Add `dat_multisource`, an example dataset with one target and two source + populations with independently generated noise. +* Add separate row- and column-space penalties in `learner()` and + cross-validation over these penalties in `cv.learner()`. + ### learner version 1.0.0 (2025-03-02) * Re-implemented most of `learner` and `cv.learner` in Rcpp, resulting in significant speed-ups diff --git a/R/RcppExports.R b/R/RcppExports.R index ec831f9..d1b4b70 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,12 +1,12 @@ # Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 -learner_cpp <- function(Y_source, Y_target, r, lambda1, lambda2, step_size, max_iter, threshold, max_value) { - .Call(`_learner_learner_cpp`, Y_source, Y_target, r, lambda1, lambda2, step_size, max_iter, threshold, max_value) +learner_cpp <- function(Y_source, Y_target, source_weights, r, lambda1_row, lambda1_col, lambda2, step_size, max_iter, threshold, max_value) { + .Call(`_learner_learner_cpp`, Y_source, Y_target, source_weights, r, lambda1_row, lambda1_col, lambda2, step_size, max_iter, threshold, max_value) } -cv_learner_cpp <- function(Y_source, Y_target, lambda1_all, lambda2_all, step_size, n_folds, max_iter, threshold, n_cores, r, max_value, index_set) { - .Call(`_learner_cv_learner_cpp`, Y_source, Y_target, lambda1_all, lambda2_all, step_size, n_folds, max_iter, threshold, n_cores, r, max_value, index_set) +cv_learner_cpp <- function(Y_source, Y_target, source_weights, row_grid, col_grid, balance_grid, step_size, max_iter, threshold, n_cores, r, max_value, index_set) { + .Call(`_learner_cv_learner_cpp`, Y_source, Y_target, source_weights, row_grid, col_grid, balance_grid, step_size, max_iter, threshold, n_cores, r, max_value, index_set) } omp_max_threads <- function() { diff --git a/R/data-multisource.R b/R/data-multisource.R new file mode 100644 index 0000000..d98d4d9 --- /dev/null +++ b/R/data-multisource.R @@ -0,0 +1,43 @@ +#' Simulated data set: Multiple sources with different noise levels +#' +#' Simulated matrices for one target population and two source populations. +#' The sources share the target's latent row and column spaces, but source A +#' is observed more precisely than source B. This data set illustrates fitting +#' LEARNER and D-LEARNER with multiple sources. +#' +#' @docType data +#' @format A list with four components. All matrices have 100 rows and 50 columns, +#' with corresponding rows and columns aligned across populations. +#' \describe{ +#' \item{\code{Y_source}}{A named list of observed source matrices, \code{A} +#' and \code{B}, suitable for the \code{Y_source} argument.} +#' \item{\code{Y_target}}{The observed target matrix.} +#' \item{\code{Theta_source}}{A named list of the true rank-3 source matrices, +#' \code{A} and \code{B}. The two true matrices are identical.} +#' \item{\code{Theta_target}}{The true rank-3 target matrix.} +#' } +#' @details +#' The source signal is obtained by reversing the three nonzero singular values +#' of the target signal while keeping its singular vectors. Each observed matrix +#' is generated by adding independent, mean-zero normal noise to its own signal. +#' Noise is independent across entries and populations, with variances 0.10 for +#' the target, 0.01 for source A, and 0.50 for source B. Thus, source A has less +#' noise than the target and source B has more. Source B is not generated from +#' the observed source A matrix. +#' +#' The true signal matrices are included for illustration and estimation-error +#' calculations; they are not inputs to the fitting functions. These simulated +#' data are a usage example, not a reproduction of the paper's simulation study. +#' +#' @examples +#' data(dat_multisource) +#' fit <- dlearner( +#' Y_source = dat_multisource$Y_source, +#' Y_target = dat_multisource$Y_target, +#' r = 3, source_weights = c(0.7, 0.3) +#' ) +#' dim(fit$dlearner_estimate) +#' @seealso \code{\link{dat_highsim}}, \code{\link{dat_modsim}}, +#' \code{\link{learner}}, \code{\link{dlearner}} +#' @keywords datasets +"dat_multisource" diff --git a/R/dlearner.R b/R/dlearner.R index 0454de2..014d9ad 100644 --- a/R/dlearner.R +++ b/R/dlearner.R @@ -1,66 +1,106 @@ -#' Latent space-based transfer learning +#' Direct projection transfer learning #' -#' This function applies the Direct project LatEnt spAce-based tRaNsfer lEaRning (D-LEARNER) method (McGrath et al. 2024) to leverage data from a source population to improve -#' estimation of a low rank matrix in an underrepresented target population. +#' @description +#' This function applies the Direct projection LatEnt spAce-based tRaNsfer +#' lEaRning (D-LEARNER) method (McGrath et al. 2024) to leverage data from a source +#' population to improve estimation of a low-rank matrix in an underrepresented +#' target population. #' -#' @param Y_target matrix containing the target population data -#' @param Y_source matrix containing the source population data -#' @param r (optional) integer specifying the rank of the knowledge graphs. By default, ScreeNOT (Donoho et al. 2023) is applied to the source population knowledge graph to select the rank. -#' -#' @return A list with the following components: -#' \item{dlearner_estimate}{matrix containing the D-LEARNER estimate of the target population knowledge graph.} -#' \item{r}{rank value used.} +#' @param Y_source Matrix containing the source population data, with the same rows +#' and columns as \code{Y_target}. For multiple sources, supply a list of +#' matrices. +#' @param Y_target Matrix containing the target population data. Missing entries +#' are not allowed. +#' @param r Rank of the knowledge graphs. If omitted, ScreeNOT (Donoho et al. 2023) +#' is applied to the source population data to select the rank. +#' @param source_weights Relative weights of the sources, in the order of +#' \code{Y_source}. Default is equal weights. #' #' @details -#' #' \strong{Data and notation:} #' -#' The data consists of a matrix in the target population \eqn{Y_0 \in \mathbb{R}^{p \times q}} and the source population \eqn{Y_1 \in \mathbb{R}^{p \times q}}. -#' Let \eqn{\hat{U}_{k} \hat{\Lambda}_{k} \hat{V}_{k}^{\top}} denote the truncated singular value decomposition (SVD) of \eqn{Y_k}, \eqn{k = 0, 1}. +#' The data consists of a matrix in the target population +#' \eqn{Y_0 \in \mathbb{R}^{p \times q}} and the source population +#' \eqn{Y_1 \in \mathbb{R}^{p \times q}}. Let +#' \eqn{\hat U_k\hat\Lambda_k\hat V_k^\top} denote the rank-\eqn{r} truncated +#' singular value decomposition (SVD) of \eqn{Y_k}, \eqn{k = 0, 1}. #' -#' For \eqn{k = 0, 1}, one can view \eqn{Y_k} as a noisy version of \eqn{\Theta_k}, referred to as the knowledge graph. The target of inference is the target population knowledge graph, \eqn{\Theta_0}. +#' For \eqn{k = 0, 1}, one can view \eqn{Y_k} as a noisy version of +#' \eqn{\Theta_k}, referred to as the knowledge graph. The target of inference +#' is the target population knowledge graph, \eqn{\Theta_0}. #' #' \strong{Estimation:} #' -#' This method estimates \eqn{\Theta_0} by \eqn{\hat{U}_{1}^{\top}\hat{U}_{1} Y_0 \hat{V}_{1}^{\top}\hat{V}_{1}}. +#' This method estimates \eqn{\Theta_0} by +#' +#' \deqn{\hat U_1\hat U_1^\top Y_0 \hat V_1\hat V_1^\top.} +#' +#' That is, the target population data are projected onto the latent row and +#' column spaces of the source population, without iterative fitting or penalty +#' selection. +#' +#' \strong{Multiple sources:} +#' +#' Supply a list of source matrices to combine information from several +#' populations. Their projection operators are averaged using +#' \code{source_weights}, and the estimate becomes +#' +#' \deqn{\widehat\Theta_0=\bar P_U Y_0\bar P_V,\qquad +#' \bar P_U=\sum_{k=1}^K w_k\hat U_k\hat U_k^\top,\qquad +#' \bar P_V=\sum_{k=1}^K w_k\hat V_k\hat V_k^\top.} +#' +#' where \eqn{\hat U_k} and \eqn{\hat V_k} come from the truncated SVD of +#' the \eqn{k}th source and the weights \eqn{w_k} are given by +#' \code{source_weights}. If \code{r} is not specified, the rank is selected +#' using the first source. +#' +#' @return +#' A list with the following components: +#' \item{dlearner_estimate}{matrix containing the D-LEARNER estimate of the target population knowledge graph.} +#' \item{r}{rank value used.} #' #' @references #' Donoho, D., Gavish, M. and Romanov, E. (2023). \emph{ScreeNOT: Exact MSE-optimal singular value thresholding in correlated noise}. The Annals of Statistics, 51(1), pp.122-148. #' +#' @seealso +#' \code{\link{learner}} for a target fit that can adapt the source +#' spaces through penalized estimation. +#' #' @examples #' res <- dlearner(Y_source = dat_highsim$Y_source, #' Y_target = dat_highsim$Y_target) #' +#' # Multiple sources with fixed demonstration weights. +#' res_multi <- dlearner( +#' Y_source = dat_multisource$Y_source, +#' Y_target = dat_multisource$Y_target, r = 3, +#' source_weights = c(0.7, 0.3)) +#' dim(res_multi$dlearner_estimate) +#' #' @export -dlearner <- function(Y_source, Y_target, r){ - # Error catching - if (!identical(dim(Y_source), dim(Y_target))){ - stop('Y_source and Y_target must have the same dimensions') - } - if (any(is.na(Y_source))){ - stop('Y_source cannot have NA values.') - } - if (any(is.na(Y_target))){ - stop('Y_target cannot have NA values') - } - - p <- nrow(Y_source) - q <- ncol(Y_source) - - if (missing(r)){ - max_rank <- min(p, q) / 3 - r <- max(ScreeNOT::adaptiveHardThresholding(Y = Y_source, k = max_rank)$r, 1) +dlearner <- function(Y_source, Y_target, r, source_weights = NULL) { + sources <- prepare_sources(Y_source, Y_target, source_weights, + allow_missing_target = FALSE) + r <- resolve_rank(if (missing(r)) NULL else r, sources$matrices[[1]]) + bases <- lapply(sources$matrices, svd, nu = r, nv = r) + if (length(bases) == 1L) { + # Preserve the original single-source multiplication order. + s <- bases[[1]] + estimate <- s$u %*% (t(s$u) %*% Y_target %*% s$v) %*% t(s$v) + } else { + # Average source projectors, not raw source matrices. + middle <- matrix(0, nrow(Y_target), ncol(Y_target)) + for (k in seq_along(bases)) { + u <- bases[[k]]$u + middle <- middle + sources$weights[k] * (u %*% crossprod(u, Y_target)) + } + estimate <- matrix(0, nrow(Y_target), ncol(Y_target)) + for (k in seq_along(bases)) { + v <- bases[[k]]$v + estimate <- estimate + sources$weights[k] * ((middle %*% v) %*% t(v)) + } } - - svd_source <- svd(Y_source, nu = r, nv = r) - dlearner_estimate <- svd_source$u %*% - (t(svd_source$u) %*% Y_target %*% svd_source$v) %*% - t(svd_source$v) - - colnames(dlearner_estimate) <- colnames(Y_source) - rownames(dlearner_estimate) <- rownames(Y_source) - - return(list(dlearner_estimate = dlearner_estimate, r = r)) + dimnames(estimate) <- dimnames(sources$matrices[[1]]) + list(dlearner_estimate = estimate, r = r) } - diff --git a/R/input-validation.R b/R/input-validation.R new file mode 100644 index 0000000..d15f347 --- /dev/null +++ b/R/input-validation.R @@ -0,0 +1,76 @@ +# Normalize one source or a source list without changing the user's ordering. +# The first source determines the default rank and LEARNER initialization. +prepare_sources <- function(Y_source, Y_target, source_weights = NULL, + allow_missing_target = TRUE) { + if (!is.matrix(Y_target) || !is.numeric(Y_target) || + any(dim(Y_target) == 0L) || any(is.infinite(Y_target))) { + stop('Y_target must be a nonempty numeric matrix without infinite values.') + } + if ((!allow_missing_target && anyNA(Y_target)) || all(is.na(Y_target))) { + stop('Y_target must contain observed values; dlearner does not allow NA values.') + } + sources <- if (is.matrix(Y_source)) list(Y_source) else Y_source + if (!is.list(sources) || length(sources) == 0L) { + stop('Y_source must be a matrix or a nonempty list of matrices.') + } + for (source in sources) { + if (!is.matrix(source) || !is.numeric(source) || any(!is.finite(source))) { + stop('Every source must be a numeric matrix with finite values and no NA values.') + } + if (!identical(dim(source), dim(Y_target))) { + stop('All source matrices and Y_target must have the same dimensions.') + } + } + if (is.null(source_weights)) source_weights <- rep(1, length(sources)) + if (!is.numeric(source_weights) || length(source_weights) != length(sources) || + any(!is.finite(source_weights)) || any(source_weights < 0) || + !any(source_weights > 0)) { + stop('source_weights must have one finite nonnegative value per source and a positive total.') + } + weights <- source_weights / max(source_weights) + list(matrices = sources, weights = weights / sum(weights)) +} + +resolve_rank <- function(r, source) { + if (is.null(r)) { + r <- max(ScreeNOT::adaptiveHardThresholding( + Y = source, k = min(dim(source)) / 3)$r, 1) + } + if (!is.numeric(r) || length(r) != 1L || !is.finite(r) || + r < 1 || r != floor(r) || r > min(dim(source))) { + stop('r must be an integer between 1 and the smaller matrix dimension.') + } + as.integer(r) +} + +validate_penalty_grid <- function(values, name) { + if (!is.numeric(values) || length(values) == 0L || + any(!is.finite(values)) || any(values < 0)) { + stop(name, ' must be a nonempty vector of finite nonnegative numbers.', call. = FALSE) + } +} + +validate_count <- function(value, name, lower = 1, upper = .Machine$integer.max) { + if (!is.numeric(value) || length(value) != 1L || !is.finite(value) || + value != floor(value) || value < lower || value > upper) { + stop(name, ' must be an integer between ', lower, ' and ', upper, '.', call. = FALSE) + } +} + +prepare_control <- function(control, step_size) { + if (!is.list(control)) stop('control must be a list.') + if (!is.numeric(step_size) || length(step_size) != 1L || + !is.finite(step_size) || step_size <= 0) { + stop('step_size must be a finite positive number.') + } + if (is.null(control$max_iter)) control$max_iter <- 100L + if (is.null(control$threshold)) control$threshold <- 0.001 + if (is.null(control$max_value)) control$max_value <- 10 + validate_count(control$max_iter, 'control$max_iter') + validate_space_penalty(control$threshold, 'control$threshold') + if (!is.numeric(control$max_value) || length(control$max_value) != 1L || + !is.finite(control$max_value) || control$max_value <= 0) { + stop('control$max_value must be a finite positive number.') + } + control +} diff --git a/R/learner.R b/R/learner.R index 5116111..00fc67d 100644 --- a/R/learner.R +++ b/R/learner.R @@ -1,29 +1,71 @@ #' Cross-validation for LEARNER #' -#' This function performs k-fold cross-validation to select the nuisance parameters \eqn{(\lambda_1, \lambda_2)} for \code{\link{learner}}. -#' -#' @param Y_target matrix containing the target population data, as in \code{\link{learner}} -#' @param Y_source matrix containing the source population data, as in \code{\link{learner}} -#' @param r (optional) integer specifying the rank of the knowledge graphs, as in \code{\link{learner}} -#' @param lambda_1_all vector of numerics specifying the candidate values of \eqn{\lambda_1} (see Details) -#' @param lambda_2_all vector of numerics specifying the candidate values of \eqn{\lambda_2} (see Details) -#' @param step_size numeric scalar specifying the step size for the Newton steps in the numerical optimization algorithm, as in \code{\link{learner}} -#' @param n_folds an integer specify the number of cross-validation folds. The default is \code{4}. -#' @param n_cores an integer specifying the number of CPU cores in OpenMP parallelization. Parallelization is performed across the different candidate \eqn{(\lambda_1, \lambda_2)} pairs. The default is \code{1}, i.e., no parallelization. -#' @param control a list of parameters for controlling the stopping criteria for the numerical optimization algorithm, as in \code{\link{learner}}. -#' -#' @return A list with the following elements: -#' \item{lambda_1_min}{value of \eqn{\lambda_1} with the smallest MSE} -#' \item{lambda_2_min}{value of \eqn{\lambda_2} with the smallest MSE} -#' \item{mse_all}{matrix containing MSE value for each \eqn{(\lambda_1, \lambda_2)} pair. The rows correspond to the \eqn{\lambda_1} values, and the columns correspond to the \eqn{\lambda_2} values.} -#' \item{r}{rank value used.} +#' @description +#' Performs k-fold cross-validation to select the source-space and balance +#' penalties for \code{\link{learner}}. Returns prediction errors and the +#' penalty combination with the smallest error. +#' +#' @param Y_source Source population data, as in \code{\link{learner}}. +#' Supply a matrix for one source or a list of matrices for multiple sources. +#' @param Y_target Target population data matrix, as in \code{\link{learner}}. +#' Only observed entries are used to evaluate predictions. +#' @param r Rank used in every fold, as in \code{\link{learner}}. It is not +#' selected by cross-validation. +#' @param lambda_1_all Candidate values for the common source-space penalty +#' \eqn{\lambda_1}. All combinations with \code{lambda_2_all} are evaluated. +#' @param lambda_2_all Candidate values for the balance penalty \eqn{\lambda_2}. +#' @param step_size Step size for each fit, as in \code{\link{learner}}. +#' @param n_folds Number of cross-validation folds. Default is \code{4}. +#' @param n_cores Number of CPU cores used to evaluate the candidate penalty +#' combinations in parallel. Default is \code{1}, i.e., no parallelization. +#' @param control Optimization settings for each fit; see \code{\link{learner}}. +#' @param lambda_1_row_all,lambda_1_col_all Candidate values for separate +#' penalties on the row and column factors. Supply both instead of +#' \code{lambda_1_all}; all combinations with \code{lambda_2_all} are evaluated. +#' @param source_weights Relative source weights, as in \code{\link{learner}}. The weights +#' are not selected by cross-validation. Default is equal weights. #' #' @details -#' Given sets of candidate values of \eqn{\lambda_1} and \eqn{\lambda_2}, this function performs k-fold cross-validation to select the pair \eqn{(\lambda_1, \lambda_2)} with the smallest held out error. This function randomly partitions the entries of \code{Y_target} into \eqn{k} (approximately) equally sized subsamples. The training data sets are obtained by removing one of the \eqn{k} subsamples and the corresponding test data sets are based on the held out subsamples. The \code{\link{learner}} function is applied to each training data set. The held out error is computed by the mean squared error comparing the entries in the test data sets with those imputed from the LEARNER estimates. See McGrath et al. (2024) for further details. +#' Given sets of candidate values of \eqn{\lambda_1} and \eqn{\lambda_2}, this +#' function performs k-fold cross-validation to select the pair +#' \eqn{(\lambda_1, \lambda_2)} with the smallest held out error. This function +#' randomly partitions the entries of \code{Y_target} into \eqn{k} +#' (approximately) equally sized subsamples. The training data sets are obtained +#' by removing one of the \eqn{k} subsamples and the corresponding test data +#' sets are based on the held out subsamples. The \code{\link{learner}} function is +#' applied to each training data set. The held out error is computed by comparing +#' the entries in the test data sets with those imputed from the LEARNER +#' estimates. See McGrath et al. (2024) for further details. +#' +#' With separate penalties, the procedure selects the row, column, and balance +#' penalties together. Both modes can be used with multiple sources. Call +#' \code{set.seed()} first to reproduce the random partition. +#' +#' To obtain the final estimate, apply \code{\link{learner}} with the selected +#' penalties to the full data (see Examples). Fits that reach the iteration +#' limit still contribute to the held out error, so check the settings in +#' \code{control} before interpreting the selection. +#' +#' @return +#' A list containing: +#' \item{lambda_1_min}{Common source-space penalty in the selected combination. +#' \code{NA} when separate penalties are used.} +#' \item{lambda_2_min}{Balance penalty in the selected combination.} +#' \item{lambda_1_row_min, lambda_1_col_min}{Row and column penalties in the +#' selected combination. Returned only when separate penalties are used.} +#' \item{mse_all}{Sum of held-out squared errors for each candidate combination. +#' For common penalties, rows correspond to \code{lambda_1_all} and columns to +#' \code{lambda_2_all}. For separate penalties, the three dimensions correspond +#' to the row, column, and balance grids, in that order. Divide by the number +#' of observed target entries to obtain mean squared errors.} +#' \item{r}{Rank used in the fits.} #' #' @references #' McGrath, S., Zhu, C,. Guo, M. and Duan, R. (2024). \emph{LEARNER: A transfer learning method for low-rank matrix estimation}. arXiv preprint arXiv:2412.20605. #' +#' @seealso +#' \code{\link{learner}} for fitting with the selected penalties. +#' #' @examples #' res <- cv.learner(Y_source = dat_highsim$Y_source, #' Y_target = dat_highsim$Y_target, @@ -31,139 +73,273 @@ #' lambda_2_all = c(1, 10, 100), #' step_size = 0.003) #' +#' # Refit using the selected penalties and all observed target entries. +#' fit <- learner(dat_highsim$Y_source, dat_highsim$Y_target, r = res$r, +#' lambda_1 = res$lambda_1_min, lambda_2 = res$lambda_2_min, +#' step_size = 0.003) +#' fit$convergence_criterion +#' +#' # Multiple sources with fixed demonstration weights. +#' sources <- dat_multisource$Y_source +#' target <- dat_multisource$Y_target +#' weights <- c(0.7, 0.3) +#' +#' set.seed(815) +#' res_separate <- cv.learner( +#' Y_source = sources, Y_target = target, r = 3, +#' source_weights = weights, +#' lambda_1_row_all = c(1, 10), lambda_1_col_all = c(1, 3), +#' lambda_2_all = c(0.1, 1), step_size = 0.0003, +#' n_folds = 2, control = list(max_iter = 100)) +#' dim(res_separate$mse_all) # row grid x column grid x balance grid #' +#' fit <- learner( +#' Y_source = sources, Y_target = target, r = res_separate$r, +#' source_weights = weights, +#' lambda_1_row = res_separate$lambda_1_row_min, +#' lambda_1_col = res_separate$lambda_1_col_min, +#' lambda_2 = res_separate$lambda_2_min, step_size = 0.0003, +#' control = list(max_iter = 100)) +#' fit$convergence_criterion +#' # This short example demonstrates the workflow; check convergence before +#' # interpreting results or comparing statistical performance. #' #' @export -cv.learner <- function(Y_source, Y_target, r, lambda_1_all, lambda_2_all, - step_size, n_folds = 4, n_cores = 1, control = list()) { - ## Error catching - if (!identical(dim(Y_source), dim(Y_target))){ - stop('Y_source and Y_target must have the same dimensions') - } - if (any(is.na(Y_source))){ - stop('Y_source cannot have NA values.') - } +cv.learner <- function(Y_source, Y_target, r, lambda_1_all = NULL, lambda_2_all, + step_size, n_folds = 4, n_cores = 1, control = list(), + lambda_1_row_all = NULL, lambda_1_col_all = NULL, + source_weights = NULL) { + sources <- prepare_sources(Y_source, Y_target, source_weights) + r <- resolve_rank(if (missing(r)) NULL else r, sources$matrices[[1]]) + control <- prepare_control(control, step_size) + validate_penalty_grid(lambda_2_all, 'lambda_2_all') - if (missing(r)){ - p <- nrow(Y_source); q <- ncol(Y_source) - max_rank <- min(p, q) / 3 - r <- max(ScreeNOT::adaptiveHardThresholding(Y = Y_source, k = max_rank)$r, 1) - } - if (!('max_iter' %in% names(control))){ - control$max_iter <- 100 - } - if (!('threshold' %in% names(control))){ - control$threshold <- 0.001 - } - if (!('max_value' %in% names(control))){ - control$max_value <- 10 - } - - if (n_folds < 2){ - stop('n_folds must be 2 or greater.') + # A common penalty uses a 2D grid; independent penalties use a 3D grid. + separate <- !is.null(lambda_1_row_all) || !is.null(lambda_1_col_all) + if (separate) { + if (!is.null(lambda_1_all)) { + stop('Provide either lambda_1_all or both separate grids, not both modes.') + } + if (is.null(lambda_1_row_all) || is.null(lambda_1_col_all)) { + stop('Both lambda_1_row_all and lambda_1_col_all must be provided together.') + } + validate_penalty_grid(lambda_1_row_all, 'lambda_1_row_all') + validate_penalty_grid(lambda_1_col_all, 'lambda_1_col_all') + grid <- expand.grid(row = lambda_1_row_all, col = lambda_1_col_all, + balance = lambda_2_all) + grid_dim <- c(length(lambda_1_row_all), length(lambda_1_col_all), length(lambda_2_all)) + } else { + validate_penalty_grid(lambda_1_all, 'lambda_1_all') + grid <- expand.grid(row = lambda_1_all, balance = lambda_2_all) + grid$col <- grid$row + grid_dim <- c(length(lambda_1_all), length(lambda_2_all)) } - ## Creating training and testing data sets + # Only observed target entries can be validation entries. available_indices <- which(!is.na(Y_target)) n_indices <- length(available_indices) - indices <- sample(available_indices, size = n_indices, replace = FALSE) - 1 - - index_set <- vector(mode = "list", length = n_folds) - for (fold in 1:n_folds){ - index_set[[fold]] <- indices[floor((fold - 1) * n_indices / n_folds + 1):floor(fold * n_indices / n_folds)] + validate_count(n_folds, 'n_folds', lower = 2, upper = n_indices) + validate_count(n_cores, 'n_cores') + indices <- sample(available_indices, size = n_indices, replace = FALSE) - 1L + index_set <- vector('list', n_folds) + for (fold in seq_len(n_folds)) { + start <- floor((fold - 1) * n_indices / n_folds) + 1L + end <- floor(fold * n_indices / n_folds) + index_set[[fold]] <- indices[seq.int(start, end)] } - result <- cv_learner_cpp(Y_source, Y_target, lambda_1_all, lambda_2_all, step_size, - n_folds, control$max_iter, control$threshold, n_cores, r, control$max_value, - index_set) - return(result) + scores <- cv_learner_cpp(sources$matrices, Y_target, sources$weights, + grid$row, grid$col, grid$balance, step_size, + control$max_iter, control$threshold, n_cores, r, + control$max_value, index_set) + if (!any(is.finite(scores))) stop('No candidate produced finite validation errors.') + if (any(!is.finite(scores))) warning('Some candidates produced non-finite validation errors and were excluded.') + scores[!is.finite(scores)] <- Inf + best <- which.min(scores) + # Keep the historical mse_all scale: summed held-out squared errors. + mse_all <- array(scores, dim = grid_dim) + if (!separate) { + return(list(lambda_1_min = grid$row[best], lambda_2_min = grid$balance[best], + mse_all = mse_all, r = r)) + } + list(lambda_1_min = NA_real_, lambda_2_min = grid$balance[best], + lambda_1_row_min = grid$row[best], lambda_1_col_min = grid$col[best], + mse_all = mse_all, r = r) } #' Latent space-based transfer learning #' -#' This function applies the LatEnt spAce-based tRaNsfer lEaRning (LEARNER) method (McGrath et al. 2024) to leverage data from a source population to improve -#' estimation of a low rank matrix in an underrepresented target population. -#' -#' @param Y_target matrix containing the target population data -#' @param Y_source matrix containing the source population data -#' @param r (optional) integer specifying the rank of the knowledge graphs. By default, ScreeNOT (Donoho et al. 2023) is applied to the source population knowledge graph to select the rank. -#' @param lambda_1 numeric scalar specifying the value of \eqn{\lambda_1} (see Details) -#' @param lambda_2 numeric scalar specifying the value of \eqn{\lambda_2} (see Details) -#' @param step_size numeric scalar specifying the step size for the Newton steps in the numerical optimization algorithm -#' @param control a list of parameters for controlling the stopping criteria for the numerical optimization algorithm. The list may include the following components: -#' \tabular{ll}{ -#' \code{max_iter} \tab integer specifying the maximum number of iterations \cr -#' \code{threshold} \tab numeric scalar specifying a convergence threshold. The algorithm converges when \eqn{|\epsilon_t - \epsilon_{t-1}| < }\code{threshold}, where \eqn{\epsilon_t} denotes the value of the objective function at iteration \eqn{t}. \cr -#' \code{max_value} \tab numeric scalar used to specify the maximum value of the objective function allowed before terminating the algorithm. Specifically, the algorithm will terminate if the value of the objective function exceeds \code{max_value}\eqn{\times \epsilon_0}, where \eqn{\epsilon_0} denotes the value of the objective function at the initial point. This is used to prevent unnecessary computation time after the optimization algorithm diverges. \cr} -#' -#' @return A list with the following elements: -#' \item{learner_estimate}{matrix containing the LEARNER estimate of the target population knowledge graph} -#' \item{objective_values}{numeric vector containing the values of the objective function at each iteration} -#' \item{convergence_criterion}{integer specifying the criterion that was satisfied for terminating the numerical optimization algorithm. A value of 1 indicates the convergence threshold was satisfied; A value of 2 indicates that the maximum number of iterations was satisfied; A value of 3 indicates that the maximum value of the objective function was satisfied.} -#' \item{r}{rank value used.} +#' @description +#' This function applies the LatEnt spAce-based tRaNsfer lEaRning (LEARNER) +#' method (McGrath et al. 2024) to leverage data from a source population to improve +#' estimation of a low-rank matrix in an underrepresented target population. #' -#' @details +#' @param Y_source Matrix containing the source population data, with the same rows +#' and columns as \code{Y_target}. For multiple sources, supply a list of +#' matrices. +#' @param Y_target Matrix containing the target population data. Missing entries +#' are allowed. +#' @param r Rank of the knowledge graphs. If omitted, ScreeNOT (Donoho et al. 2023) +#' is applied to the source population data to select the rank. +#' @param lambda_1 Common source-space penalty. Larger values borrow more +#' information from the source population; zero does not use the source spaces. +#' Use \code{\link{cv.learner}} to select penalty values. +#' @param lambda_2 Balance penalty. Larger values more strongly encourage +#' \eqn{U} and \eqn{V} to have comparable scale. +#' @param step_size Step size in the optimization algorithm. Smaller values may +#' reduce oscillation but require more iterations. +#' @param control List of settings controlling when optimization stops: +#' \describe{ +#' \item{\code{max_iter}}{Maximum number of updates; default \code{100}.} +#' \item{\code{threshold}}{Stop when the absolute change between consecutive +#' objective values is smaller than this value; default \code{0.001}.} +#' \item{\code{max_value}}{Stop if the objective grows beyond this multiple of +#' its preceding value; default \code{10}.}} +#' @param lambda_1_row,lambda_1_col Separate source-space penalties for the row +#' factor \eqn{U} and column factor \eqn{V}, respectively. Use these when the two +#' sides should borrow different amounts of source information. Supply both +#' instead of \code{lambda_1}; equal values reproduce the common penalty. +#' @param source_weights Relative weights of the sources, in the order of +#' \code{Y_source}. Default is equal weights. #' +#' @details #' \strong{Data and notation:} #' -#' The data consists of a matrix in the target population \eqn{Y_0 \in \mathbb{R}^{p \times q}} and the source population \eqn{Y_1 \in \mathbb{R}^{p \times q}}. -#' Let \eqn{\hat{U}_{k} \hat{\Lambda}_{k} \hat{V}_{k}^{\top}} denote the truncated singular value decomposition (SVD) of \eqn{Y_k}, \eqn{k = 0, 1}. +#' The data consists of a matrix in the target population +#' \eqn{Y_0\in\mathbb{R}^{p\times q}} and the source population +#' \eqn{Y_1\in\mathbb{R}^{p\times q}}. Let +#' \eqn{\hat U_k\hat\Lambda_k\hat V_k^\top} denote the rank-\eqn{r} truncated +#' singular value decomposition (SVD) of \eqn{Y_k}, \eqn{k = 0, 1}. #' -#' For \eqn{k = 0, 1}, one can view \eqn{Y_k} as a noisy version of \eqn{\Theta_k}, referred to as the knowledge graph. The target of inference is the target population knowledge graph, \eqn{\Theta_0}. +#' For \eqn{k = 0, 1}, one can view \eqn{Y_k} as a noisy version of +#' \eqn{\Theta_k}, referred to as the knowledge graph. The target of inference +#' is the target population knowledge graph, \eqn{\Theta_0}. #' #' \strong{Estimation:} #' -#' This method estimates \eqn{\Theta_0} by \eqn{\tilde{U}\tilde{V}^{\top}}, where \eqn{(\tilde{U}, \tilde{V})} is the solution to the following optimization problem -#' \deqn{\mathrm{arg\,min}_{U \in \mathbb{R}^{p \times r}, V \in \mathbb{R}^{q \times r}} \big\{ \| U V^{\top} - Y_0 \|_F^2 + \lambda_1\| \mathcal{P}_{\perp}(\hat{U}_{1})U \|_F^2 + \lambda_1\| \mathcal{P}_{\perp}(\hat{V}_{1})V \|_F^2 + \lambda_2 \| U^{\top} U - V^{\top} V \|_F^2 \big\}} -#' where \eqn{\mathcal{P}_{\perp}(\hat{U}_{1}) = I - \hat{U}_{1}^{\top}\hat{U}_{1}} and \eqn{\mathcal{P}_{\perp}(\hat{V}_{1}) = I - \hat{V}_{1}^{\top}\hat{V}_{1}}. +#' This method estimates \eqn{\Theta_0} by \eqn{\tilde U\tilde V^\top}, where +#' \eqn{(\tilde U, \tilde V)} is the solution to the following optimization problem +#' +#' \deqn{\mathrm{arg\,min}_{U\in\mathbb{R}^{p\times r},\,V\in\mathbb{R}^{q\times r}} +#' \big\{\|UV^\top-Y_0\|_F^2 +#' +\lambda_1\|\mathcal{P}_\perp(\hat U_1)U\|_F^2 +#' +\lambda_1\|\mathcal{P}_\perp(\hat V_1)V\|_F^2 +#' +\lambda_2\|U^\top U-V^\top V\|_F^2\big\}} #' -#' This function uses an alternating minimization strategy to solve the optimization problem. That is, this approach updates \eqn{U} by minimizing the objective function (via a gradient descent step) treating \eqn{V} as fixed. Then, \eqn{V} is updated treating \eqn{U} as fixed. These updates of \eqn{U} and \eqn{V} are repeated until convergence. +#' where \eqn{\mathcal{P}_\perp(\hat U_1) = I - \hat U_1\hat U_1^\top} and +#' \eqn{\mathcal{P}_\perp(\hat V_1) = I - \hat V_1\hat V_1^\top}. The four terms measure +#' target fit, departures from the two source spaces, and imbalance between the +#' target factors, respectively. If \code{Y_target} has missing entries, the +#' first term is computed over the observed entries and divided by the observed +#' fraction (the number of observed entries divided by \eqn{pq}). The penalty +#' terms are unchanged. The same adjustment applies to the extensions below. +#' +#' At each iteration, \eqn{U} and \eqn{V} are updated by a gradient +#' descent step, starting from the truncated SVD of the source population data. +#' These updates are repeated until convergence. +#' +#' \strong{Extensions:} +#' +#' Separate penalties \code{lambda_1_row} and \code{lambda_1_col} replace +#' \eqn{\lambda_1} in the second and third terms. For multiple sources, the +#' source projectors are replaced by weighted combinations: +#' +#' \deqn{\bar P_U=\sum_{k=1}^K w_k\hat U_k\hat U_k^\top,\qquad +#' \bar P_V=\sum_{k=1}^K w_k\hat V_k\hat V_k^\top.} +#' +#' where \eqn{\hat U_k} and \eqn{\hat V_k} come from the truncated SVD of +#' the \eqn{k}th source and the weights \eqn{w_k} are given by +#' \code{source_weights}. The full objective is +#' +#' \deqn{\begin{aligned} +#' L(U,V) ={}& \|UV^\top-Y_0\|_F^2 \\ +#' &+\lambda_{1,\mathrm{row}}\|(I_p-\bar P_U)U\|_F^2 \\ +#' &+\lambda_{1,\mathrm{col}}\|(I_q-\bar P_V)V\|_F^2 \\ +#' &+\lambda_2\|U^\top U-V^\top V\|_F^2. +#' \end{aligned}} +#' +#' where \eqn{I_p} and \eqn{I_q} are identity matrices. Equal space penalties +#' give the common-penalty version. With multiple sources, the first source is +#' used to initialize the algorithm and, if \code{r} is not specified, to +#' select the rank. +#' +#' @return +#' A list with the following elements: +#' \item{learner_estimate}{matrix containing the LEARNER estimate of the target population knowledge graph.} +#' \item{objective_values}{numeric vector containing the values of the objective function at each iteration.} +#' \item{convergence_criterion}{stopping code: \code{1}, the absolute objective-change threshold was met; \code{2}, the iteration limit was reached; \code{3}, excessive objective growth or non-finite objective/factors were detected.} +#' \item{r}{rank value used.} #' #' @references #' McGrath, S., Zhu, C,. Guo, M. and Duan, R. (2024). \emph{LEARNER: A transfer learning method for low-rank matrix estimation}. arXiv preprint arXiv:2412.20605. #' #' Donoho, D., Gavish, M. and Romanov, E. (2023). \emph{ScreeNOT: Exact MSE-optimal singular value thresholding in correlated noise}. The Annals of Statistics, 51(1), pp.122-148. #' +#' @seealso +#' \code{\link{cv.learner}} for penalty selection; +#' \code{\link{dlearner}} for direct projection onto source spaces. +#' #' @examples +#' # Single source with a common source-space penalty. #' res <- learner(Y_source = dat_highsim$Y_source, #' Y_target = dat_highsim$Y_target, #' lambda_1 = 1, lambda_2 = 1, #' step_size = 0.003) #' +#' # Same source, with separate penalties for the two factors. +#' res_separate <- learner(Y_source = dat_highsim$Y_source, +#' Y_target = dat_highsim$Y_target, +#' lambda_1_row = 10, lambda_1_col = 1, +#' lambda_2 = 1, step_size = 0.003) +#' +#' # Multiple sources with fixed demonstration weights. +#' res_multi <- learner( +#' Y_source = dat_multisource$Y_source, +#' Y_target = dat_multisource$Y_target, r = 3, +#' source_weights = c(0.7, 0.3), +#' lambda_1_row = 10, lambda_1_col = 1, lambda_2 = 1, +#' step_size = 0.0003, control = list(max_iter = 100)) +#' dim(res_multi$learner_estimate) +#' res_multi$convergence_criterion +#' # Short runs demonstrate usage; they need not meet the stopping threshold. +#' #' @export -learner <- function(Y_source, Y_target, r, lambda_1, lambda_2, step_size, - control = list()) { - ## Error catching - if (!identical(dim(Y_source), dim(Y_target))){ - stop('Y_source and Y_target must have the same dimensions') - } - if (any(is.na(Y_source))){ - stop('Y_source cannot have NA values.') - } - if (length(lambda_1) > 1){ - stop('lambda_1 must be a scalar. See the function cv.learner for selecting a suitable lambda_1 value.') - } - if (length(lambda_2) > 1){ - stop('lambda_2 must be a scalar. See the function cv.learner for selecting a suitable lambda_2 value.') +learner <- function(Y_source, Y_target, r, lambda_1 = NULL, lambda_2, step_size, + control = list(), lambda_1_row = NULL, lambda_1_col = NULL, + source_weights = NULL) { + sources <- prepare_sources(Y_source, Y_target, source_weights) + r <- resolve_rank(if (missing(r)) NULL else r, sources$matrices[[1]]) + control <- prepare_control(control, step_size) + # Resolve the original common penalty or the two independent penalties. + separate <- !is.null(lambda_1_row) || !is.null(lambda_1_col) + if (separate){ + if (!is.null(lambda_1)){ + stop('Provide either lambda_1 or both lambda_1_row and lambda_1_col, not both modes.') + } + if (is.null(lambda_1_row) || is.null(lambda_1_col)){ + stop('Both lambda_1_row and lambda_1_col must be provided together.') + } + validate_space_penalty(lambda_1_row, 'lambda_1_row') + validate_space_penalty(lambda_1_col, 'lambda_1_col') + } else { + if (is.null(lambda_1)){ + stop('Provide lambda_1 or both lambda_1_row and lambda_1_col.') + } + validate_space_penalty(lambda_1, 'lambda_1') + lambda_1_row <- lambda_1 + lambda_1_col <- lambda_1 } + validate_space_penalty(lambda_2, 'lambda_2') - if (missing(r)){ - p <- nrow(Y_source); q <- ncol(Y_source) - max_rank <- min(p, q) / 3 - r <- max(ScreeNOT::adaptiveHardThresholding(Y = Y_source, k = max_rank)$r, 1) - } - if (!('max_iter' %in% names(control))){ - control$max_iter <- 100 - } - if (!('threshold' %in% names(control))){ - control$threshold <- 0.001 - } - if (!('max_value' %in% names(control))){ - control$max_value <- 10 - } - - result <- learner_cpp(Y_source, Y_target, r, lambda_1, lambda_2, step_size, control$max_iter, control$threshold, control$max_value) + result <- learner_cpp(sources$matrices, Y_target, sources$weights, r, + lambda_1_row, lambda_1_col, lambda_2, step_size, + control$max_iter, control$threshold, control$max_value) return(result) } - +validate_space_penalty <- function(value, name) { + if (!is.numeric(value) || length(value) != 1L || + !is.finite(value) || value < 0){ + stop(name, ' must be a finite nonnegative numeric scalar.', call. = FALSE) + } +} diff --git a/data-raw/gen-data.R b/data-raw/gen-data.R index 32d302a..53a7863 100644 --- a/data-raw/gen-data.R +++ b/data-raw/gen-data.R @@ -55,3 +55,38 @@ dat_modsim <- list(Y_source = Y_source, Theta_target = Theta_target) usethis::use_data(dat_modsim, overwrite = TRUE) + +################################################################################ +## Multiple sources with different noise levels +################################################################################ + +# This block can be run on its own without regenerating the existing datasets. +local({ + set.seed(20261014) + p <- 100; q <- 50; r <- 3 + + Theta_target <- matrix(rnorm(p * r), p, r) %*% + matrix(rnorm(r * q), r, q) + target_svd <- svd(Theta_target, nu = r, nv = r) + # Both sources share the target's latent spaces, with reversed signal strengths. + Theta_source <- target_svd$u %*% + diag(rev(target_svd$d[seq_len(r)]), nrow = r, ncol = r) %*% + t(target_svd$v) + + # Variances, not standard deviations. Each call draws independent noise. + noise_variance <- c(target = 0.10, A = 0.01, B = 0.50) + Y_target <- Theta_target + matrix( + rnorm(p * q, sd = sqrt(noise_variance['target'])), p, q) + Y_A <- Theta_source + matrix( + rnorm(p * q, sd = sqrt(noise_variance['A'])), p, q) + Y_B <- Theta_source + matrix( + rnorm(p * q, sd = sqrt(noise_variance['B'])), p, q) + + dat_multisource <- list( + Y_source = list(A = Y_A, B = Y_B), + Y_target = Y_target, + Theta_source = list(A = Theta_source, B = Theta_source), + Theta_target = Theta_target + ) + usethis::use_data(dat_multisource, overwrite = TRUE, version = 2) +}) diff --git a/data/dat_multisource.rda b/data/dat_multisource.rda new file mode 100644 index 0000000000000000000000000000000000000000..21395b444e2ef32a711d2e88a3337194eb58c8db GIT binary patch literal 212592 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%0DY@G&#{g9$tJ5*I_<6GC6^m-nQmn- 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≻bnd_p`B4 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
XA3Ke5f!fTl`lCb8PU4RHr;mwaWT_-j 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¥1m|B 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 UKXKQv5C8FZBvXY61A&#^VEk8;4*&oF literal 0 HcmV?d00001 diff --git a/inst/examples/multiple-sources.R b/inst/examples/multiple-sources.R new file mode 100644 index 0000000..61ea953 --- /dev/null +++ b/inst/examples/multiple-sources.R @@ -0,0 +1,60 @@ +# Demonstration using the built-in simulated multiple-source data. +# Each population has independently generated noise; source A is more precise. +sources <- learner::dat_multisource$Y_source +target <- learner::dat_multisource$Y_target +# Illustrative weights, not weights estimated or tuned from these data. +weights <- c(0.7, 0.3) + +# Tune the U-space, V-space, and balance penalties separately. +set.seed(815) +cv_result <- learner::cv.learner( + Y_source = sources, Y_target = target, r = 3, + source_weights = weights, + lambda_1_row_all = c(1, 10), + lambda_1_col_all = c(1, 3), + lambda_2_all = c(0.1, 1), + step_size = 0.0003, n_folds = 3, + control = list(max_iter = 2000) +) +print(c(row = cv_result$lambda_1_row_min, + col = cv_result$lambda_1_col_min, + balance = cv_result$lambda_2_min)) +print(dim(cv_result$mse_all)) # row grid x column grid x balance grid + +# Refit with the selected penalties using all observed target entries. +fit <- learner::learner( + Y_source = sources, Y_target = target, r = cv_result$r, + source_weights = weights, + lambda_1_row = cv_result$lambda_1_row_min, + lambda_1_col = cv_result$lambda_1_col_min, + lambda_2 = cv_result$lambda_2_min, + step_size = 0.0003, control = list(max_iter = 5000) +) +print(fit$learner_estimate[1:5, 1:5]) +print(fit$convergence_criterion) +# 1: objective-change threshold; 2: iteration limit; 3: excessive growth/breakdown. +# This example demonstrates the workflow, not scientific performance or convergence. + +# D-LEARNER also accepts multiple sources with the same weights. +direct_fit <- learner::dlearner(sources, target, r = 3, source_weights = weights) +print(dim(direct_fit$dlearner_estimate)) + +# Compare source choices using D-LEARNER at the same fixed rank. +# D-LEARNER avoids optimization and penalty tuning as additional differences. +# Truth is available only because this is a simulated dataset. +source_choices <- list( + A_only = sources$A, + B_only = sources$B, + Weighted_A_B = sources +) +comparison <- do.call(rbind, lapply(names(source_choices), function(label) { + estimate <- learner::dlearner( + source_choices[[label]], target, r = 3, + source_weights = if (label == 'Weighted_A_B') weights else NULL + )$dlearner_estimate + data.frame(source = label, + frobenius_error = norm(estimate - learner::dat_multisource$Theta_target, 'F')) +})) +print(comparison, row.names = FALSE) +# Lower Frobenius error is better. These are single-dataset results, not CV MSE. +# The weights 0.7/0.3 are illustrative; combining sources need not beat source A. diff --git a/man/cv.learner.Rd b/man/cv.learner.Rd index 8c0bd0c..609ca27 100644 --- a/man/cv.learner.Rd +++ b/man/cv.learner.Rd @@ -8,45 +8,87 @@ cv.learner( Y_source, Y_target, r, - lambda_1_all, + lambda_1_all = NULL, lambda_2_all, step_size, n_folds = 4, n_cores = 1, - control = list() + control = list(), + lambda_1_row_all = NULL, + lambda_1_col_all = NULL, + source_weights = NULL ) } \arguments{ -\item{Y_source}{matrix containing the source population data, as in \code{\link{learner}}} +\item{Y_source}{Source population data, as in \code{\link{learner}}. +Supply a matrix for one source or a list of matrices for multiple sources.} -\item{Y_target}{matrix containing the target population data, as in \code{\link{learner}}} +\item{Y_target}{Target population data matrix, as in \code{\link{learner}}. +Only observed entries are used to evaluate predictions.} -\item{r}{(optional) integer specifying the rank of the knowledge graphs, as in \code{\link{learner}}} +\item{r}{Rank used in every fold, as in \code{\link{learner}}. It is not +selected by cross-validation.} -\item{lambda_1_all}{vector of numerics specifying the candidate values of \eqn{\lambda_1} (see Details)} +\item{lambda_1_all}{Candidate values for the common source-space penalty +\eqn{\lambda_1}. All combinations with \code{lambda_2_all} are evaluated.} -\item{lambda_2_all}{vector of numerics specifying the candidate values of \eqn{\lambda_2} (see Details)} +\item{lambda_2_all}{Candidate values for the balance penalty \eqn{\lambda_2}.} -\item{step_size}{numeric scalar specifying the step size for the Newton steps in the numerical optimization algorithm, as in \code{\link{learner}}} +\item{step_size}{Step size for each fit, as in \code{\link{learner}}.} -\item{n_folds}{an integer specify the number of cross-validation folds. The default is \code{4}.} +\item{n_folds}{Number of cross-validation folds. Default is \code{4}.} -\item{n_cores}{an integer specifying the number of CPU cores in OpenMP parallelization. Parallelization is performed across the different candidate \eqn{(\lambda_1, \lambda_2)} pairs. The default is \code{1}, i.e., no parallelization.} +\item{n_cores}{Number of CPU cores used to evaluate the candidate penalty +combinations in parallel. Default is \code{1}, i.e., no parallelization.} -\item{control}{a list of parameters for controlling the stopping criteria for the numerical optimization algorithm, as in \code{\link{learner}}.} +\item{control}{Optimization settings for each fit; see \code{\link{learner}}.} + +\item{lambda_1_row_all, lambda_1_col_all}{Candidate values for separate +penalties on the row and column factors. Supply both instead of +\code{lambda_1_all}; all combinations with \code{lambda_2_all} are evaluated.} + +\item{source_weights}{Relative source weights, as in \code{\link{learner}}. The weights +are not selected by cross-validation. Default is equal weights.} } \value{ -A list with the following elements: -\item{lambda_1_min}{value of \eqn{\lambda_1} with the smallest MSE} -\item{lambda_2_min}{value of \eqn{\lambda_2} with the smallest MSE} -\item{mse_all}{matrix containing MSE value for each \eqn{(\lambda_1, \lambda_2)} pair. The rows correspond to the \eqn{\lambda_1} values, and the columns correspond to the \eqn{\lambda_2} values.} -\item{r}{rank value used.} +A list containing: +\item{lambda_1_min}{Common source-space penalty in the selected combination. +\code{NA} when separate penalties are used.} +\item{lambda_2_min}{Balance penalty in the selected combination.} +\item{lambda_1_row_min, lambda_1_col_min}{Row and column penalties in the +selected combination. Returned only when separate penalties are used.} +\item{mse_all}{Sum of held-out squared errors for each candidate combination. +For common penalties, rows correspond to \code{lambda_1_all} and columns to +\code{lambda_2_all}. For separate penalties, the three dimensions correspond +to the row, column, and balance grids, in that order. Divide by the number +of observed target entries to obtain mean squared errors.} +\item{r}{Rank used in the fits.} } \description{ -This function performs k-fold cross-validation to select the nuisance parameters \eqn{(\lambda_1, \lambda_2)} for \code{\link{learner}}. +Performs k-fold cross-validation to select the source-space and balance +penalties for \code{\link{learner}}. Returns prediction errors and the +penalty combination with the smallest error. } \details{ -Given sets of candidate values of \eqn{\lambda_1} and \eqn{\lambda_2}, this function performs k-fold cross-validation to select the pair \eqn{(\lambda_1, \lambda_2)} with the smallest held out error. This function randomly partitions the entries of \code{Y_target} into \eqn{k} (approximately) equally sized subsamples. The training data sets are obtained by removing one of the \eqn{k} subsamples and the corresponding test data sets are based on the held out subsamples. The \code{\link{learner}} function is applied to each training data set. The held out error is computed by the mean squared error comparing the entries in the test data sets with those imputed from the LEARNER estimates. See McGrath et al. (2024) for further details. +Given sets of candidate values of \eqn{\lambda_1} and \eqn{\lambda_2}, this +function performs k-fold cross-validation to select the pair +\eqn{(\lambda_1, \lambda_2)} with the smallest held out error. This function +randomly partitions the entries of \code{Y_target} into \eqn{k} +(approximately) equally sized subsamples. The training data sets are obtained +by removing one of the \eqn{k} subsamples and the corresponding test data +sets are based on the held out subsamples. The \code{\link{learner}} function is +applied to each training data set. The held out error is computed by comparing +the entries in the test data sets with those imputed from the LEARNER +estimates. See McGrath et al. (2024) for further details. + +With separate penalties, the procedure selects the row, column, and balance +penalties together. Both modes can be used with multiple sources. Call +\code{set.seed()} first to reproduce the random partition. + +To obtain the final estimate, apply \code{\link{learner}} with the selected +penalties to the full data (see Examples). Fits that reach the iteration +limit still contribute to the held out error, so check the settings in +\code{control} before interpreting the selection. } \examples{ res <- cv.learner(Y_source = dat_highsim$Y_source, @@ -55,9 +97,41 @@ res <- cv.learner(Y_source = dat_highsim$Y_source, lambda_2_all = c(1, 10, 100), step_size = 0.003) +# Refit using the selected penalties and all observed target entries. +fit <- learner(dat_highsim$Y_source, dat_highsim$Y_target, r = res$r, + lambda_1 = res$lambda_1_min, lambda_2 = res$lambda_2_min, + step_size = 0.003) +fit$convergence_criterion +# Multiple sources with fixed demonstration weights. +sources <- dat_multisource$Y_source +target <- dat_multisource$Y_target +weights <- c(0.7, 0.3) + +set.seed(815) +res_separate <- cv.learner( + Y_source = sources, Y_target = target, r = 3, + source_weights = weights, + lambda_1_row_all = c(1, 10), lambda_1_col_all = c(1, 3), + lambda_2_all = c(0.1, 1), step_size = 0.0003, + n_folds = 2, control = list(max_iter = 100)) +dim(res_separate$mse_all) # row grid x column grid x balance grid + +fit <- learner( + Y_source = sources, Y_target = target, r = res_separate$r, + source_weights = weights, + lambda_1_row = res_separate$lambda_1_row_min, + lambda_1_col = res_separate$lambda_1_col_min, + lambda_2 = res_separate$lambda_2_min, step_size = 0.0003, + control = list(max_iter = 100)) +fit$convergence_criterion +# This short example demonstrates the workflow; check convergence before +# interpreting results or comparing statistical performance. } \references{ McGrath, S., Zhu, C,. Guo, M. and Duan, R. (2024). \emph{LEARNER: A transfer learning method for low-rank matrix estimation}. arXiv preprint arXiv:2412.20605. } +\seealso{ +\code{\link{learner}} for fitting with the selected penalties. +} diff --git a/man/dat_multisource.Rd b/man/dat_multisource.Rd new file mode 100644 index 0000000..32bc0f1 --- /dev/null +++ b/man/dat_multisource.Rd @@ -0,0 +1,54 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data-multisource.R +\docType{data} +\name{dat_multisource} +\alias{dat_multisource} +\title{Simulated data set: Multiple sources with different noise levels} +\format{ +A list with four components. All matrices have 100 rows and 50 columns, + with corresponding rows and columns aligned across populations. +\describe{ + \item{\code{Y_source}}{A named list of observed source matrices, \code{A} + and \code{B}, suitable for the \code{Y_source} argument.} + \item{\code{Y_target}}{The observed target matrix.} + \item{\code{Theta_source}}{A named list of the true rank-3 source matrices, + \code{A} and \code{B}. The two true matrices are identical.} + \item{\code{Theta_target}}{The true rank-3 target matrix.} +} +} +\usage{ +dat_multisource +} +\description{ +Simulated matrices for one target population and two source populations. +The sources share the target's latent row and column spaces, but source A +is observed more precisely than source B. This data set illustrates fitting +LEARNER and D-LEARNER with multiple sources. +} +\details{ +The source signal is obtained by reversing the three nonzero singular values +of the target signal while keeping its singular vectors. Each observed matrix +is generated by adding independent, mean-zero normal noise to its own signal. +Noise is independent across entries and populations, with variances 0.10 for +the target, 0.01 for source A, and 0.50 for source B. Thus, source A has less +noise than the target and source B has more. Source B is not generated from +the observed source A matrix. + +The true signal matrices are included for illustration and estimation-error +calculations; they are not inputs to the fitting functions. These simulated +data are a usage example, not a reproduction of the paper's simulation study. +} +\examples{ +data(dat_multisource) +fit <- dlearner( + Y_source = dat_multisource$Y_source, + Y_target = dat_multisource$Y_target, + r = 3, source_weights = c(0.7, 0.3) +) +dim(fit$dlearner_estimate) +} +\seealso{ +\code{\link{dat_highsim}}, \code{\link{dat_modsim}}, + \code{\link{learner}}, \code{\link{dlearner}} +} +\keyword{datasets} diff --git a/man/dlearner.Rd b/man/dlearner.Rd index f1c4563..4d9bbbb 100644 --- a/man/dlearner.Rd +++ b/man/dlearner.Rd @@ -2,16 +2,23 @@ % Please edit documentation in R/dlearner.R \name{dlearner} \alias{dlearner} -\title{Latent space-based transfer learning} +\title{Direct projection transfer learning} \usage{ -dlearner(Y_source, Y_target, r) +dlearner(Y_source, Y_target, r, source_weights = NULL) } \arguments{ -\item{Y_source}{matrix containing the source population data} +\item{Y_source}{Matrix containing the source population data, with the same rows +and columns as \code{Y_target}. For multiple sources, supply a list of +matrices.} -\item{Y_target}{matrix containing the target population data} +\item{Y_target}{Matrix containing the target population data. Missing entries +are not allowed.} -\item{r}{(optional) integer specifying the rank of the knowledge graphs. By default, ScreeNOT (Donoho et al. 2023) is applied to the source population knowledge graph to select the rank.} +\item{r}{Rank of the knowledge graphs. If omitted, ScreeNOT (Donoho et al. 2023) +is applied to the source population data to select the rank.} + +\item{source_weights}{Relative weights of the sources, in the order of +\code{Y_source}. Default is equal weights.} } \value{ A list with the following components: @@ -19,26 +26,65 @@ A list with the following components: \item{r}{rank value used.} } \description{ -This function applies the Direct project LatEnt spAce-based tRaNsfer lEaRning (D-LEARNER) method (McGrath et al. 2024) to leverage data from a source population to improve -estimation of a low rank matrix in an underrepresented target population. +This function applies the Direct projection LatEnt spAce-based tRaNsfer +lEaRning (D-LEARNER) method (McGrath et al. 2024) to leverage data from a source +population to improve estimation of a low-rank matrix in an underrepresented +target population. } \details{ \strong{Data and notation:} -The data consists of a matrix in the target population \eqn{Y_0 \in \mathbb{R}^{p \times q}} and the source population \eqn{Y_1 \in \mathbb{R}^{p \times q}}. -Let \eqn{\hat{U}_{k} \hat{\Lambda}_{k} \hat{V}_{k}^{\top}} denote the truncated singular value decomposition (SVD) of \eqn{Y_k}, \eqn{k = 0, 1}. +The data consists of a matrix in the target population +\eqn{Y_0 \in \mathbb{R}^{p \times q}} and the source population +\eqn{Y_1 \in \mathbb{R}^{p \times q}}. Let +\eqn{\hat U_k\hat\Lambda_k\hat V_k^\top} denote the rank-\eqn{r} truncated +singular value decomposition (SVD) of \eqn{Y_k}, \eqn{k = 0, 1}. -For \eqn{k = 0, 1}, one can view \eqn{Y_k} as a noisy version of \eqn{\Theta_k}, referred to as the knowledge graph. The target of inference is the target population knowledge graph, \eqn{\Theta_0}. +For \eqn{k = 0, 1}, one can view \eqn{Y_k} as a noisy version of +\eqn{\Theta_k}, referred to as the knowledge graph. The target of inference +is the target population knowledge graph, \eqn{\Theta_0}. \strong{Estimation:} -This method estimates \eqn{\Theta_0} by \eqn{\hat{U}_{1}^{\top}\hat{U}_{1} Y_0 \hat{V}_{1}^{\top}\hat{V}_{1}}. +This method estimates \eqn{\Theta_0} by + +\deqn{\hat U_1\hat U_1^\top Y_0 \hat V_1\hat V_1^\top.} + +That is, the target population data are projected onto the latent row and +column spaces of the source population, without iterative fitting or penalty +selection. + +\strong{Multiple sources:} + +Supply a list of source matrices to combine information from several +populations. Their projection operators are averaged using +\code{source_weights}, and the estimate becomes + +\deqn{\widehat\Theta_0=\bar P_U Y_0\bar P_V,\qquad +\bar P_U=\sum_{k=1}^K w_k\hat U_k\hat U_k^\top,\qquad +\bar P_V=\sum_{k=1}^K w_k\hat V_k\hat V_k^\top.} + +where \eqn{\hat U_k} and \eqn{\hat V_k} come from the truncated SVD of +the \eqn{k}th source and the weights \eqn{w_k} are given by +\code{source_weights}. If \code{r} is not specified, the rank is selected +using the first source. } \examples{ res <- dlearner(Y_source = dat_highsim$Y_source, Y_target = dat_highsim$Y_target) +# Multiple sources with fixed demonstration weights. +res_multi <- dlearner( + Y_source = dat_multisource$Y_source, + Y_target = dat_multisource$Y_target, r = 3, + source_weights = c(0.7, 0.3)) +dim(res_multi$dlearner_estimate) + } \references{ Donoho, D., Gavish, M. and Romanov, E. (2023). \emph{ScreeNOT: Exact MSE-optimal singular value thresholding in correlated noise}. The Annals of Statistics, 51(1), pp.122-148. } +\seealso{ +\code{\link{learner}} for a target fit that can adapt the source +spaces through penalized estimation. +} diff --git a/man/learner.Rd b/man/learner.Rd index e1bdce4..a56809b 100644 --- a/man/learner.Rd +++ b/man/learner.Rd @@ -4,63 +4,160 @@ \alias{learner} \title{Latent space-based transfer learning} \usage{ -learner(Y_source, Y_target, r, lambda_1, lambda_2, step_size, control = list()) +learner( + Y_source, + Y_target, + r, + lambda_1 = NULL, + lambda_2, + step_size, + control = list(), + lambda_1_row = NULL, + lambda_1_col = NULL, + source_weights = NULL +) } \arguments{ -\item{Y_source}{matrix containing the source population data} +\item{Y_source}{Matrix containing the source population data, with the same rows +and columns as \code{Y_target}. For multiple sources, supply a list of +matrices.} -\item{Y_target}{matrix containing the target population data} +\item{Y_target}{Matrix containing the target population data. Missing entries +are allowed.} -\item{r}{(optional) integer specifying the rank of the knowledge graphs. By default, ScreeNOT (Donoho et al. 2023) is applied to the source population knowledge graph to select the rank.} +\item{r}{Rank of the knowledge graphs. If omitted, ScreeNOT (Donoho et al. 2023) +is applied to the source population data to select the rank.} -\item{lambda_1}{numeric scalar specifying the value of \eqn{\lambda_1} (see Details)} +\item{lambda_1}{Common source-space penalty. Larger values borrow more +information from the source population; zero does not use the source spaces. +Use \code{\link{cv.learner}} to select penalty values.} -\item{lambda_2}{numeric scalar specifying the value of \eqn{\lambda_2} (see Details)} +\item{lambda_2}{Balance penalty. Larger values more strongly encourage +\eqn{U} and \eqn{V} to have comparable scale.} -\item{step_size}{numeric scalar specifying the step size for the Newton steps in the numerical optimization algorithm} +\item{step_size}{Step size in the optimization algorithm. Smaller values may +reduce oscillation but require more iterations.} -\item{control}{a list of parameters for controlling the stopping criteria for the numerical optimization algorithm. The list may include the following components: -\tabular{ll}{ -\code{max_iter} \tab integer specifying the maximum number of iterations \cr -\code{threshold} \tab numeric scalar specifying a convergence threshold. The algorithm converges when \eqn{|\epsilon_t - \epsilon_{t-1}| < }\code{threshold}, where \eqn{\epsilon_t} denotes the value of the objective function at iteration \eqn{t}. \cr -\code{max_value} \tab numeric scalar used to specify the maximum value of the objective function allowed before terminating the algorithm. Specifically, the algorithm will terminate if the value of the objective function exceeds \code{max_value}\eqn{\times \epsilon_0}, where \eqn{\epsilon_0} denotes the value of the objective function at the initial point. This is used to prevent unnecessary computation time after the optimization algorithm diverges. \cr}} +\item{control}{List of settings controlling when optimization stops: +\describe{ +\item{\code{max_iter}}{Maximum number of updates; default \code{100}.} +\item{\code{threshold}}{Stop when the absolute change between consecutive +objective values is smaller than this value; default \code{0.001}.} +\item{\code{max_value}}{Stop if the objective grows beyond this multiple of +its preceding value; default \code{10}.}}} + +\item{lambda_1_row, lambda_1_col}{Separate source-space penalties for the row +factor \eqn{U} and column factor \eqn{V}, respectively. Use these when the two +sides should borrow different amounts of source information. Supply both +instead of \code{lambda_1}; equal values reproduce the common penalty.} + +\item{source_weights}{Relative weights of the sources, in the order of +\code{Y_source}. Default is equal weights.} } \value{ A list with the following elements: -\item{learner_estimate}{matrix containing the LEARNER estimate of the target population knowledge graph} -\item{objective_values}{numeric vector containing the values of the objective function at each iteration} -\item{convergence_criterion}{integer specifying the criterion that was satisfied for terminating the numerical optimization algorithm. A value of 1 indicates the convergence threshold was satisfied; A value of 2 indicates that the maximum number of iterations was satisfied; A value of 3 indicates that the maximum value of the objective function was satisfied.} +\item{learner_estimate}{matrix containing the LEARNER estimate of the target population knowledge graph.} +\item{objective_values}{numeric vector containing the values of the objective function at each iteration.} +\item{convergence_criterion}{stopping code: \code{1}, the absolute objective-change threshold was met; \code{2}, the iteration limit was reached; \code{3}, excessive objective growth or non-finite objective/factors were detected.} \item{r}{rank value used.} } \description{ -This function applies the LatEnt spAce-based tRaNsfer lEaRning (LEARNER) method (McGrath et al. 2024) to leverage data from a source population to improve -estimation of a low rank matrix in an underrepresented target population. +This function applies the LatEnt spAce-based tRaNsfer lEaRning (LEARNER) +method (McGrath et al. 2024) to leverage data from a source population to improve +estimation of a low-rank matrix in an underrepresented target population. } \details{ \strong{Data and notation:} -The data consists of a matrix in the target population \eqn{Y_0 \in \mathbb{R}^{p \times q}} and the source population \eqn{Y_1 \in \mathbb{R}^{p \times q}}. -Let \eqn{\hat{U}_{k} \hat{\Lambda}_{k} \hat{V}_{k}^{\top}} denote the truncated singular value decomposition (SVD) of \eqn{Y_k}, \eqn{k = 0, 1}. +The data consists of a matrix in the target population +\eqn{Y_0\in\mathbb{R}^{p\times q}} and the source population +\eqn{Y_1\in\mathbb{R}^{p\times q}}. Let +\eqn{\hat U_k\hat\Lambda_k\hat V_k^\top} denote the rank-\eqn{r} truncated +singular value decomposition (SVD) of \eqn{Y_k}, \eqn{k = 0, 1}. -For \eqn{k = 0, 1}, one can view \eqn{Y_k} as a noisy version of \eqn{\Theta_k}, referred to as the knowledge graph. The target of inference is the target population knowledge graph, \eqn{\Theta_0}. +For \eqn{k = 0, 1}, one can view \eqn{Y_k} as a noisy version of +\eqn{\Theta_k}, referred to as the knowledge graph. The target of inference +is the target population knowledge graph, \eqn{\Theta_0}. \strong{Estimation:} -This method estimates \eqn{\Theta_0} by \eqn{\tilde{U}\tilde{V}^{\top}}, where \eqn{(\tilde{U}, \tilde{V})} is the solution to the following optimization problem -\deqn{\mathrm{arg\,min}_{U \in \mathbb{R}^{p \times r}, V \in \mathbb{R}^{q \times r}} \big\{ \| U V^{\top} - Y_0 \|_F^2 + \lambda_1\| \mathcal{P}_{\perp}(\hat{U}_{1})U \|_F^2 + \lambda_1\| \mathcal{P}_{\perp}(\hat{V}_{1})V \|_F^2 + \lambda_2 \| U^{\top} U - V^{\top} V \|_F^2 \big\}} -where \eqn{\mathcal{P}_{\perp}(\hat{U}_{1}) = I - \hat{U}_{1}^{\top}\hat{U}_{1}} and \eqn{\mathcal{P}_{\perp}(\hat{V}_{1}) = I - \hat{V}_{1}^{\top}\hat{V}_{1}}. +This method estimates \eqn{\Theta_0} by \eqn{\tilde U\tilde V^\top}, where +\eqn{(\tilde U, \tilde V)} is the solution to the following optimization problem + +\deqn{\mathrm{arg\,min}_{U\in\mathbb{R}^{p\times r},\,V\in\mathbb{R}^{q\times r}} + \big\{\|UV^\top-Y_0\|_F^2 + +\lambda_1\|\mathcal{P}_\perp(\hat U_1)U\|_F^2 + +\lambda_1\|\mathcal{P}_\perp(\hat V_1)V\|_F^2 + +\lambda_2\|U^\top U-V^\top V\|_F^2\big\}} + +where \eqn{\mathcal{P}_\perp(\hat U_1) = I - \hat U_1\hat U_1^\top} and +\eqn{\mathcal{P}_\perp(\hat V_1) = I - \hat V_1\hat V_1^\top}. The four terms measure +target fit, departures from the two source spaces, and imbalance between the +target factors, respectively. If \code{Y_target} has missing entries, the +first term is computed over the observed entries and divided by the observed +fraction (the number of observed entries divided by \eqn{pq}). The penalty +terms are unchanged. The same adjustment applies to the extensions below. + +At each iteration, \eqn{U} and \eqn{V} are updated by a gradient +descent step, starting from the truncated SVD of the source population data. +These updates are repeated until convergence. + +\strong{Extensions:} + +Separate penalties \code{lambda_1_row} and \code{lambda_1_col} replace +\eqn{\lambda_1} in the second and third terms. For multiple sources, the +source projectors are replaced by weighted combinations: -This function uses an alternating minimization strategy to solve the optimization problem. That is, this approach updates \eqn{U} by minimizing the objective function (via a gradient descent step) treating \eqn{V} as fixed. Then, \eqn{V} is updated treating \eqn{U} as fixed. These updates of \eqn{U} and \eqn{V} are repeated until convergence. +\deqn{\bar P_U=\sum_{k=1}^K w_k\hat U_k\hat U_k^\top,\qquad + \bar P_V=\sum_{k=1}^K w_k\hat V_k\hat V_k^\top.} + +where \eqn{\hat U_k} and \eqn{\hat V_k} come from the truncated SVD of +the \eqn{k}th source and the weights \eqn{w_k} are given by +\code{source_weights}. The full objective is + +\deqn{\begin{aligned} +L(U,V) ={}& \|UV^\top-Y_0\|_F^2 \\ +&+\lambda_{1,\mathrm{row}}\|(I_p-\bar P_U)U\|_F^2 \\ +&+\lambda_{1,\mathrm{col}}\|(I_q-\bar P_V)V\|_F^2 \\ +&+\lambda_2\|U^\top U-V^\top V\|_F^2. +\end{aligned}} + +where \eqn{I_p} and \eqn{I_q} are identity matrices. Equal space penalties +give the common-penalty version. With multiple sources, the first source is +used to initialize the algorithm and, if \code{r} is not specified, to +select the rank. } \examples{ +# Single source with a common source-space penalty. res <- learner(Y_source = dat_highsim$Y_source, Y_target = dat_highsim$Y_target, lambda_1 = 1, lambda_2 = 1, step_size = 0.003) +# Same source, with separate penalties for the two factors. +res_separate <- learner(Y_source = dat_highsim$Y_source, + Y_target = dat_highsim$Y_target, + lambda_1_row = 10, lambda_1_col = 1, + lambda_2 = 1, step_size = 0.003) + +# Multiple sources with fixed demonstration weights. +res_multi <- learner( + Y_source = dat_multisource$Y_source, + Y_target = dat_multisource$Y_target, r = 3, + source_weights = c(0.7, 0.3), + lambda_1_row = 10, lambda_1_col = 1, lambda_2 = 1, + step_size = 0.0003, control = list(max_iter = 100)) +dim(res_multi$learner_estimate) +res_multi$convergence_criterion +# Short runs demonstrate usage; they need not meet the stopping threshold. + } \references{ McGrath, S., Zhu, C,. Guo, M. and Duan, R. (2024). \emph{LEARNER: A transfer learning method for low-rank matrix estimation}. arXiv preprint arXiv:2412.20605. Donoho, D., Gavish, M. and Romanov, E. (2023). \emph{ScreeNOT: Exact MSE-optimal singular value thresholding in correlated noise}. The Annals of Statistics, 51(1), pp.122-148. } +\seealso{ +\code{\link{cv.learner}} for penalty selection; +\code{\link{dlearner}} for direct projection onto source spaces. +} diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index f39d9a3..0574cb1 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -12,43 +12,46 @@ Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); #endif // learner_cpp -List learner_cpp(const Eigen::MatrixXd& Y_source, const Eigen::MatrixXd& Y_target, int r, double lambda1, double lambda2, double step_size, int max_iter, double threshold, double max_value); -RcppExport SEXP _learner_learner_cpp(SEXP Y_sourceSEXP, SEXP Y_targetSEXP, SEXP rSEXP, SEXP lambda1SEXP, SEXP lambda2SEXP, SEXP step_sizeSEXP, SEXP max_iterSEXP, SEXP thresholdSEXP, SEXP max_valueSEXP) { +List learner_cpp(const Rcpp::List& Y_source, const Eigen::MatrixXd& Y_target, const std::vector& source_weights, int r, double lambda1_row, double lambda1_col, double lambda2, double step_size, int max_iter, double threshold, double max_value); +RcppExport SEXP _learner_learner_cpp(SEXP Y_sourceSEXP, SEXP Y_targetSEXP, SEXP source_weightsSEXP, SEXP rSEXP, SEXP lambda1_rowSEXP, SEXP lambda1_colSEXP, SEXP lambda2SEXP, SEXP step_sizeSEXP, SEXP max_iterSEXP, SEXP thresholdSEXP, SEXP max_valueSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< const Eigen::MatrixXd& >::type Y_source(Y_sourceSEXP); + Rcpp::traits::input_parameter< const Rcpp::List& >::type Y_source(Y_sourceSEXP); Rcpp::traits::input_parameter< const Eigen::MatrixXd& >::type Y_target(Y_targetSEXP); + Rcpp::traits::input_parameter< const std::vector& >::type source_weights(source_weightsSEXP); Rcpp::traits::input_parameter< int >::type r(rSEXP); - Rcpp::traits::input_parameter< double >::type lambda1(lambda1SEXP); + Rcpp::traits::input_parameter< double >::type lambda1_row(lambda1_rowSEXP); + Rcpp::traits::input_parameter< double >::type lambda1_col(lambda1_colSEXP); Rcpp::traits::input_parameter< double >::type lambda2(lambda2SEXP); Rcpp::traits::input_parameter< double >::type step_size(step_sizeSEXP); Rcpp::traits::input_parameter< int >::type max_iter(max_iterSEXP); Rcpp::traits::input_parameter< double >::type threshold(thresholdSEXP); Rcpp::traits::input_parameter< double >::type max_value(max_valueSEXP); - rcpp_result_gen = Rcpp::wrap(learner_cpp(Y_source, Y_target, r, lambda1, lambda2, step_size, max_iter, threshold, max_value)); + rcpp_result_gen = Rcpp::wrap(learner_cpp(Y_source, Y_target, source_weights, r, lambda1_row, lambda1_col, lambda2, step_size, max_iter, threshold, max_value)); return rcpp_result_gen; END_RCPP } // cv_learner_cpp -List cv_learner_cpp(const Eigen::MatrixXd& Y_source, const Eigen::MatrixXd& Y_target, const std::vector& lambda1_all, const std::vector& lambda2_all, double step_size, int n_folds, int max_iter, double threshold, int n_cores, int r, double max_value, const std::vector>& index_set); -RcppExport SEXP _learner_cv_learner_cpp(SEXP Y_sourceSEXP, SEXP Y_targetSEXP, SEXP lambda1_allSEXP, SEXP lambda2_allSEXP, SEXP step_sizeSEXP, SEXP n_foldsSEXP, SEXP max_iterSEXP, SEXP thresholdSEXP, SEXP n_coresSEXP, SEXP rSEXP, SEXP max_valueSEXP, SEXP index_setSEXP) { +std::vector cv_learner_cpp(const Rcpp::List& Y_source, const Eigen::MatrixXd& Y_target, const std::vector& source_weights, const std::vector& row_grid, const std::vector& col_grid, const std::vector& balance_grid, double step_size, int max_iter, double threshold, int n_cores, int r, double max_value, const std::vector>& index_set); +RcppExport SEXP _learner_cv_learner_cpp(SEXP Y_sourceSEXP, SEXP Y_targetSEXP, SEXP source_weightsSEXP, SEXP row_gridSEXP, SEXP col_gridSEXP, SEXP balance_gridSEXP, SEXP step_sizeSEXP, SEXP max_iterSEXP, SEXP thresholdSEXP, SEXP n_coresSEXP, SEXP rSEXP, SEXP max_valueSEXP, SEXP index_setSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< const Eigen::MatrixXd& >::type Y_source(Y_sourceSEXP); + Rcpp::traits::input_parameter< const Rcpp::List& >::type Y_source(Y_sourceSEXP); Rcpp::traits::input_parameter< const Eigen::MatrixXd& >::type Y_target(Y_targetSEXP); - Rcpp::traits::input_parameter< const std::vector& >::type lambda1_all(lambda1_allSEXP); - Rcpp::traits::input_parameter< const std::vector& >::type lambda2_all(lambda2_allSEXP); + Rcpp::traits::input_parameter< const std::vector& >::type source_weights(source_weightsSEXP); + Rcpp::traits::input_parameter< const std::vector& >::type row_grid(row_gridSEXP); + Rcpp::traits::input_parameter< const std::vector& >::type col_grid(col_gridSEXP); + Rcpp::traits::input_parameter< const std::vector& >::type balance_grid(balance_gridSEXP); Rcpp::traits::input_parameter< double >::type step_size(step_sizeSEXP); - Rcpp::traits::input_parameter< int >::type n_folds(n_foldsSEXP); Rcpp::traits::input_parameter< int >::type max_iter(max_iterSEXP); Rcpp::traits::input_parameter< double >::type threshold(thresholdSEXP); Rcpp::traits::input_parameter< int >::type n_cores(n_coresSEXP); Rcpp::traits::input_parameter< int >::type r(rSEXP); Rcpp::traits::input_parameter< double >::type max_value(max_valueSEXP); Rcpp::traits::input_parameter< const std::vector>& >::type index_set(index_setSEXP); - rcpp_result_gen = Rcpp::wrap(cv_learner_cpp(Y_source, Y_target, lambda1_all, lambda2_all, step_size, n_folds, max_iter, threshold, n_cores, r, max_value, index_set)); + rcpp_result_gen = Rcpp::wrap(cv_learner_cpp(Y_source, Y_target, source_weights, row_grid, col_grid, balance_grid, step_size, max_iter, threshold, n_cores, r, max_value, index_set)); return rcpp_result_gen; END_RCPP } @@ -64,8 +67,8 @@ END_RCPP } static const R_CallMethodDef CallEntries[] = { - {"_learner_learner_cpp", (DL_FUNC) &_learner_learner_cpp, 9}, - {"_learner_cv_learner_cpp", (DL_FUNC) &_learner_cv_learner_cpp, 12}, + {"_learner_learner_cpp", (DL_FUNC) &_learner_learner_cpp, 11}, + {"_learner_cv_learner_cpp", (DL_FUNC) &_learner_cv_learner_cpp, 13}, {"_learner_omp_max_threads", (DL_FUNC) &_learner_omp_max_threads, 0}, {NULL, NULL, 0} }; diff --git a/src/kernels.cpp b/src/kernels.cpp index dbf2ed3..f6d09b0 100644 --- a/src/kernels.cpp +++ b/src/kernels.cpp @@ -12,31 +12,56 @@ using namespace Rcpp; using namespace Eigen; -//-------------------------------------------------------------- -// Internal worker function: computes the learner estimate - thread safe for OMP -List learner_worker(const Eigen::MatrixXd &Y_source, - const Eigen::MatrixXd &Y_target, - int r, double lambda1, double lambda2, - double step_size, int max_iter, double threshold, - double max_value) { - - Eigen::BDCSVD svd(Y_source, Eigen::ComputeThinU | Eigen::ComputeThinV); - Eigen::MatrixXd U_full = svd.matrixU(); - Eigen::MatrixXd V_full = svd.matrixV(); - int r_use = std::min(r, static_cast(U_full.cols())); - Eigen::MatrixXd U_trunc = U_full.leftCols(r_use); - Eigen::MatrixXd V_trunc = V_full.leftCols(r_use); - Eigen::VectorXd singular_vals = svd.singularValues().head(r_use); - - // Initialize as in R: U_init = U_trunc * sqrt(D), V_init = V_trunc * sqrt(D) - Eigen::MatrixXd sqrtD = singular_vals.array().sqrt().matrix().asDiagonal(); - Eigen::MatrixXd U = U_trunc * sqrtD; - Eigen::MatrixXd V = V_trunc * sqrtD; - - // Precompute reusable matrices - Eigen::MatrixXd U_trunc_T = U_trunc.transpose(); - Eigen::MatrixXd V_trunc_T = V_trunc.transpose(); +// Source decompositions are prepared once on the R thread and shared read-only. +struct SourceSpaces { + std::vector u, v; + std::vector weights; + Eigen::MatrixXd initial_u, initial_v; +}; + +SourceSpaces prepare_spaces(const Rcpp::List &sources, + const std::vector &weights, int r) { + SourceSpaces spaces; + spaces.weights = weights; + for (R_xlen_t k = 0; k < sources.size(); ++k) { + Eigen::MatrixXd source = Rcpp::as(sources[k]); + Eigen::BDCSVD svd(source, Eigen::ComputeThinU | Eigen::ComputeThinV); + spaces.u.push_back(svd.matrixU().leftCols(r)); + spaces.v.push_back(svd.matrixV().leftCols(r)); + if (k == 0) { + Eigen::MatrixXd root = svd.singularValues().head(r).array().sqrt().matrix().asDiagonal(); + spaces.initial_u = spaces.u[0] * root; + spaces.initial_v = spaces.v[0] * root; + } + } + return spaces; +} + +// Apply I - sum(w_k B_k B_k') without allocating a p-by-p projector. +Eigen::MatrixXd space_residual(const std::vector &bases, + const std::vector &weights, + const Eigen::MatrixXd &value) { + Eigen::MatrixXd projected = Eigen::MatrixXd::Zero(value.rows(), value.cols()); + for (size_t k = 0; k < bases.size(); ++k) { + projected.noalias() += weights[k] * (bases[k] * (bases[k].transpose() * value)); + } + return value - projected; +} +// Workers use no R objects or allocations, including inside the OpenMP loop. +struct FitResult { + Eigen::MatrixXd estimate; + std::vector objective; + int criterion; +}; + +FitResult learner_worker(const SourceSpaces &spaces, + const Eigen::MatrixXd &Y_target, + double lambda1_row, double lambda1_col, double lambda2, + double step_size, int max_iter, double threshold, + double max_value) { + Eigen::MatrixXd U = spaces.initial_u; + Eigen::MatrixXd V = spaces.initial_v; double perc_nonmissing = 1.0 - (static_cast((Y_target.array().isNaN()).count()) / Y_target.size()); bool missing = Y_target.hasNaN(); @@ -47,8 +72,8 @@ List learner_worker(const Eigen::MatrixXd &Y_source, diff = diff.array().isNaN().select(Eigen::MatrixXd::Zero(diff.rows(), diff.cols()), diff); } obj_init = diff.squaredNorm() / perc_nonmissing + - lambda1 * (U - U_trunc * (U_trunc_T * U)).squaredNorm() + - lambda1 * (V - V_trunc * (V_trunc_T * V)).squaredNorm() + + lambda1_row * space_residual(spaces.u, spaces.weights, U).squaredNorm() + + lambda1_col * space_residual(spaces.v, spaces.weights, V).squaredNorm() + lambda2 * (U.transpose() * U - V.transpose() * V).squaredNorm(); } @@ -71,12 +96,20 @@ List learner_worker(const Eigen::MatrixXd &Y_source, adjusted_theta = adjusted_theta.array().isNaN().select(temp, adjusted_theta); } + Eigen::MatrixXd residual_u = space_residual(spaces.u, spaces.weights, U); + Eigen::MatrixXd residual_v = space_residual(spaces.v, spaces.weights, V); + // A weighted average of projectors is generally not idempotent. + // The derivative of ||A U||^2 is 2 A' A U; here A is symmetric. + Eigen::MatrixXd penalty_u = spaces.u.size() == 1 ? residual_u : + space_residual(spaces.u, spaces.weights, residual_u); + Eigen::MatrixXd penalty_v = spaces.v.size() == 1 ? residual_v : + space_residual(spaces.v, spaces.weights, residual_v); Eigen::MatrixXd grad_U = (2.0 / perc_nonmissing) * (U * V_tilde - adjusted_theta * V) - + lambda1 * 2 * (U - U_trunc * (U_trunc_T * U)) - + lambda2 * 4 * U * (U_tilde - V_tilde); + + lambda1_row * 2 * penalty_u + + lambda2 * 4 * U * (U_tilde - V_tilde); Eigen::MatrixXd grad_V = (2.0 / perc_nonmissing) * (V * U_tilde - adjusted_theta.transpose() * U) - + lambda1 * 2 * (V - V_trunc * (V_trunc_T * V)) - + lambda2 * 4 * V * (V_tilde - U_tilde); + + lambda1_col * 2 * penalty_v + + lambda2 * 4 * V * (V_tilde - U_tilde); double grad_U_norm = grad_U.norm(); double grad_V_norm = grad_V.norm(); @@ -93,11 +126,14 @@ List learner_worker(const Eigen::MatrixXd &Y_source, diff = diff.array().isNaN().select(Eigen::MatrixXd::Zero(diff.rows(), diff.cols()), diff); } obj = diff.squaredNorm() / perc_nonmissing + - lambda1 * (U - U_trunc * (U_trunc_T * U)).squaredNorm() + - lambda1 * (V - V_trunc * (V_trunc_T * V)).squaredNorm() + + lambda1_row * space_residual(spaces.u, spaces.weights, U).squaredNorm() + + lambda1_col * space_residual(spaces.v, spaces.weights, V).squaredNorm() + lambda2 * (U.transpose() * U - V.transpose() * V).squaredNorm(); } obj_values.push_back(obj); + if (!std::isfinite(obj) || !U.allFinite() || !V.allFinite()) { + return FitResult{U_best * V_best.transpose(), obj_values, 3}; + } if (obj < obj_best) { obj_best = obj; @@ -117,79 +153,63 @@ List learner_worker(const Eigen::MatrixXd &Y_source, obj_init = obj; } - return List::create( - Named("learner_estimate") = U_best * V_best.transpose(), - Named("objective_values") = obj_values, - Named("convergence_criterion") = convergence_criterion - ); + return FitResult{U_best * V_best.transpose(), obj_values, convergence_criterion}; } -//-------------------------------------------------------------- -// Exported learner function. // [[Rcpp::export]] -List learner_cpp(const Eigen::MatrixXd &Y_source, const Eigen::MatrixXd &Y_target, - int r, double lambda1, double lambda2, double step_size, int max_iter, double threshold, double max_value) { - List out = learner_worker(Y_source, Y_target, r, lambda1, lambda2, step_size, max_iter, threshold, max_value); - return List::create( - Named("learner_estimate") = out["learner_estimate"], - Named("objective_values") = out["objective_values"], - Named("convergence_criterion") = out["convergence_criterion"], - Named("r") = r - ); +List learner_cpp(const Rcpp::List &Y_source, const Eigen::MatrixXd &Y_target, + const std::vector &source_weights, int r, + double lambda1_row, double lambda1_col, double lambda2, + double step_size, int max_iter, double threshold, double max_value) { + SourceSpaces spaces = prepare_spaces(Y_source, source_weights, r); + FitResult out = learner_worker(spaces, Y_target, lambda1_row, lambda1_col, + lambda2, step_size, max_iter, threshold, max_value); + return List::create(Named("learner_estimate") = out.estimate, + Named("objective_values") = out.objective, + Named("convergence_criterion") = out.criterion, + Named("r") = r); } -//-------------------------------------------------------------- +// All three vectors contain one entry per candidate combination, in R array order. // [[Rcpp::export]] -List cv_learner_cpp(const Eigen::MatrixXd &Y_source, const Eigen::MatrixXd &Y_target, - const std::vector &lambda1_all, const std::vector &lambda2_all, - double step_size, int n_folds, int max_iter, double threshold, - int n_cores, int r, double max_value, - const std::vector> &index_set) { - int p = Y_source.rows(); - int q = Y_source.cols(); - int n_lambda1 = lambda1_all.size(); - int n_lambda2 = lambda2_all.size(); - - Eigen::MatrixXd mse_all = Eigen::MatrixXd::Zero(n_lambda1, n_lambda2); - -#pragma omp parallel for collapse(2) schedule(dynamic) num_threads(n_cores) - for (int i = 0; i < n_lambda1; ++i) { - for (int j = 0; j < n_lambda2; ++j) { - double mse = 0.0; - - for (int fold = 0; fold < n_folds; ++fold) { - Eigen::MatrixXd Y_train = Y_target; - for (int idx : index_set[fold]) { - int row = idx % p; - int col = idx / p; - Y_train(row, col) = std::numeric_limits::quiet_NaN(); - } - List temp = learner_worker(Y_source, Y_train, r, - lambda1_all[i], lambda2_all[j], - step_size, max_iter, threshold, max_value); - Eigen::MatrixXd learner_estimate = temp["learner_estimate"]; - double fold_mse = 0.0; - for (int idx : index_set[fold]) { - int row = idx % p; - int col = idx / p; - double diff = learner_estimate(row, col) - Y_target(row, col); - fold_mse += diff * diff; - } - mse += fold_mse; +std::vector cv_learner_cpp(const Rcpp::List &Y_source, + const Eigen::MatrixXd &Y_target, + const std::vector &source_weights, + const std::vector &row_grid, + const std::vector &col_grid, + const std::vector &balance_grid, + double step_size, int max_iter, double threshold, + int n_cores, int r, double max_value, + const std::vector> &index_set) { + SourceSpaces spaces = prepare_spaces(Y_source, source_weights, r); + int p = Y_target.rows(); + int n_grid = row_grid.size(); + std::vector scores(n_grid, 0.0); + +#pragma omp parallel for schedule(dynamic) num_threads(n_cores) + for (int g = 0; g < n_grid; ++g) { + double score = 0.0; + for (const auto &fold : index_set) { + Eigen::MatrixXd training = Y_target; + for (int idx : fold) training(idx % p, idx / p) = std::numeric_limits::quiet_NaN(); + FitResult fit = learner_worker(spaces, training, row_grid[g], col_grid[g], + balance_grid[g], step_size, max_iter, threshold, max_value); + if (!fit.estimate.allFinite() || + !std::all_of(fit.objective.begin(), fit.objective.end(), + [](double x) { return std::isfinite(x); })) { + score = std::numeric_limits::infinity(); + break; + } + double fold_score = 0.0; + for (int idx : fold) { + double difference = fit.estimate(idx % p, idx / p) - Y_target(idx % p, idx / p); + fold_score += difference * difference; } - mse_all(i, j) = mse; + score += fold_score; } + scores[g] = score; } - - Eigen::Index minRow, minCol; - mse_all.minCoeff(&minRow, &minCol); - - return List::create( - Named("lambda_1_min") = lambda1_all[minRow], - Named("lambda_2_min") = lambda2_all[minCol], - Named("mse_all") = mse_all, - Named("r") = r - ); + return scores; } // -------------------------------------------------------------- @@ -201,4 +221,3 @@ int omp_max_threads() { return 1; #endif } - diff --git a/tests/testthat/fixtures/README.md b/tests/testthat/fixtures/README.md new file mode 100644 index 0000000..ea3a456 --- /dev/null +++ b/tests/testthat/fixtures/README.md @@ -0,0 +1,54 @@ +# Fixed reference results for the extensions + +`multisource-v030.rds` contains inputs, fitting arguments, and expected outputs +computed by Sean McGrath's base-R **learnerv2 0.3.0** implementation from the +`learner-paper` repository's simulations materials. The tests do not create +expected values by calling the `learner` implementation under test. + +## Coverage + +- Three simulated 9-by-7 source matrices with weights 2, 3, 5 and fixed rank 2. +- Common penalties and unequal U/V penalties, for complete and missing targets. +- Complete fitted matrices and all 15 objective values, rank, and stopping code. +- Separate-penalty CV with 2-by-2-by-2 candidates, three folds, and fixed RNG + settings, for complete and missing targets. All scores and selected values + are checked; each saved CV case has a unique minimum. +- The complete multiple-source D-LEARNER estimate, also checked at generation + time against explicit dense weighted source operators. + +The saved inputs are synthetic. They are generated with seed 405 and then stored +in full, rather than regenerated during tests. CV uses seed 514 with RNG kinds +`Mersenne-Twister`, `Inversion`, and `Rejection`; its test restores the incoming +RNG state. The fixture records the reference version, source-file MD5 hashes, +R version, and RNG kinds so the source of the expected values can be audited. + +`expect_equal()` uses tolerance `1e-8` to allow ordinary floating-point and SVD +library differences. Matrix estimates and objective histories are checked, not +raw U/V factors, whose SVD signs are arbitrary. Rank is fixed to avoid depending +on future changes in automatic rank selection. + +The 15-update examples use `threshold = 0` and a large growth limit to compare a +fixed optimization path. They do not demonstrate convergence or statistical +accuracy. They do not assert that the two implementations have identical stopping +behavior for all settings. The analytic tests in `test-stopping-behavior.R` +separately check the current package's documented stopping rules. + +Normal tests only read this fixture and require neither `learnerv2` nor `foreach`. + +## Deliberate regeneration + +Run the generator manually from the package root, using an extracted, unmodified +copy of learnerv2 0.3.0. The generator requires `foreach`; it verifies the package +name and version and sources the reference R files without loading `learner`. + +```sh +Rscript tests/testthat/fixtures/generate-reference.R \ + /path/to/learnerv2 \ + tests/testthat/fixtures/multisource-v030.rds +``` + +The generator refuses to overwrite an existing baseline unless `--overwrite` is +added. Do not regenerate the fixture merely to make a failing test pass. First +understand whether a change is an intended method/interface change, an optimization +difference, or a bug; review any new baseline independently and update this note. +Neither testthat nor R CMD check runs the generator automatically. diff --git a/tests/testthat/fixtures/generate-reference.R b/tests/testthat/fixtures/generate-reference.R new file mode 100644 index 0000000..fa1b5c0 --- /dev/null +++ b/tests/testthat/fixtures/generate-reference.R @@ -0,0 +1,87 @@ +# Developer-only script. It is never run by testthat or R CMD check. +# Usage: Rscript generate-reference.R /path/to/learnerv2-0.3.0 /path/to/output.rds +# Add --overwrite only after reviewing an intentional change to the baseline. +args <- commandArgs(trailingOnly = TRUE) +if (length(args) < 2L) stop('Supply the extracted reference package directory and output .rds path.') +reference_dir <- normalizePath(args[1], mustWork = TRUE) +output <- args[2] +if (file.exists(output) && !('--overwrite' %in% args)) { + stop('Reference already exists; review the change before using --overwrite.') +} +description <- read.dcf(file.path(reference_dir, 'DESCRIPTION')) +stopifnot(description[1, 'Package'] == 'learnerv2', description[1, 'Version'] == '0.3.0') +# The reference CV implementation uses foreach even for sequential execution. +if (!requireNamespace('foreach', quietly = TRUE)) stop('Install foreach to generate this fixture.') +reference <- new.env(parent = asNamespace('foreach')) +reference_files <- file.path('R', c('learner.R', 'cv_learner.R', 'dlearner.R')) +for (f in reference_files) sys.source(file.path(reference_dir, f), envir = reference) + +# Inputs are saved in the fixture, so tests do not regenerate them from the RNG. +RNGkind('Mersenne-Twister', 'Inversion', 'Rejection') +set.seed(405) +sources <- list(matrix(rnorm(63), 9, 7), matrix(rnorm(63), 9, 7), + matrix(rnorm(63), 9, 7)) +target <- matrix(rnorm(63), 9, 7) +masked <- target +masked[c(3, 8, 19)] <- NA_real_ +targets <- list(complete = target, missing = masked) +control <- list(max_iter = 15L, threshold = 0, max_value = 1e6) +rank <- 2L +weights <- c(2, 3, 5) +step <- 0.01 +penalties <- list(common = list(lambda_1 = 3), + separate = list(lambda_1_row = 3, lambda_1_col = 0.25)) +grids <- list(lambda_1_row_all = c(0.25, 3), lambda_1_col_all = c(0.5, 2), + lambda_2_all = c(0, 1)) +fit_cases <- list() +cv_cases <- list() +for (target_name in names(targets)) { + for (penalty_name in names(penalties)) { + fit_args <- c(list(Y_source = sources, Y_target = targets[[target_name]], + r = rank, source_weights = weights, lambda_2 = 1, + step_size = step, control = control), penalties[[penalty_name]]) + reference_args <- fit_args + reference_args$r <- NULL + reference_args$r_source <- rank + reference_args$r_target <- rank + expected <- do.call(reference$learner, reference_args) + stopifnot(expected$convergence_criterion == 2L, + length(expected$objective_values) == control$max_iter, + all(is.finite(expected$objective_values))) + fit_cases[[paste(target_name, penalty_name, sep = '_')]] <- + list(args = fit_args, expected = expected) + } + cv_args <- c(list(Y_source = sources, Y_target = targets[[target_name]], + r = rank, source_weights = weights, step_size = step, + control = control, n_folds = 3L, n_cores = 1L), grids) + reference_args <- cv_args + reference_args$r <- NULL + reference_args$r_source <- rank + reference_args$r_target <- rank + set.seed(514) + expected <- do.call(reference$cv.learner, reference_args) + stopifnot(all(is.finite(expected$mse_all))) + sorted_scores <- sort(as.vector(expected$mse_all)) + stopifnot(sorted_scores[2] - sorted_scores[1] > 1e-5) + cv_cases[[target_name]] <- list(args = cv_args, seed = 514L, expected = expected) +} +direct_args <- list(Y_source = sources, Y_target = target, r = rank, + source_weights = weights) +direct_expected <- do.call(reference$dlearner, direct_args) +# Independently verify D-LEARNER by forming the dense weighted operators. +bases <- lapply(sources, svd, nu = rank, nv = rank) +w <- weights / sum(weights) +pu <- Reduce(`+`, Map(function(b, wk) wk * tcrossprod(b$u), bases, w)) +pv <- Reduce(`+`, Map(function(b, wk) wk * tcrossprod(b$v), bases, w)) +stopifnot(isTRUE(all.equal(direct_expected$dlearner_estimate, + pu %*% target %*% pv, tolerance = 1e-12))) +fixture <- list( + provenance = list(reference_package = 'learnerv2', reference_version = '0.3.0', + reference_md5 = setNames(as.character(tools::md5sum( + file.path(reference_dir, reference_files))), reference_files), + r_version = as.character(getRversion()), + rng_kind = RNGkind(), tolerance = 1e-8), + fit = fit_cases, cv = cv_cases, + direct = list(args = direct_args, expected = direct_expected)) +saveRDS(fixture, output, version = 2) +cat('Wrote independently generated reference fixture:', output, '\n') diff --git a/tests/testthat/fixtures/multisource-v030.rds b/tests/testthat/fixtures/multisource-v030.rds new file mode 100644 index 0000000000000000000000000000000000000000..7377dc5f0459e0e4305fe54b224ad1446c22ef7a GIT binary patch literal 6238 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 1e-8), 3) + } + expect_equal(d$Theta_source$A, d$Theta_source$B) + target <- svd(d$Theta_target, nu = 3, nv = 3) + source <- svd(d$Theta_source$A, nu = 3, nv = 3) + expect_equal(tcrossprod(target$u), tcrossprod(source$u), tolerance = 1e-10) + expect_equal(tcrossprod(target$v), tcrossprod(source$v), tolerance = 1e-10) +}) + +test_that('saved example has the intended noise scales without shared source noise', { + d <- dat_multisource + noise <- cbind(target = as.vector(d$Y_target - d$Theta_target), + A = as.vector(d$Y_source$A - d$Theta_source$A), + B = as.vector(d$Y_source$B - d$Theta_source$B)) + # Fixed saved data: broad checks catch variance/SD mistakes and reused noise. + ratios <- apply(noise, 2, var) / c(target = 0.10, A = 0.01, B = 0.50) + expect_true(all(ratios > 0.8 & ratios < 1.2)) + correlations <- cor(noise) + expect_true(all(abs(correlations[upper.tri(correlations)]) < 0.05)) +}) diff --git a/tests/testthat/test-reference-regression.R b/tests/testthat/test-reference-regression.R new file mode 100644 index 0000000..bbc28cb --- /dev/null +++ b/tests/testthat/test-reference-regression.R @@ -0,0 +1,51 @@ +# These expected values come from Sean's base-R learnerv2 0.3.0 implementation, +# not from the function under test. See fixtures/README.md for provenance. +reference_fixture <- function() { + readRDS(test_path('fixtures', 'multisource-v030.rds')) +} + +with_reference_rng <- function(seed, kind, code) { + old_kind <- RNGkind() + had_seed <- exists('.Random.seed', envir = .GlobalEnv, inherits = FALSE) + if (had_seed) old_seed <- get('.Random.seed', envir = .GlobalEnv) + on.exit({ + do.call(RNGkind, as.list(old_kind)) + if (had_seed) { + assign('.Random.seed', old_seed, envir = .GlobalEnv) + } else if (exists('.Random.seed', envir = .GlobalEnv, inherits = FALSE)) { + rm('.Random.seed', envir = .GlobalEnv) + } + }) + do.call(RNGkind, as.list(kind)) + set.seed(seed) + force(code) +} + +for (case_name in c('complete_common', 'complete_separate', + 'missing_common', 'missing_separate')) { + test_that(paste('multisource fit matches the saved reference:', case_name), { + fixture <- reference_fixture() + case <- fixture$fit[[case_name]] + actual <- do.call(learner, case$args) + # Includes every estimated entry, every objective value, rank, and stop code. + expect_equal(actual, case$expected, tolerance = fixture$provenance$tolerance) + }) +} + +for (case_name in c('complete', 'missing')) { + test_that(paste('separate-penalty CV matches the saved reference:', case_name), { + fixture <- reference_fixture() + case <- fixture$cv[[case_name]] + actual <- with_reference_rng(case$seed, fixture$provenance$rng_kind, + do.call(cv.learner, case$args)) + # Includes all eight scores and the selected penalties, not only dimensions. + expect_equal(actual, case$expected, tolerance = fixture$provenance$tolerance) + }) +} + +test_that('multisource D-LEARNER matches the saved reference', { + fixture <- reference_fixture() + actual <- do.call(dlearner, fixture$direct$args) + expect_equal(actual, fixture$direct$expected, + tolerance = fixture$provenance$tolerance) +}) diff --git a/tests/testthat/test-separate-penalties.R b/tests/testthat/test-separate-penalties.R new file mode 100644 index 0000000..878bd24 --- /dev/null +++ b/tests/testthat/test-separate-penalties.R @@ -0,0 +1,144 @@ +penalty_example <- function() { + set.seed(421) + list(source = matrix(rnorm(20), 5, 4), + target = matrix(rnorm(20), 5, 4)) +} + +test_that("equal separate penalties preserve common and positional calls", { + dat <- penalty_example() + for (with_missing in c(FALSE, TRUE)) { + target <- dat$target + if (with_missing) target[c(2, 7)] <- NA_real_ + control <- list(max_iter = 12, threshold = 0) + common <- learner(dat$source, target, 1, 3, 1, 0.01, control) + separate <- learner(dat$source, target, r = 1, lambda_2 = 1, + step_size = 0.01, control = control, + lambda_1_row = 3, lambda_1_col = 3) + expect_equal(separate, common, tolerance = 1e-12) + } +}) + +test_that("transposing data swaps the two independent space penalties", { + dat <- penalty_example() + fit <- function(source, target, row, col) { + learner(source, target, r = 1, lambda_1_row = row, + lambda_1_col = col, lambda_2 = 1, step_size = 0.02, + control = list(max_iter = 12, threshold = 0)) + } + original <- fit(dat$source, dat$target, 3, 0.25) + transposed <- fit(t(dat$source), t(dat$target), 0.25, 3) + expect_equal(original$learner_estimate, t(transposed$learner_estimate), + tolerance = 1e-9) + expect_equal(original$objective_values, transposed$objective_values, + tolerance = 1e-9) +}) + +# A finite-difference oracle checks the C++ updates against the objective, +# without copying the analytic gradient formulas used by the implementation. +numeric_penalty_fit <- function(source, target, row, col, balance, + step_size, iterations, weights = NULL) { + sources <- if (is.matrix(source)) list(source) else source + bases <- lapply(sources, svd, nu = 1, nv = 1) + s <- bases[[1]] + if (is.null(weights)) weights <- rep(1, length(bases)) + weights <- weights / sum(weights) + p <- nrow(sources[[1]]) + q <- ncol(sources[[1]]) + pu <- Reduce(`+`, Map(function(b, w) w * tcrossprod(b$u), bases, weights)) + pv <- Reduce(`+`, Map(function(b, w) w * tcrossprod(b$v), bases, weights)) + u <- s$u * sqrt(s$d[1]) + v <- s$v * sqrt(s$d[1]) + theta <- c(u, v) + observed <- !is.na(target) + objective <- function(x) { + U <- matrix(x[seq_len(p)], p, 1) + V <- matrix(x[p + seq_len(q)], q, 1) + residual <- (U %*% t(V) - target)[observed] + sum(residual^2) / mean(observed) + + row * sum(((diag(p) - pu) %*% U)^2) + + col * sum(((diag(q) - pv) %*% V)^2) + + balance * (sum(U^2) - sum(V^2))^2 + } + best <- theta + best_value <- objective(theta) + values <- numeric(iterations) + for (i in seq_len(iterations)) { + gradient <- vapply(seq_along(theta), function(j) { + direction <- numeric(length(theta)) + direction[j] <- 1e-6 + (objective(theta + direction) - objective(theta - direction)) / 2e-6 + }, numeric(1)) + for (indices in list(seq_len(p), p + seq_len(q))) { + theta[indices] <- theta[indices] - step_size * + sqrt(sum(theta[indices]^2)) / + (sqrt(sum(gradient[indices]^2)) + 1e-12) * gradient[indices] + } + values[i] <- objective(theta) + if (values[i] < best_value) { + best <- theta + best_value <- values[i] + } + } + list(estimate = outer(best[seq_len(p)], best[p + seq_len(q)]), + objective = values) +} + +test_that("unequal and zero penalties follow the intended objective", { + dat <- penalty_example() + for (with_missing in c(FALSE, TRUE)) { + target <- dat$target + if (with_missing) target[c(2, 7)] <- NA_real_ + for (penalties in list(c(3, 0.25), c(0.25, 3), c(0, 3), c(3, 0))) { + reference <- numeric_penalty_fit(dat$source, target, penalties[1], + penalties[2], 1, 0.02, 12) + actual <- learner(dat$source, target, r = 1, + lambda_1_row = penalties[1], + lambda_1_col = penalties[2], lambda_2 = 1, + step_size = 0.02, + control = list(max_iter = 12, threshold = 0, + max_value = 1e6)) + expect_equal(actual$objective_values, reference$objective, + tolerance = 1e-6) + expect_equal(actual$learner_estimate, reference$estimate, + tolerance = 1e-6) + } + } +}) + +test_that("invalid or ambiguous space penalties fail clearly", { + dat <- penalty_example() + fit <- function(...) learner(dat$source, dat$target, r = 1, + lambda_2 = 1, step_size = 0.01, ...) + expect_error(fit(), "Provide lambda_1") + expect_error(fit(lambda_1_row = 1), "provided together") + expect_error(fit(lambda_1_col = 1), "provided together") + expect_error(fit(lambda_1 = 1, lambda_1_row = 1, lambda_1_col = 1), + "not both modes") + expect_error(fit(lambda_1 = 1, lambda_1_row = 1), "not both modes") + invalid <- list(numeric(0), c(1, 2), NA_real_, NaN, Inf, -1, "1", TRUE) + for (value in invalid) { + expect_error(fit(lambda_1 = value), "lambda_1 must be") + expect_error(fit(lambda_1_row = value, lambda_1_col = 1), + "lambda_1_row must be") + expect_error(fit(lambda_1_row = 1, lambda_1_col = value), + "lambda_1_col must be") + } +}) + + +test_that("multiple-source updates match finite differences of the weighted objective", { + dat <- penalty_example() + set.seed(25) + sources <- list(dat$source, matrix(rnorm(20), 5, 4), matrix(rnorm(20), 5, 4)) + for (masked in c(FALSE, TRUE)) { + y <- dat$target + if (masked) y[c(2, 7)] <- NA_real_ + reference <- numeric_penalty_fit(sources, y, 3, 0.25, 1, 0.02, 12, + weights = c(0.2, 0.3, 0.5)) + actual <- learner(sources, y, r = 1, lambda_1_row = 3, lambda_1_col = 0.25, + lambda_2 = 1, step_size = 0.02, source_weights = c(2, 3, 5), + control = list(max_iter = 12, threshold = 0, max_value = 1e6)) + expect_equal(actual$objective_values, reference$objective, tolerance = 1e-6) + expect_equal(actual$learner_estimate, reference$estimate, tolerance = 1e-6) + } +}) diff --git a/tests/testthat/test-stopping-behavior.R b/tests/testthat/test-stopping-behavior.R new file mode 100644 index 0000000..7bfd930 --- /dev/null +++ b/tests/testthat/test-stopping-behavior.R @@ -0,0 +1,51 @@ +# Analytic examples distinguish a stopping code from optimization accuracy. +# The source has distinct singular values 4, 2, 1; its rank-one approximation +# and initial target estimate are exactly diag(4, 0, 0) in a 4-by-3 matrix. +stopping_example <- function() { + source <- matrix(0, 4, 3) + source[cbind(1:3, 1:3)] <- c(4, 2, 1) + target <- matrix(0, 4, 3) + target[1, 1] <- 4 + list(source = source, target = target) +} + +test_that('unchanged consecutive objectives meet a positive threshold', { + d <- stopping_example() + fit <- learner(d$source, d$target, r = 1, lambda_1 = 1, lambda_2 = 1, + step_size = 0.01, control = list(max_iter = 5, threshold = 0.001)) + expect_equal(fit$convergence_criterion, 1) + expect_equal(fit$objective_values, c(0, 0), tolerance = 1e-12) + expect_equal(fit$learner_estimate, d$target, tolerance = 1e-12) +}) + +test_that('a zero threshold uses a strict inequality and reaches the budget', { + d <- stopping_example() + fit <- learner(d$source, d$target, r = 1, lambda_1 = 1, lambda_2 = 1, + step_size = 0.01, control = list(max_iter = 5, threshold = 0)) + expect_equal(fit$convergence_criterion, 2) + expect_length(fit$objective_values, 5) + expect_equal(fit$learner_estimate, d$target, tolerance = 1e-12) +}) + +test_that('the returned estimate can retain the initialization after a bad step', { + d <- stopping_example() + # Opposite target and an intentionally huge step make the first update worse. + fit <- learner(d$source, -d$target, r = 1, lambda_1 = 1, lambda_2 = 1, + step_size = 10, control = list(max_iter = 1, threshold = 0)) + initial_objective <- sum((d$target - (-d$target))^2) + expect_equal(fit$convergence_criterion, 2) + expect_length(fit$objective_values, 1) + expect_gt(fit$objective_values[1], initial_objective) + expect_equal(fit$learner_estimate, d$target, tolerance = 1e-12) +}) + +test_that('excessive objective growth returns code three and the best estimate', { + d <- stopping_example() + fit <- learner(d$source, -d$target, r = 1, lambda_1 = 1, lambda_2 = 1, + step_size = 10, + control = list(max_iter = 5, threshold = 0, max_value = 2)) + expect_equal(fit$convergence_criterion, 3) + expect_length(fit$objective_values, 2) + expect_gt(fit$objective_values[2], 2 * fit$objective_values[1]) + expect_equal(fit$learner_estimate, d$target, tolerance = 1e-12) +}) From c2d19a7b173d7e72f676ba6ad803d4c47b1f4116 Mon Sep 17 00:00:00 2001 From: Jodie Li Date: Thu, 15 Oct 2026 23:34:01 -0500 Subject: [PATCH 2/4] Test invalid inputs and non-finite optimization failures --- tests/testthat/test-failure-handling.R | 84 ++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 tests/testthat/test-failure-handling.R diff --git a/tests/testthat/test-failure-handling.R b/tests/testthat/test-failure-handling.R new file mode 100644 index 0000000..e9075a0 --- /dev/null +++ b/tests/testthat/test-failure-handling.R @@ -0,0 +1,84 @@ +# Small, deterministic matrices keep error-path tests independent of fixtures. +failure_example <- function() { + list(source = diag(c(4, 3, 2, 1)), target = diag(c(1, 2, 3, 4))) +} + +test_that('all fitting interfaces reject malformed target matrices', { + d <- failure_example() + infinite <- d$target + infinite[1, 1] <- Inf + calls <- list( + function(y) learner(d$source, y, r = 2, lambda_1 = 1, + lambda_2 = 1, step_size = 0.001), + function(y) cv.learner(d$source, y, r = 2, lambda_1_all = 1, + lambda_2_all = 1, step_size = 0.001), + function(y) dlearner(d$source, y, r = 2)) + for (target in list(as.vector(d$target), matrix('x', 4, 4), + matrix(numeric(), 0, 4), infinite)) { + for (fit in calls) { + expect_error(fit(target), 'Y_target must be a nonempty numeric matrix', + fixed = TRUE) + } + } +}) + +test_that('learner and CV reject invalid optimization settings', { + d <- failure_example() + calls <- list( + function(...) learner(d$source, d$target, r = 2, lambda_1 = 1, + lambda_2 = 1, ...), + function(...) cv.learner(d$source, d$target, r = 2, lambda_1_all = 1, + lambda_2_all = 1, ...)) + for (fit in calls) { + expect_error(fit(step_size = 0.001, control = 3), + 'control must be a list', fixed = TRUE) + for (bad in c(0, -1, Inf, NA_real_)) { + expect_error(fit(step_size = bad), + 'step_size must be a finite positive number', fixed = TRUE) + expect_error(fit(step_size = 0.001, control = list(max_value = bad)), + 'control$max_value must be a finite positive number', fixed = TRUE) + } + } +}) + +test_that('a non-finite update stops immediately and retains the finite initialization', { + d <- failure_example() + # A finite but extreme step overflows the objective on the first update. + fit <- learner(d$source, d$target, r = 2, lambda_1 = 1, lambda_2 = 1, + step_size = 1e200, control = list(max_iter = 3)) + expect_equal(fit$convergence_criterion, 3) + expect_length(fit$objective_values, 1) + expect_false(is.finite(fit$objective_values[1])) + expect_true(all(is.finite(fit$learner_estimate))) + expect_equal(fit$learner_estimate, diag(c(4, 3, 0, 0)), tolerance = 1e-12) +}) + +test_that('CV reports when no candidate has a finite validation score', { + d <- failure_example() + set.seed(42) + expect_error( + cv.learner(d$source, d$target, r = 2, lambda_1_all = c(0, 1), + lambda_2_all = 1, step_size = 1e200, n_folds = 2, + control = list(max_iter = 3)), + 'No candidate produced finite validation errors', fixed = TRUE) +}) + +test_that('CV excludes a failed candidate and preserves the valid candidate score', { + d <- failure_example() + cv <- function(grid) { + set.seed(42) + cv.learner(d$source, d$target, r = 2, lambda_1_all = grid, + lambda_2_all = 1, step_size = 0.001, n_folds = 2, + control = list(max_iter = 3)) + } + reference <- cv(0) + # An extreme finite penalty causes non-finite updates in just that candidate. + expect_warning(result <- cv(c(1e308, 0)), + 'Some candidates produced non-finite validation errors and were excluded', + fixed = TRUE) + expect_equal(result$mse_all[1, 1], Inf) + expect_true(is.finite(result$mse_all[2, 1])) + expect_equal(result$mse_all[2, 1], reference$mse_all[1, 1], tolerance = 1e-12) + expect_equal(result$lambda_1_min, reference$lambda_1_min) + expect_equal(result$lambda_2_min, reference$lambda_2_min) +}) From 82a77f2f915b89a27c60d1eed3da86c57bc0f0b9 Mon Sep 17 00:00:00 2001 From: Jodie Li Date: Fri, 16 Oct 2026 00:00:11 -0500 Subject: [PATCH 3/4] Clarify missing-target validation messages --- R/input-validation.R | 7 +++++-- tests/testthat/test-failure-handling.R | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/R/input-validation.R b/R/input-validation.R index d15f347..d942698 100644 --- a/R/input-validation.R +++ b/R/input-validation.R @@ -6,8 +6,11 @@ prepare_sources <- function(Y_source, Y_target, source_weights = NULL, any(dim(Y_target) == 0L) || any(is.infinite(Y_target))) { stop('Y_target must be a nonempty numeric matrix without infinite values.') } - if ((!allow_missing_target && anyNA(Y_target)) || all(is.na(Y_target))) { - stop('Y_target must contain observed values; dlearner does not allow NA values.') + if (all(is.na(Y_target))) { + stop('Y_target must contain observed values.') + } + if (!allow_missing_target && anyNA(Y_target)) { + stop('dlearner requires a complete Y_target without missing values.') } sources <- if (is.matrix(Y_source)) list(Y_source) else Y_source if (!is.list(sources) || length(sources) == 0L) { diff --git a/tests/testthat/test-failure-handling.R b/tests/testthat/test-failure-handling.R index e9075a0..d7cb877 100644 --- a/tests/testthat/test-failure-handling.R +++ b/tests/testthat/test-failure-handling.R @@ -22,6 +22,21 @@ test_that('all fitting interfaces reject malformed target matrices', { } }) +test_that('missing-target messages distinguish an empty target from D-LEARNER requirements', { + d <- failure_example() + missing <- d$target + missing[] <- NA_real_ + expect_error(learner(d$source, missing, r = 2, lambda_1 = 1, + lambda_2 = 1, step_size = 0.001), + '^Y_target must contain observed values\\.$') + expect_error(cv.learner(d$source, missing, r = 2, lambda_1_all = 1, + lambda_2_all = 1, step_size = 0.001), + '^Y_target must contain observed values\\.$') + d$target[1, 1] <- NA_real_ + expect_error(dlearner(d$source, d$target, r = 2), + 'dlearner requires a complete Y_target without missing values', fixed = TRUE) +}) + test_that('learner and CV reject invalid optimization settings', { d <- failure_example() calls <- list( From a72af46622304c7324a41a359931685c12307e67 Mon Sep 17 00:00:00 2001 From: Jodie Li Date: Fri, 16 Oct 2026 13:02:48 -0500 Subject: [PATCH 4/4] Add noisier source comparison to the core examples --- inst/examples/multiple-sources.R | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/inst/examples/multiple-sources.R b/inst/examples/multiple-sources.R index 61ea953..fd72a87 100644 --- a/inst/examples/multiple-sources.R +++ b/inst/examples/multiple-sources.R @@ -58,3 +58,31 @@ comparison <- do.call(rbind, lapply(names(source_choices), function(label) { print(comparison, row.names = FALSE) # Lower Frobenius error is better. These are single-dataset results, not CV MSE. # The weights 0.7/0.3 are illustrative; combining sources need not beat source A. + +# A second setting: both sources have appreciable noise. +# Keep the built-in data unchanged; variances are target 0.10, A 0.25, B 0.50. +# Reuse the true signals, with new independent noise for every population. +set.seed(20261016) +add_noise <- function(signal, variance) { + signal + matrix(rnorm(length(signal), sd = sqrt(variance)), + nrow(signal), ncol(signal)) +} +target_noisy <- add_noise(learner::dat_multisource$Theta_target, variance = 0.10) +sources_noisy <- list( + A = add_noise(learner::dat_multisource$Theta_source$A, variance = 0.25), + B = add_noise(learner::dat_multisource$Theta_source$B, variance = 0.50) +) +estimates_noisy <- list( + Target_only = learner::dlearner(target_noisy, target_noisy, r = 3)$dlearner_estimate, + A_only = learner::dlearner(sources_noisy$A, target_noisy, r = 3)$dlearner_estimate, + B_only = learner::dlearner(sources_noisy$B, target_noisy, r = 3)$dlearner_estimate, + Weighted_A_B = learner::dlearner(sources_noisy, target_noisy, r = 3, + source_weights = c(0.7, 0.3))$dlearner_estimate +) +errors_noisy <- vapply(estimates_noisy, function(estimate) { + norm(estimate - learner::dat_multisource$Theta_target, "F") +}, numeric(1)) +print(round(errors_noisy, 3)) +# Here the weighted combination improves on either source alone, but the +# target-only SVD has the smallest error. Fixed weights and one noise draw +# illustrate a possible outcome, not a general performance guarantee.