% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/liblex.R
\name{liblex}
\alias{liblex}
\alias{predict.liblex}
\alias{plot.liblex}
\title{Build a precomputed library of localised experts using memory-based learning}
\usage{
liblex(Xr, Yr, neighbors,
       diss_method = diss_pca(ncomp = ncomp_by_opc()),
       fit_method = fit_wapls(min_ncomp = 3, max_ncomp = 15),
       anchor_indices = NULL, gh = TRUE, group = NULL,
       control = liblex_control(), verbose = TRUE, ...)

\method{predict}{liblex}(object, newdata, diss_method = NULL,
        weighting = c("gaussian", "tricube", "triweight", "triangular",
                      "quartic", "parabolic", "cauchy", "none"),
        adaptive_bandwidth = TRUE, reliability_weighting = TRUE,
        range_prediction_limits = FALSE, residual_cutoff = NULL,
        enforce_indices = NULL, probs = c(0.05, 0.25, 0.5, 0.75, 0.95),
        verbose = TRUE, allow_parallel = TRUE, blas_threads = 1L, ...)
        
\method{plot}{liblex}(x, ...)
}
\arguments{
\item{Xr}{A numeric matrix of predictor variables with dimensions \verb{n × p}
(observations in rows, variables in columns). Column names are required.}

\item{Yr}{A numeric vector or single-column matrix of length \code{n} containing
the response variable values corresponding to \code{Xr}. Missing values are
allowed (see Details).}

\item{neighbors}{A neighbor selection object specifying how to select
neighbors. Use \code{\link{neighbors_k}()} for fixed k-nearest neighbors
or \code{\link{neighbors_diss}()} for dissimilarity threshold-based
selection.}

\item{diss_method}{For \code{liblex}: either a \verb{diss_*} object specifying
the dissimilarity method, or a precomputed numeric dissimilarity matrix.
If a \verb{diss_*} object (e.g., \code{\link[=diss_pca]{diss_pca()}}, \code{\link[=diss_pls]{diss_pls()}}, \code{\link[=diss_correlation]{diss_correlation()}},
\code{\link[=diss_euclidean]{diss_euclidean()}}), dissimilarities are computed internally. Additional
parameters (centering, scaling, number of components) are controlled
within the object.
If a matrix is provided:
\itemize{
\item When \code{anchor_indices = NULL}: must be square (\verb{n × n}) with zeros
on the diagonal.
\item When \code{anchor_indices} is specified (length \code{m}): must have
dimensions \verb{n × m}, with \code{diss_method[anchor_indices, ]} having zeros
on the diagonal.
}
Default is \code{diss_pca(ncomp = ncomp_by_opc())}.

For \code{predict.liblex}: a dissimilarity method object created by
\code{diss_*()} constructors. If not provided, uses the method stored in
\code{object}. Required if \code{object} was built with a precomputed
dissimilarity matrix.}

\item{fit_method}{A \code{local_fit} object specifying the local regression
method. Currently supported: \code{\link[=fit_pls]{fit_pls()}} and \code{\link[=fit_wapls]{fit_wapls()}}.
\code{\link[=fit_gpr]{fit_gpr()}} is not yet supported. Default is
\code{fit_wapls(min_ncomp = 3, max_ncomp = 15)}.}

\item{anchor_indices}{An optional integer vector specifying row indices
of \code{Xr} around which to build local models. If \code{NULL} (default), models
are built for all observations. See Details.}

\item{gh}{Logical indicating whether to compute the GH distance
(Mahalanobis distance in PLS score space) for each anchor observation.
Default is \code{TRUE}.}

\item{group}{An optional factor assigning group labels to observations in
\code{Xr}. Used for leave-group-out validation to avoid pseudo-replication.
When an observation is selected for validation, all observations from
the same group are excluded from model fitting. Default is \code{NULL}
(each observation is its own group).}

\item{control}{A list of control parameters created by \code{\link[=liblex_control]{liblex_control()}}.
Default is \code{liblex_control()}.}

\item{verbose}{Logical indicating whether to display progress messages.
Default is \code{TRUE}.}

\item{...}{Additional arguments (currently unused).}

\item{object}{A fitted object of class \code{"liblex"}, created by
\code{\link{liblex}} (for \code{predict}).}

\item{newdata}{A numeric matrix or data frame containing new predictor
values. Must include all predictors used in \code{object}.}

\item{weighting}{Character string specifying the kernel weighting function
applied to neighbours when combining predictions. Options are:
\code{"gaussian"} (default), \code{"tricube"}, \code{"triweight"},
\code{"triangular"}, \code{"quartic"}, \code{"parabolic"}, \code{"cauchy"},
or \code{"none"} (equal weights). See Details for kernel definitions.}

\item{adaptive_bandwidth}{Logical indicating whether to use adaptive
bandwidth for kernel weighting. When \code{TRUE} (default), the bandwidth
is set to the maximum dissimilarity within the neighborhood of each observation,
so weights adapt to local density. When \code{FALSE}, a fixed global
bandwidth is used across all predictions, which may result in uniform
weights in sparse regions or overly concentrated weights in dense regions.}

\item{reliability_weighting}{Logical indicating whether to weight expert
predictions by their estimated reliability. When \code{TRUE} (default),
the contribution of each experrt is additionally weighted by the inverse of its
cross-validation residual variance, giving more influence to models that
performed well during fitting. When \code{FALSE}, only dissimilarity-based
kernel weights are used.}

\item{probs}{A numeric vector of probabilities in \eqn{[0, 1]} for computing
weighted quantiles of expert predictions. Default is
\code{c(0.05, 0.25, 0.5, 0.75, 0.95)}.}

\item{range_prediction_limits}{Logical. If \code{TRUE}, predictions falling
outside the 5th–95th percentile range of neighbour response values are
clipped to those limits. Default is \code{FALSE}.}

\item{residual_cutoff}{Numeric threshold for excluding models. Models with
absolute residuals exceeding this value are penalized during neighbour
selection. Default is \code{NULL} (no exclusion).}

\item{enforce_indices}{Optional integer vector specifying model indices that
must always be included in each prediction neighborhood. These models are
assigned the minimum dissimilarity of the neighborhood to ensure selection.
Default is \code{NULL} (no enforced models).}

\item{allow_parallel}{Logical indicating whether parallel computation is
permitted if a backend is registered. Default is \code{TRUE}.}

\item{blas_threads}{Integer specifying the number of BLAS threads to use.
Default is \code{1L}. Requires the \pkg{RhpcBLASctl} package for thread
control.}

\item{x}{An object of class \code{"liblex"} as returned by \code{\link[=liblex]{liblex()}}.}
}
\value{
\strong{For \code{liblex}:} A list of class \code{"liblex"} (when
\code{control$mode = "build"}) or \code{"liblex_validation"} (when
\code{control$mode = "validate"}) containing:
\itemize{
\item \code{dissimilarity}: List containing the dissimilarity method
and matrix.
\item \code{fit_method}: Fit constructor from \code{fit_method}.
\item \code{gh}: If \code{gh = TRUE}, a list with GH distances and the PLS
projection.
\item \code{results}: Data frame of validation statistics for each
parameter combination (if validation was performed).
\item \code{best}: The optimal parameter combination based on
\code{control$metric}.
\item \code{optimal_params}: List with optimal \code{k} and \code{ncomp} values.
\item \code{residuals}: Residuals from predictions using optimal
parameters.
\item \code{coefficients}: (Build mode only) List of regression
coefficients: \code{B0} (intercepts), \code{B} (slopes).
\item \code{vips}: (Build mode only) Variable importance in projection
scores.
\item \code{selectivity_ratios}: (Build mode only) Selectivity ratios
for each predictor.
\item \code{scaling}: (Build mode only) Centering and scaling vectors
for prediction.
\item \code{neighborhood_stats}: Statistics (response quantiles) for
each neighborhood size.
\item \code{anchor_indices}: The anchor indices used.
\item \code{neighbors}: The object passed to \code{neighbors}.
}

\strong{For \code{predict.liblex}:} A list with the following components:
\itemize{
\item \code{predictions}: A data frame containing:
\itemize{
\item \code{pred}: Weighted mean predictions.
\item \code{pred_sd}: Weighted standard deviation of expert
predictions.
\item \code{q*}: Weighted quantiles at probabilities specified by
\code{probs}.
\item \code{gh}: Global Mahalanobis distance (if computed during
fitting).
\item \code{min_yr}: Minimum response value (5th percentile) across
neighbours.
\item \code{max_yr}: Maximum response value (95th percentile) across
neighbours.
\item \code{below_min}: Logical indicating prediction below
\code{min_yr}.
\item \code{above_max}: Logical indicating prediction above
\code{max_yr}.
}
\item \code{neighbors}: A list with:
\itemize{
\item \code{indices}: Matrix of neighbour indices (models) for each
observation.
\item \code{dissimilarities}: Matrix of corresponding dissimilarity
scores.
}
\item \code{expert_predictions}: A list with:
\itemize{
\item \code{weights}: Matrix of kernel weights applied to each expert.
\item \code{predictions}: Matrix of raw predictions from each expert.
\item \code{weighted}: Matrix of weighted predictions from each expert.
}
}
}
\description{
Constructs a library of local predictive models based on memory-based
learning (MBL). For each anchor observation, a local regression model is
fitted using its nearest neighbors from the reference set. This
implementation is based on the methods proposed in
Ramirez-Lopez et al. (2026b).
}
\details{
By default, local models are constructed for all \code{n} observations in the
reference set. Alternatively, specify a subset of \code{m} observations
(\code{m < n}) via \code{anchor_indices} to reduce computation.

Each local model uses neighbors selected from the full reference set, but
models are only built for anchor observations. This is useful for large
datasets where building models for all observations is computationally
prohibitive.

When dissimilarity methods depend on \code{Yr} (e.g., PLS-based distances), the
response values of anchor observations are excluded during dissimilarity
computation for efficiency. However, anchor response values are always
used when fitting local models.

The number of anchors must not exceed 90\% of \code{nrow(Xr)}; to build models
for all observations, use \code{anchor_indices = NULL}.
\subsection{Relationship between anchors and neighborhood size}{

The \code{neighbors} argument controls the neighborhood size (\code{k}) used both
for fitting local models and for retrieving experts during prediction.
When \code{anchor_indices} is specified, the number of available experts equals
the number of anchors. If \code{max(k)} exceeds the number of anchors and
tuning selects a large optimal \code{k}, prediction will retrieve fewer experts
than specified. For reliable predictions, ensure the number of anchors is
at least as large as the maximum \code{k} value being evaluated.
}

\subsection{Missing values in Yr}{

Missing values in \code{Yr} are permitted. Observations with missing response
values can still serve as neighbors but are excluded from model fitting
as target observations.
}

\subsection{GH distance}{

The GH distance is computed independently from \code{diss_method} using a PLS
projection with optimized component selection. This provides a measure of
how far each observation lies from the center of the reference set in the
PLS score space.
}

\subsection{Validation and tuning}{

When \code{control$mode = "validate"} or \code{control$tune = TRUE}, nearest-neighbor
cross-validation is performed. For each anchor observation, its nearest
neighbor is excluded, a model is fitted on remaining neighbors, and the
excluded neighbor's response is predicted. This provides validation
statistics for parameter selection.
}

\subsection{Prediction}{

For each observation in \code{newdata}, the \code{predict} method:
\enumerate{
\item Computes dissimilarities to anchor observations (or their
neighbourhood centres) stored in \code{object}.
\item Selects the \code{k} nearest neighbours based on the optimal
\code{k} determined during model fitting.
\item Applies kernel weighting based on dissimilarity.
\item Combines expert predictions using weighted averaging.
}
}

\subsection{Kernel weighting functions}{

The weighting functions follow Cleveland and Devlin (1988). Let \eqn{d} be
the normalised dissimilarity (scaled to \eqn{[0, 1]} within the neighbourhood
when \code{adaptive_bandwidth = TRUE}). The available kernels are:
\itemize{
\item \code{"gaussian"}: \eqn{w = \exp(-d^2)}
\item \code{"tricube"}: \eqn{w = (1 - d^3)^3}
\item \code{"triweight"}: \eqn{w = (1 - d^2)^3}
\item \code{"triangular"}: \eqn{w = 1 - d}
\item \code{"quartic"}: \eqn{w = (1 - d^2)^2}
\item \code{"parabolic"}: \eqn{w = 1 - d^2}
\item \code{"cauchy"}: \eqn{w = 1 / (1 + d^2)}
\item \code{"none"}: \eqn{w = 1} (equal weights)
}
}
}
\examples{
\dontrun{
library(prospectr)
data(NIRsoil)

# Preprocess spectra
NIRsoil$spc_pr <- savitzkyGolay(
  detrend(NIRsoil$spc, wav = as.numeric(colnames(NIRsoil$spc))),
  m = 1, p = 1, w = 7
)

# Missing values in the response are allowed
train_x <- NIRsoil$spc_pr[NIRsoil$train == 1, ]
train_y <- NIRsoil$Ciso[NIRsoil$train == 1]
test_x  <- NIRsoil$spc_pr[NIRsoil$train == 0, ]
test_y  <- NIRsoil$Ciso[NIRsoil$train == 0]

# Build library
model_library <- liblex(
  Xr = train_x,
  Yr = train_y,
  neighbors = neighbors_k(c(30, 40)),
  diss_method = diss_correlation(ws = 27, scale = TRUE),
  fit_method = fit_wapls(
    min_ncomp = 4,
    max_ncomp = 17,
    scale = FALSE,
    method = "mpls"
  ),
  control = liblex_control(tune = TRUE)
)

# Visualise neighborhood centroids and samples to predict
matplot(
  as.numeric(colnames(model_library$scaling$local_x_center)),
  t(test_x),
  col = rgb(1, 0, 0, 0.3),
  lty = 1,
  type = "l",
  xlab = "Wavelength (nm)",
  ylab = "First derivative detrended absorbance"
)
matlines(
  as.numeric(colnames(model_library$scaling$local_x_center)),
  t(model_library$scaling$local_x_center),
  col = rgb(0, 0, 1, 0.3),
  lty = 1,
  type = "l"
)
grid(lty = 1)
legend(
  "topright",
  legend = c("Samples to predict", "Neighborhood centroids"),
  col = c(rgb(1, 0, 0, 0.8), rgb(0, 0, 1, 0.8)),
  lty = 1,
  lwd = 2,
  bty = "n"
)

# Predict new observations
y_hat_liblex <- predict(model_library, test_x)

# Predicted versus observed values
lims <- range(y_hat_liblex$predictions$pred, test_y, na.rm = TRUE)
plot(
  y_hat_liblex$predictions$pred,
  test_y,
  pch = 16,
  col = rgb(0, 0, 0, 0.5),
  xlab = "Predicted",
  ylab = "Observed",
  xlim = lims,
  ylim = lims
)
abline(a = 0, b = 1, col = "red")
grid(lty = 1)

## run liblex in parallel (requires a parallel backend, e.g., doParallel)
library(doParallel)
n_cores <- min(2, parallel::detectCores() - 1)
clust <- makeCluster(n_cores)
registerDoParallel(clust)

model_library2 <- liblex(
  Xr = train_x,
  Yr = train_y,
  neighbors = neighbors_k(c(30, 40)),
  fit_method = fit_wapls(min_ncomp = 4, max_ncomp = 17, method = "simpls")
)

y_hat_liblex2 <- predict(model_library2, test_x)
registerDoSEQ()
try(stopCluster(clust))
}
}
\references{
Cleveland, W. S., & Devlin, S. J. (1988). Locally weighted regression:
An approach to regression analysis by local fitting.
\emph{Journal of the American Statistical Association}, 83(403), 596–610.

Naes, T., Isaksson, T., & Kowalski, B. (1990). Locally weighted regression
and scatter correction for near-infrared reflectance data.
\emph{Analytical Chemistry}, 62(7), 664–673.

Ramirez-Lopez, L., Behrens, T., Schmidt, K., Stevens, A., Dematte, J.A.M.,
Scholten, T. (2013). The spectrum-based learner: A new local approach for
modeling soil vis-NIR spectra of complex datasets. Geoderma, 195-196,
268-279.

Ramirez-Lopez, L., Metz, M., Lesnoff, M., Orellano, C.,
Perez-Fernandez, E., Plans, M., Breure, T., Behrens, T.,
Viscarra Rossel, R., & Peng, Y. (2026b). Rethinking local spectral
modelling: From per-query refitting to model libraries.
\emph{Analytica Chimica Acta}, under review.

Rajalahti, T., Arneberg, R., Berven, F.S., Myhr, K.M., Ulvik, R.J.,
Kvalheim, O.M. (2009). Biomarker discovery in mass spectral profiles by
means of selectivity ratio plot. Chemometrics and Intelligent Laboratory
Systems, 95(1), 35-48.
}
\seealso{
\code{\link[=liblex_control]{liblex_control()}} for control parameters, \code{\link[=neighbors_k]{neighbors_k()}} for neighborhood
specification, \code{\link[=diss_pca]{diss_pca()}}, \code{\link[=diss_pls]{diss_pls()}}, \code{\link[=diss_correlation]{diss_correlation()}} for
dissimilarity methods, \code{\link[=fit_pls]{fit_pls()}}, \code{\link[=fit_wapls]{fit_wapls()}} for fitting methods.
}
\author{
\href{https://orcid.org/0000-0002-5369-5120}{Leonardo Ramirez-Lopez}
}
