Commit cd824120 authored by davidkep's avatar davidkep

expose different strategies for how to use starting points.

parent 3fcabb4b
......@@ -27,7 +27,8 @@ Depends:
Imports:
Rcpp,
parallel,
methods
methods,
lifecycle
LinkingTo:
nsoptim,
Rcpp,
......
......@@ -17,6 +17,7 @@ export(pense_mm_options)
export(rho_function)
export(tau_size)
importFrom(Rcpp,evalCpp)
importFrom(lifecycle,deprecate_soft)
importFrom(methods,as)
importFrom(stats,mad)
useDynLib(pense, .registration = TRUE)
This diff is collapsed.
......@@ -4,12 +4,13 @@
\alias{pense}
\title{Compute the PENSE Regularization Path}
\usage{
pense(x, y, alpha, lambdas, cold_lambdas, penalty_loadings,
additional_initial_estimates, include_intercept = TRUE, bdp = 0.25,
cc, eps = 1e-06, algorithm_opts, nr_tracks = 10, explore_it = 10,
sparse = TRUE, mscale_opts = mscale_algorithm_options(),
enpy_opts = enpy_options(), zero_based = TRUE,
share_initials = FALSE)
pense(x, y, alpha, lambdas, enpy_lambdas, penalty_loadings,
strategies = "ZEsEiOsOi", other_starts, include_intercept = TRUE,
bdp = 0.25, cc, eps = 1e-06, algorithm_opts,
explore_solutions = 10, explore_tol = 0.1, max_solutions = 10,
comparison_tol = sqrt(eps), sparse = TRUE,
mscale_opts = mscale_algorithm_options(), enpy_opts = enpy_options(),
...)
}
\arguments{
\item{x}{\code{n} by \code{p} matrix of numeric predictors.}
......@@ -21,18 +22,21 @@ penalization.}
\item{lambdas}{a vector of positive values for the lambda parameter.}
\item{cold_lambdas}{a vector of lambda values at which \emph{cold} initial
\item{enpy_lambdas}{a vector of lambda values at which \emph{cold} initial
estimates are computed (see \link{enpy} for details).}
\item{penalty_loadings}{a vector of positive penalty loadings
(a.k.a. weights) for different penalization of each
coefficient.}
\item{additional_initial_estimates}{a list of other initial estimates to try.
Each list item must contain the value
for the regularization parameter \code{lambda}
as well as the \code{intercept} and \code{beta}
coefficients.}
\item{strategies}{a string specifying the strategies used to get starting points for the optimization.
See \emph{Strategies} for a list of supported strategies. The strategies can be in any order.}
\item{other_starts}{a list of other initial estimates to try only at the corresponding lambda values.
Each list item must contain the \code{intercept} and \code{beta} coefficients.
If the strategy \emph{Other Starting Points (individual)} is requested, any starting point which has
the value for the regularization parameter \code{lambda} included (alongside \code{intercept} and \code{beta}),
will be used only at the specified \code{lambda} value.}
\item{include_intercept}{include an intercept in the model.}
......@@ -45,10 +49,20 @@ given breakdown point under the Normal model.}
\item{algorithm_opts}{options for the PENSE algorithm. See \link{pense_algorithm_options} for details.}
\item{nr_tracks}{number of optima to track in the "cold" and "others" regularization path.}
\item{explore_solutions}{number of optima to track for the \emph{EN-PY (individual)} and
\emph{Other Starting Points (individual)} regularization path strategies. Also controls how many
starting points for \emph{EN-PY (individual)} and \emph{Other Starting Points (shared)} are
computed to the full accuracy.}
\item{explore_tol}{relative numerical tolerance when exploring possible solutions.}
\item{explore_it}{number of iterations to explore potential candidate
solutions.}
\item{max_solutions}{only retain up to \code{max_solutions} unique optima per lambda value.}
\item{comparison_tol}{numeric tolerance to determine if two optima are equal The comparison is first done
on the absolute difference in the value of the objective function at the optima.
If this is less than \code{comparison_tol}, two optima are deemed equal if the squared difference
of the intercepts is less than \code{comparison_tol} and the squared L_2 norm of the difference
vector is less than \code{comparison_tol}.}
\item{sparse}{use sparse coefficient vector.}
......@@ -57,10 +71,39 @@ solutions.}
\item{enpy_opts}{options for the ENPY initial estimates, created with the
\link{enpy_options} function. See \link{enpy_initial_estimates} for details.}
\item{zero_based}{also compute the PENSE regularization path starting from the 0 vector.}
\item{...}{currently not used.}
\item{share_initials}{use all initial estimates for every lambda value.}
\item{cold_lambdas}{a deprecated alias for \code{enpy_lambdas}.}
}
\description{
Compute the PENSE Regularization Path
}
\section{Strategies}{
The function supports several different strategies to compute, and use given, starting points for the optimization.
They are all applied to the entire regularization path, i.e., for every value in the descending lambda grid.
\itemize{
\item \emph{Zero-based} (\code{'Z'}): Use the 0-vector to start the optimization at the largest lambda value.
For subsequent lambda values, use the optimum at the previous lambda value as starting point.
\item \emph{EN-PY (shared)} (\code{'Es'}): compute the EN-PY estimates at each of the lambda values in \code{enpy_lambdas}. Each of
these estimates is used as starting point at every lambda value in \code{lambdas}.
\item \emph{EN-PY (individual)} (\code{'Ei'}): compute the EN-PY estimates at each of the lambda values in \code{enpy_lambdas}.
These estimates are used as starting points at the corresponding value in \code{lambdas}. Only the best \code{nr_tracks}
optima are retained. At the following lambda value, the previous optima are used as starting points.
At the next smaller lambda which is both in \code{enpy_lambdas} and in \code{lambdas}, an additional \code{nr_tracks} optima are
computed by starting from the EN-PY estimates, however, only the best \code{nr_tracks} estimates (from using the
previous optima and the EN-PY estimates as starting points) are retained.
\item \emph{Other Starting Points (shared)} (\code{'Os'}): use the starting points given in \code{other_starts} at every lambda value.
Only used if \code{other_starts} is a list of estimates.
\item \emph{Other Starting Points (individual)} (\code{'Oi'}): use the starting points in \code{other_starts} at the corresponding
lambda values. Only used if \code{other_starts} is a list of estimates and if at least one of these estimates includes
the value of the regularization parameter \code{lambda}. The same "warm-start" strategy as for \emph{EN-PY (individual)}
is used.
}
For example, the strategies string \code{strategies = 'ZEiOs'} uses the strategies \emph{Zero-based}, \emph{EN-PY (individual)},
and \emph{Other Starting Points (shared)} to compute the optima along the regularization path. The strategies
don't have to be in any specific order; for example \code{strategies = 'EiZOs'} and \code{strategies = 'OsEiZ'} would also
select the same strategies as in the previous example.
}
CXX_STD = CXX11
PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
PKG_CXXFLAGS= -fstrict-aliasing -Wstrict-aliasing
PKG_CXXFLAGS= -fstrict-aliasing -Wstrict-aliasing -ftemplate-backtrace-limit=0
PKG_OPTFLAGS= -g -Os -flto=thin
# -DNSOPTIM_METRICS_DISABLED -DNSOPTIM_DETAILED_METRICS
......
......@@ -38,8 +38,6 @@ using pense::r_interface::MakePredictorResponseData;
using pense::r_interface::MakeVectorView;
using pense::r_interface::MakePenalties;
using pense::r_interface::MakeOptimizer;
using pense::WrapOptima;
using pense::RegularizationPath;
namespace {
//! Create a loss with the observation weights taken from the list of optional arguments.
......@@ -71,15 +69,18 @@ SEXP LsEnRegressionImpl(SEXP r_x, SEXP r_y, SEXP r_penalties, SEXP r_include_int
auto penalties = MakePenalties<Optimizer>(r_penalties, optional_args);
auto optimizer = MakeOptimizer<Optimizer>(en_options);
auto reg_path = RegularizationPath(loss, penalties, optimizer);
Rcpp::List output_reg_path;
Metrics all_metrics("reg_path");
for (auto&& optimum : reg_path) {
if (optimum.metrics) {
all_metrics.AddSubMetrics(std::move(*optimum.metrics));
optimum.metrics.reset();
pense::RegPath0<Optimizer> reg_path(optimizer, loss, penalties);
while (!reg_path.End()) {
auto next_optimum = reg_path.Next();
if (next_optimum.metrics) {
all_metrics.AddSubMetrics(std::move(*next_optimum.metrics));
next_optimum.metrics.reset();
}
output_reg_path.push_back(pense::WrapOptimum(next_optimum));
}
Rcpp::List en_results = Rcpp::List::create(Rcpp::Named("estimates") = WrapOptima(reg_path),
Rcpp::List en_results = Rcpp::List::create(Rcpp::Named("estimates") = output_reg_path,
Rcpp::Named("metrics") = wrap(all_metrics));
return wrap(en_results);
......
......@@ -34,7 +34,7 @@ const R_CallMethodDef kExportedCallMethods[] = {
{"C_mloc", (DL_FUNC) &MLocation, 3},
{"C_mlocscale", (DL_FUNC) &MLocationScale, 3},
{"C_lsen_regression", (DL_FUNC) &LsEnRegression, 5},
{"C_pense_regression", (DL_FUNC) &PenseEnRegression, 8},
{"C_pense_regression", (DL_FUNC) &PenseEnRegression, 7},
{"C_pense_max_lambda", (DL_FUNC) &PenseMaxLambda, 4},
// {"C_pensem_en_regression_dal", (DL_FUNC) &PensemEnRegressionDAL, 7},
// {"C_pensem_ridge_regression", (DL_FUNC) &PensemRidgeRegression, 6},
......
This diff is collapsed.
......@@ -18,15 +18,17 @@ namespace r_interface {
//! @param x numeric predictor matrix with `n` rows and `p` columns.
//! @param y numeric response vector with `n` elements.
//! @param penalties a list of EN penalties with decreasing values of the lambda hyper-parameter.
//! @param initial_ests a list of other initial estimates to try.
//! @param enpy_inds a vector of 1-based indices for the `penalties` list, at which initial ENPY estimates should be
//! computed.
//! @param pense_opts a list of options for the PENSE algorithm.
//! @param enpy_opts a list of options for the ENPY algorithm.
//! @param optional_args a list containing the following named items:
//! `shared_starts` ... optional list of coefficients to start at every penalty.
//! `individual_starts` ... optional list the same length as `penalties` with a list coefficients
//! to start at the corresponding penalty.
//! `pen_loadings` ... optional vector of length `p` with non-negative penalty loadings.
SEXP PenseEnRegression(SEXP x, SEXP y, SEXP penalties, SEXP initial_ests, SEXP enpy_inds,
SEXP pense_opts, SEXP enpy_opts, SEXP optional_args) noexcept;
SEXP PenseEnRegression(SEXP x, SEXP y, SEXP penalties, SEXP enpy_inds, SEXP pense_opts, SEXP enpy_opts,
SEXP optional_args) noexcept;
//! Get the smallest lambda such that the (Adaptive) PENSE estimate gives the empty model.
//!
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment