| Title: | Percentage-Error Support Vector Regression |
| Version: | 0.1.0 |
| Description: | Implements four support vector regression (SVR) models derived from a unified mathematical framework for percentage-error loss functions: epsilon-SVR minimizing the mean absolute percentage error (MAPE), its symmetric kernel extension, least-squares SVR (LS-SVR) minimizing the root mean square percentage error (RMSPE), and its symmetric counterpart. All models require strictly positive targets. The epsilon-SVR models are solved via a built-in sequential minimal optimization (SMO) algorithm (with 'osqp' available as an optional alternative backend) and the LS-SVR models via a linear system (base R). See Benavides-Herrera et al. (2026) <doi:10.3390/math14101679> for the mathematical derivations. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| RoxygenNote: | 7.3.3 |
| Depends: | R (≥ 4.1) |
| Imports: | dials, Matrix, parsnip, Rcpp (≥ 1.0.10), rlang, scales, stats, tune, utils, workflowsets |
| LinkingTo: | Rcpp |
| Suggests: | dplyr, ggplot2, knitr, osqp, recipes, rmarkdown, rsample, testthat (≥ 3.0.0), tibble, workflows, yardstick |
| Config/testthat/edition: | 3 |
| VignetteBuilder: | knitr |
| URL: | https://pbenavidesh.github.io/psvr/ |
| Config/Needs/website: | rmarkdown, tsibbledata, tsibble, lubridate, ggplot2, kableExtra, kernlab, scales, tidyr, tidyverse, tidymodels, modeldata, future, ranger, xgboost, ggrepel, sessioninfo, modeltime, timetk, randomForest, readxl, xfun, e1071, quantreg, lars, patchwork, here |
| NeedsCompilation: | yes |
| Packaged: | 2026-09-14 19:56:47 UTC; behep |
| Author: | Pablo Benavides-Herrera
|
| Maintainer: | Pablo Benavides-Herrera <pbenavides@iteso.mx> |
| Repository: | CRAN |
| Date/Publication: | 2026-09-24 14:40:08 UTC |
psvr: Percentage-Error Support Vector Regression
Description
Implements four support vector regression (SVR) models derived from a unified mathematical framework for percentage-error loss functions: epsilon-SVR minimizing the mean absolute percentage error (MAPE), its symmetric kernel extension, least-squares SVR (LS-SVR) minimizing the root mean square percentage error (RMSPE), and its symmetric counterpart. All models require strictly positive targets. The epsilon-SVR models are solved via a built-in sequential minimal optimization (SMO) algorithm (with 'osqp' available as an optional alternative backend) and the LS-SVR models via a linear system (base R). See Benavides-Herrera et al. (2026) doi:10.3390/math14101679 for the mathematical derivations.
Author(s)
Maintainer: Pablo Benavides-Herrera pbenavides@iteso.mx (ORCID)
See Also
Useful links:
Adaptive spectral regularization (internal, F3)
Description
Estimates the extreme eigenvalues of the symmetrized kernel matrix
Omega_s by power iteration and, if the smallest is numerically negative,
adds a mu * I shift large enough to make the SMO Hessian provably PSD
(>= delta_stab * I). Returns the matrix untouched when it is already PSD,
which is the case for every kernel make_kernel() supplies. Implements
Theorem 2 of arXiv:2605.01446 v3, with the eigenvalue estimator corrected;
see below.
Usage
.adaptive_spectral_shift(Omega_s, T_pi = 5L, delta_stab = 1e-08)
Arguments
Omega_s |
Symmetrized kernel matrix
|
T_pi |
Power-iteration steps per pass (default |
delta_stab |
Numerical PSD floor (default |
Value
A list with components:
Omega_useMatrix to pass to the SMO/QP solver.
muNumeric scalar; the shift applied (
0if no shift).lambda_min_hatNumeric scalar; Rayleigh-quotient estimate of
lambda_min(Omega_s)from Pass 2.lambda_max_hatNumeric scalar; Pass 1's Rayleigh quotient. For PSD or
lambda_max-dominant matrices (the typical case for Mercer kernels in this package), this equalslambda_max(Omega_s). Forlambda_min-dominant matrices (|lambda_min| > lambda_max— a pathological case not reachable withmake_kernel()-supplied kernels), it equalslambda_min(Omega_s). The branch decision in either case is made correctly via the Pass 2 estimate oflambda_min_hat.branch_takenCharacter
"no_shift"or"shifted".n_power_iterationsInteger vector of length 2; iterations executed in Pass 1 and Pass 2.
Algorithm and paper deviation
Algorithm 2 line 6 of the paper, as literally written
(v <- -Omega_s * v / ||Omega_s * v||), estimates -lambda_max(Omega_s)
rather than lambda_min(Omega_s): power iteration on -Omega_s
converges to the eigenvector of largest |eigenvalue|, which is
v_max(Omega_s) whenever |lambda_max| > |lambda_min| (the typical
case for Mercer-PSD or near-PSD matrices). This implementation uses the
standard two-pass shifted power iteration: Pass 1 estimates
lambda_max via power iteration on Omega_s; Pass 2 estimates
lambda_min via power iteration on rho * I - Omega_s (whose
dominant eigenvector is v_min(Omega_s)). Both passes are O(N^2); the
total cost is 2 * T_pi matvecs.
The Pass 2 shift uses the spectral radius rho = |Pass 1 Rayleigh|,
not Pass 1's signed Rayleigh. This handles the lambda_min-dominant
pathological case (|lambda_min| > lambda_max), where plain power
iteration on Omega_s in Pass 1 converges to v_min and gives a
negative Rayleigh; using abs(Pass 1 Rayleigh) ensures the shifted
operator rho * I - Omega_s is PSD, so Pass 2 reliably finds
v_min(Omega_s) regardless of which side of the spectrum dominated
Pass 1.
Determinism
Both passes start from the uniform unit vector rep(1, N) / sqrt(N)
(not random) so the routine is bit-reproducible.
Fit epsilon-SVR with MAPE loss (Model 1) — internal
Description
Internal fitter for the MAPE epsilon-SVR family. Use psvr_mape() instead.
Returns the psvr_mape shape, which is what psvr_mape() and the parsnip
engine fit wrappers both return.
Usage
.fit_mape(
X,
y,
kernel,
C,
eps,
solver = c("smo", "osqp"),
tol = 0.001,
max_iter = 100000L,
alpha_init = NULL,
alpha_star_init = NULL,
warm_start_check = TRUE,
precomputed_Omega = NULL,
block_k4_enabled = TRUE,
alpha_couple = 0.5,
engine = c("rcpp", "r")
)
Arguments
X, y, kernel, C, eps, solver, tol |
See |
alpha_init, alpha_star_init |
Optional length-N numeric vectors of
starting values for the two sets of SMO dual variables, typically the
converged duals of a previous fit on overlapping data. They are projected
back onto the constraint set before the solve (the warm-start procedure of
Theorem 5 / Algorithm 1 in arXiv:2605.01446 v3). |
warm_start_check |
Logical; if |
Value
A list of class "psvr_mape" (legacy shape).
Fit symmetric epsilon-SVR with MAPE loss (Model 2) — internal
Description
Internal fitter for the symmetric MAPE epsilon-SVR family. Use psvr_mape()
with sym_type = "even" / "odd" instead. Returns the psvr_mape_sym
shape, which is what psvr_mape() and the parsnip engine fit wrappers both
return with sym_type = "even" / "odd". The kernel must satisfy
Assumption 3 of the paper; see make_kernel().
Usage
.fit_mape_sym(
X,
y,
kernel,
C,
eps,
a = 1,
solver = c("smo", "osqp"),
tol = 0.001,
max_iter = 100000L,
alpha_init = NULL,
alpha_star_init = NULL,
warm_start_check = TRUE,
precomputed_Omega_s = NULL,
block_k4_enabled = TRUE,
alpha_couple = 0.5,
engine = c("rcpp", "r")
)
Arguments
X, y, kernel, C, eps, solver, tol |
See |
a |
Symmetry type: |
alpha_init, alpha_star_init |
Optional length-N numeric vectors of
starting values for the two sets of SMO dual variables, typically the
converged duals of a previous fit on overlapping data. They are projected
back onto the constraint set before the solve (the warm-start procedure of
Theorem 5 / Algorithm 1 in arXiv:2605.01446 v3). |
warm_start_check |
Logical; if |
Value
A list of class "psvr_mape_sym" (legacy shape).
Fit LS-SVR with RMSPE loss (Model 3) — internal
Description
Internal fitter for the RMSPE LS-SVR family. Use psvr_rmspe() instead.
Returns the psvr_rmspe shape, which is what psvr_rmspe() and the parsnip
engine fit wrappers both return.
Usage
.fit_rmspe(X, y, kernel, gamma, precondition = "auto")
Arguments
X, y, kernel, gamma, precondition |
See |
Value
A list of class "psvr_rmspe".
Fit symmetric LS-SVR with RMSPE loss (Model 4) — internal
Description
Internal fitter for the symmetric RMSPE LS-SVR family. Use psvr_rmspe()
with sym_type = "even" / "odd" instead. Returns the psvr_rmspe_sym
shape, which is what psvr_rmspe() and the parsnip engine fit wrappers both
return with sym_type = "even" / "odd". The kernel must
satisfy Assumption 3 of the paper (kernel symmetry); see make_kernel().
Usage
.fit_rmspe_sym(X, y, kernel, gamma, a = 1, precondition = "auto")
Arguments
X, y, kernel, gamma, precondition |
See |
a |
Symmetry type: |
Value
A list of class "psvr_rmspe_sym".
Pure-R nested-loop kernel matrix (fallback path)
Description
Original kernel_matrix() body, retained as a fallback for kernel
closures that do not carry a kernel_info attribute (i.e., not built
via make_kernel()). Also used by tests to verify Rcpp-vs-R parity.
Usage
.legacy_kernel_matrix(K, X1, X2)
Arguments
K |
A kernel function from |
X1 |
Numeric matrix with one observation per row (n1 × p). |
X2 |
Numeric matrix with one observation per row (n2 × p).
Defaults to |
Value
Numeric matrix of size n1 × n2.
Build a kernel-matrix accessor (internal)
Description
Wraps a fully-materialised kernel matrix in a list of accessor closures. The SMO solver and other iterative consumers read kernel values through this interface so that future phases can replace the underlying representation (e.g., the F6 LRU cache backed by Rcpp) without touching the consumers.
Usage
.make_kernel_accessor(Omega)
Arguments
Omega |
Kernel matrix ( |
Details
This F2 implementation is a thin wrapper over the materialised matrix:
every closure delegates directly to base-R indexing or BLAS. The
diagonal is computed once at construction (diag() is called a single
time) and reused on every get_diag() call.
Symmetry assumption. The wrapped matrix is assumed symmetric. Both
\Omega (a kernel matrix for symmetric K) and \Omega_s =
\tfrac{1}{2}(\Omega + a\,\Omega^*) (used by the symmetric models when
K satisfies Assumption 3) are symmetric throughout this package, so
callers may use get_column(p)[k] in place of a row read
Omega[p, k]. The SMO solver relies on this in its WSS3 step.
Value
A list with components:
get_column(p)Returns column
pofOmega(length-Nnumeric vector).get_diag()Returns
diag(Omega)(length-Nnumeric vector). Cached at construction.get_entry(p, q)Returns the scalar
Omega[p, q].get_matvec(v)Returns the matrix-vector product
as.numeric(Omega %*% v)(length-N). Used for one-shot gradient refreshes; preserves BLAS efficiency.get_omega()Returns the underlying materialised
Omegamatrix. Added in F7-C-full (engine = "rcpp" handoff) so the Rcpp solver can take a rawdouble*view viaREAL(Omega)without re-materialising. Other consumers should prefer the targeted accessors above.nInteger, equal to
nrow(Omega).
Dispatcher: SMO solver with engine choice (R reference vs Rcpp core).
Description
Forwards to the F7-C-full Rcpp core (engine = "rcpp", default) or
the R reference implementation (engine = "r"). The R path is the
canonical algorithm and remains the bit-identical reference for the
Rcpp port; it will be deprecated in v0.0.4.0 and removed in v0.1.0
once the Rcpp path has passed the snapshot and engine-equivalence
tests for at least two release cycles.
Usage
.smo_solve(
K_acc,
y,
C,
eps,
tol = 0.001,
max_iter = 100000L,
n_check = NULL,
n_freeze = 5L,
alpha_init = NULL,
alpha_star_init = NULL,
warm_start_check = TRUE,
block_k4_enabled = TRUE,
alpha_couple = 0.5,
trace = FALSE,
engine = c("rcpp", "r")
)
Details
Projection of any supplied warm-start duals back onto the constraint set
runs in R via .warm_start_init() BEFORE the core call, regardless of
engine, so both paths see already-feasible alpha/alpha* on entry. That
projection is Algorithm 1 of arXiv:2605.01446 v3.
SMO solver — R reference implementation (engine = "r").
Description
Canonical R-level algorithm. Bit-identical reference for the Rcpp
core in src/core_smo_solve.cpp. Will be deprecated in v0.0.4.0 and
removed in v0.1.0. Do NOT call directly; go through .smo_solve().
Usage
.smo_solve_r(
K_acc,
y,
C,
eps,
tol = 0.001,
max_iter = 100000L,
n_check = NULL,
n_freeze = 5L,
alpha_init = NULL,
alpha_star_init = NULL,
warm_start_check = TRUE,
block_k4_enabled = TRUE,
alpha_couple = 0.5,
trace = FALSE
)
Extract coefficients from a psvr_mape model
Description
Extract coefficients from a psvr_mape model
Usage
## S3 method for class 'psvr_mape'
coef(object, ...)
Arguments
object |
An object of class |
... |
Ignored. |
Value
A named list with five components:
alpha,alpha_starThe length-
Npre-pruning dual variables\alpha_kand\alpha^*_k.betaThe pruned dual differences
\beta_k = \alpha_k - \alpha^*_kover the support-vector indices (lengthn_sv); this is whatpredict()uses.bBias term.
support_dataSupport vector input matrix.
The LS-SVR classes return three components rather than five, since
they have no alpha_star and no pruned beta; the absent components are
not materialised as NULL. So names(coef(fit)) depends on the model
family. That is deliberate: each class is family-specific, and inventing
empty slots to make the two agree would add structure with nothing to
inherit it from.
Renamed in 0.0.2.9011
alpha previously held the pruned \beta and support_data was
named X_sv, which made coef(fit)$alpha mean the length-n_sv
\beta here but the length-N dual \alpha on a fit
from the superseded psvr(): one generic returning two different vectors under
one name, silently, depending on entry point. The
\beta-under-alpha meaning is the one 0.0.2.9004 moved away
from on the object itself; this aligns coef() with it.
Extract coefficients from a psvr_mape_sym model
Description
Extract coefficients from a psvr_mape_sym model
Usage
## S3 method for class 'psvr_mape_sym'
coef(object, ...)
Arguments
object |
An object of class |
... |
Ignored. |
Value
A named list with five components, identical in meaning to
coef.psvr_mape():
alpha,alpha_starThe length-
Npre-pruning dual variables\alpha_kand\alpha^*_k.betaThe pruned dual differences
\beta_k = \alpha_k - \alpha^*_kover the support-vector indices (lengthn_sv); this is whatpredict()uses.bBias term.
support_dataSupport vector input matrix.
Renamed in 0.0.2.9011
See coef.psvr_mape() — the same rename, for the same reason, applied to
both MAPE classes together.
Extract coefficients from a psvr_rmspe model
Description
Extract coefficients from a psvr_rmspe model
Usage
## S3 method for class 'psvr_rmspe'
coef(object, ...)
Arguments
object |
An object of class |
... |
Ignored. |
Value
A named list with components:
alphaDual variables / Lagrange multipliers (length N).
bBias term.
support_dataTraining input matrix (all N observations).
Three components, against five for the MAPE classes (coef.psvr_mape()):
LS-SVR has no alpha_star and no pruned beta, and they are not
materialised as NULL. So names(coef(fit)) depends on the model family,
which is a decision rather than an oversight – each class is
family-specific, and inventing empty slots to make the two agree would add
structure with nothing to inherit it from. $alpha_star and $beta yield
NULL on both, so every accessor still agrees.
Renamed in 0.0.2.9011
support_data was named X_sv. LS-SVR performs no pruning — every training
point contributes to f(x) — so there are no support vectors to name: it was
an epsilon-SVR name on an LS-SVR value. The value is unchanged.
Extract coefficients from a psvr_rmspe_sym model
Description
Extract coefficients from a psvr_rmspe_sym model
Usage
## S3 method for class 'psvr_rmspe_sym'
coef(object, ...)
Arguments
object |
An object of class |
... |
Ignored. |
Value
A named list with components:
alphaDual variables / Lagrange multipliers (length N).
bBias term.
support_dataTraining input matrix (all N observations).
Three components, not the five the MAPE classes return: LS-SVR has no
alpha_star and no pruned beta, and they are not materialised as
NULL. See coef.psvr_rmspe().
Renamed in 0.0.2.9011
See coef.psvr_rmspe() — the same rename, for the same reason, applied to
both LS-SVR classes together.
Cost parameter with extended range for psvr models
Description
A dials parameter for the regularisation parameter in psvr models.
The default range [-2, 10] on the log2 scale (corresponding to
approximately 0.25 to 1024) is wider than dials::cost() to
accommodate the larger regularisation values typically needed by
LS-SVR models.
Usage
cost_psvr(range = c(-2, 10), trans = scales::log2_trans())
Arguments
range |
Numeric vector of length 2 on the log2 scale.
Default |
trans |
A |
Details
For LS-SVR (m3, m4) models the static range is still frequently too
narrow, because \Gamma enters the LS-SVR system through the
y_k^2/\Gamma diagonal and so scales with var(y) * N
rather than sitting at a fixed magnitude. Prefer cost_psvr_ls_data(),
whose range is computed from the training outcome.
Value
A quant_param dials object.
See Also
cost_psvr_ls_data() for a data-driven LS-SVR variant.
Examples
cost_psvr()
Data-driven cost range for LS-SVR psvr models
Description
Returns a quant_param whose search range scales with
var(y) * N, the standard heuristic for the LS-SVR regularisation
parameter \Gamma (Suykens et al. 2002, Least Squares
Support Vector Machines, §3.1.3). On the log2 scale, the lower bound
is -2 (i.e. \Gamma \ge 0.25) and the upper bound is
log2(var(y) * N) + width_log2.
Usage
cost_psvr_ls_data(y, n = length(y), width_log2 = 4)
Arguments
y |
Numeric vector of strictly positive training targets. |
n |
Sample size. Default |
width_log2 |
Scalar giving the half-width (in log2 units)
added above |
Details
The default width_log2 = 4 places the upper bound about 16 times above
var(y) * n, which is headroom for a Bayesian or grid search to work in
without pinning against the boundary. Because the bound tracks
var(y) * n, it moves with the outcome: the static cost_psvr() range
[-2, 10] (i.e. \Gamma \le 1024) is fixed, so it
falls short whenever var(y) * n exceeds a few hundred — which is the
usual case, not the exception.
Use this function for m3 (LS-SVR) and m4 (symmetric LS-SVR)
workflows. Stick to cost_psvr() for m1/m2
(\epsilon-SVR), where
cost maps to C and typical optima lie in [10, 100].
Value
A quant_param dials object.
See Also
cost_psvr(), psvr_option_add_cost_ls()
Examples
cost_psvr_ls_data(c(10, 20, 30, 40, 50))
Compute a kernel matrix between two sets of points
Description
Entry [i, j] equals K(X1[i, ], X2[j, ]). Used internally by all four
model fitting and prediction functions.
Usage
kernel_matrix(K, X1, X2 = X1)
Arguments
K |
A kernel function from |
X1 |
Numeric matrix with one observation per row (n1 × p). |
X2 |
Numeric matrix with one observation per row (n2 × p).
Defaults to |
Details
If K was produced by make_kernel(), dispatch reads the
kernel_info attribute and calls the Rcpp implementation for the
three built-in types ("rbf", "linear", "polynomial"). For
user-defined closures (no kernel_info attribute) the dispatch falls
through to .legacy_kernel_matrix(), the original pure-R nested
loop. Predictions are bit-identical to the R-only path on
Windows/Rtools45; see src/kernel_*.cpp for the operation-order
rationale.
Value
Numeric matrix of size n1 × n2.
Create a kernel function
Description
Returns a closure K(xi, xj) suitable for use with all four psvr model
fitting functions. The returned function accepts numeric vectors of any sign,
which is required by the symmetric models (Models 2 and 4) that evaluate
K(xk, -xl).
Usage
make_kernel(
type = c("rbf", "linear", "polynomial"),
sigma = 1,
degree = 3L,
coef0 = 1
)
Arguments
type |
Kernel type: |
sigma |
Bandwidth for the RBF kernel, |
degree |
Integer degree for the polynomial kernel, |
coef0 |
Constant term for the polynomial kernel (default |
Details
The three supported kernels are:
-
RBF:
K(xi, xj) = exp(-‖xi - xj‖² / (2 * sigma²)) -
Linear:
K(xi, xj) = xi · xj -
Polynomial:
K(xi, xj) = (xi · xj + coef0)^degree
RBF and even-degree polynomial kernels satisfy Assumption 3 of the paper
(kernel symmetry), making them compatible with the symmetric models.
The linear kernel and odd-degree polynomial kernels do not satisfy
Assumption 3 and should not be used with the symmetric models, i.e. with
psvr_mape() / psvr_rmspe() or a parsnip spec whose sym_type is
"even" or "odd".
Value
A function K(xi, xj) where xi and xj are numeric vectors of
the same length, returning a scalar kernel evaluation.
Examples
K <- make_kernel("rbf", sigma = 0.5)
K(c(1, 2), c(3, 4))
K_lin <- make_kernel("linear")
K_lin(c(1, 0), c(0, 1))
K_poly <- make_kernel("polynomial", degree = 2, coef0 = 1)
K_poly(c(1, 2), c(3, 4))
Insensitivity margin in percentage units
Description
A dials parameter for the epsilon tube half-width in psvr MAPE models.
Unlike dials::svm_margin() which uses absolute units, this parameter
is expressed as a percentage of each target value. The default range
[1, 20] means the insensitivity tube spans 1% to 20% of each target.
Usage
margin_percentage(range = c(1, 20), trans = NULL)
Arguments
range |
Numeric vector of length 2. Default |
trans |
A |
Value
A quant_param dials object.
Examples
margin_percentage()
margin_percentage(range = c(0.5, 10))
Predict from a fitted epsilon-SVR with MAPE model
Description
Method dispatched on the "psvr_mape" class, which both psvr_mape() and
the parsnip engine fit wrappers return.
Usage
## S3 method for class 'psvr_mape'
predict(object, newdata, ...)
Arguments
object |
An object of class |
newdata |
Numeric matrix of new inputs, one observation per row
( |
... |
Ignored. |
Value
Numeric vector of length M with predicted values.
Predict from a fitted symmetric epsilon-SVR with MAPE model
Description
Method dispatched on the "psvr_mape_sym" class, which both psvr_mape()
and the parsnip engine fit wrappers return. Uses the symmetric representer
theorem
f(x) = \tfrac{1}{2}\sum_k \beta_k K_s(x_k, x) + b
with K_s(x_k, x) = K(x_k, x) + a K(x_k, -x).
Usage
## S3 method for class 'psvr_mape_sym'
predict(object, newdata, ...)
Arguments
object |
An object of class |
newdata |
Numeric matrix of new inputs, one observation per row
( |
... |
Ignored. |
Value
Numeric vector of length M with predicted values.
Predict from a fitted LS-SVR with RMSPE model
Description
Method dispatched on the "psvr_rmspe" class, which both psvr_rmspe() and
the parsnip engine fit wrappers return.
Usage
## S3 method for class 'psvr_rmspe'
predict(object, newdata, ...)
Arguments
object |
An object of class |
newdata |
Numeric matrix of new inputs, one observation per row
( |
... |
Ignored. |
Value
Numeric vector of length M with predicted values.
Predict from a fitted symmetric LS-SVR with RMSPE model
Description
Method dispatched on the "psvr_rmspe_sym" class, which both psvr_rmspe()
and the parsnip engine fit wrappers return. Uses the symmetric representer
f(x) = \sum_k \alpha_k \cdot
\tfrac{1}{2}\left(K(x_k, x) + a K(x_k, -x)\right) + b
Usage
## S3 method for class 'psvr_rmspe_sym'
predict(object, newdata, ...)
Arguments
object |
An object of class |
newdata |
Numeric matrix of new inputs, one observation per row
( |
... |
Ignored. |
Value
Numeric vector of length M with predicted values.
Print method for psvr_mape objects
Description
Print method for psvr_mape objects
Usage
## S3 method for class 'psvr_mape'
print(x, ...)
Arguments
x |
An object of class |
... |
Ignored. |
Value
x, invisibly.
Print method for psvr_mape_sym objects
Description
Print method for psvr_mape_sym objects
Usage
## S3 method for class 'psvr_mape_sym'
print(x, ...)
Arguments
x |
An object of class |
... |
Ignored. |
Value
x, invisibly.
Print method for psvr_rmspe objects
Description
Print method for psvr_rmspe objects
Usage
## S3 method for class 'psvr_rmspe'
print(x, ...)
Arguments
x |
An object of class |
... |
Ignored. |
Value
x, invisibly.
Print method for psvr_rmspe_sym objects
Description
Print method for psvr_rmspe_sym objects
Usage
## S3 method for class 'psvr_rmspe_sym'
print(x, ...)
Arguments
x |
An object of class |
... |
Ignored. |
Value
x, invisibly.
Fit wrappers for parsnip engine dispatch
Description
Bridge functions called by parsnip when fitting psvr model specs.
Exported only because parsnip's resolver requires it; not intended
for direct use. Call psvr_mape() or psvr_rmspe() instead for direct
fitting.
Usage
psvr_mape_rbf_fit(
x,
y,
C,
eps,
rbf_sigma = 1,
sym_type = "none",
tol = 0.001,
max_iter = 100000L
)
psvr_mape_poly_fit(
x,
y,
C,
eps,
degree = 3L,
scale_factor = 1,
sym_type = "none",
tol = 0.001,
max_iter = 100000L
)
psvr_mape_linear_fit(
x,
y,
C,
eps,
sym_type = "none",
tol = 0.001,
max_iter = 100000L
)
psvr_rmspe_rbf_fit(
x,
y,
gamma,
rbf_sigma = 1,
sym_type = "none",
precondition = "auto"
)
psvr_rmspe_poly_fit(
x,
y,
gamma,
degree = 3L,
scale_factor = 1,
sym_type = "none",
precondition = "auto"
)
psvr_rmspe_linear_fit(x, y, gamma, sym_type = "none", precondition = "auto")
Arguments
x |
Numeric predictor matrix (parsnip matrix interface). |
y |
Numeric outcome vector (strictly positive). |
C |
Regularization parameter for MAPE models. |
eps |
Epsilon tube half-width for MAPE models. |
rbf_sigma |
RBF bandwidth |
sym_type |
Symmetry type. |
tol |
Solver convergence tolerance for the SMO loop. Default |
max_iter |
Maximum SMO iterations. Default |
degree |
Polynomial degree |
scale_factor |
Polynomial constant term
( |
gamma |
Regularization parameter for RMSPE models. |
precondition |
Optional symmetric rescaling preconditioner for the
RMSPE LS-SVR fitters. See |
Value
A fitted model object of the S3 class matching the wrapper's
model family, returned unmodified from the internal fitter. These are the
same classes psvr_mape() and psvr_rmspe() return, so a parsnip fit
unwrapped with parsnip::extract_fit_engine() and a directly fitted
object are interchangeable.
Which class is returned depends on sym_type, since each wrapper
dispatches to the symmetric or non-symmetric fitter.
The MAPE wrappers (psvr_mape_rbf_fit(), psvr_mape_poly_fit(),
psvr_mape_linear_fit()) with sym_type = "none" return an object of
class "psvr_mape": a list with beta (support-vector dual differences),
alpha and alpha_star (length-N pre-pruning duals, retained for warm
starts), b, X_sv, y_sv, y_train, fitted_values, kernel, C,
eps, n_train, p_train, iterations, converged, and block_k4.
With sym_type = "even" or "odd" they return class "psvr_mape_sym":
the same components plus a (the symmetry type) and spectral (the
estimated extreme eigenvalues of the symmetrized kernel matrix, and the
diagonal shift applied to it if it was not numerically positive
semi-definite).
The RMSPE wrappers (psvr_rmspe_rbf_fit(), psvr_rmspe_poly_fit(),
psvr_rmspe_linear_fit()) with sym_type = "none" return class
"psvr_rmspe": a list with alpha, b, X_train, y_train,
fitted_values, kernel, gamma, n_train, p_train, and
precondition_applied. With sym_type = "even" or "odd" they return
class "psvr_rmspe_sym": the same components plus a.
Extract training fitted values from a psvr model
Description
Returns the length-N in-sample predictions f(x_k) recorded
when the model was fitted. No kernel matrix is rebuilt: the values are
recovered from state the solver already holds. For the MAPE models that is
a matvec against the retained \Omega; for the LS-SVR models it
is the KKT stationarity identity
f(x_k) = y_k - (10^{-6} + y_k^2/\Gamma)\,\alpha_k
which costs O(N) and holds in both preconditioner branches.
The training inputs X are not retained for this purpose.
Usage
## S3 method for class 'psvr_mape'
fitted(object, ...)
## S3 method for class 'psvr_mape_sym'
fitted(object, ...)
## S3 method for class 'psvr_rmspe'
fitted(object, ...)
## S3 method for class 'psvr_rmspe_sym'
fitted(object, ...)
Arguments
object |
A fitted object of class |
... |
Ignored. |
Details
The result equals predict(object, X_train) to machine precision. It is
not bit-identical: the two use different summation orders (a BLAS matvec
versus the column-wise reduction in predict()), and for the LS-SVR
models the identity above is exact only up to the residual of the linear
solve. Observed agreement is within 3e-12 relative across the four
models.
Value
Numeric vector of length N (the number of training
observations), in training-row order.
Not reachable through parsnip
parsnip registers neither residuals.model_fit nor fitted.model_fit, so
calling either generic on a model_fit dispatches to the stats default and
returns NULL silently - no error, no warning. Reach the psvr object
first with parsnip::extract_fit_engine(), then call fitted() or
residuals() on that. psvr deliberately does not register S3 methods on
parsnip's class. Note also that parsnip::augment() recomputes predictions
on whatever new_data it is given and reports response residuals only.
See Also
residuals.psvr_mape() and the other residuals methods
Examples
set.seed(1)
X <- matrix(runif(40, 0.5, 3), 20, 2)
y <- 2 + X[, 1]^2
fit <- psvr_rmspe(X, y, kernel = make_kernel("rbf"), gamma = 100)
head(fitted(fit))
# Through parsnip both generics return NULL on the model_fit wrapper;
# extract the engine object first.
df <- data.frame(x1 = X[, 1], x2 = X[, 2], y = y)
spec <- psvr_rmspe_rbf(cost = 10, rbf_sigma = 0.8)
pfit <- parsnip::fit(spec, y ~ x1 + x2, data = df)
fitted(pfit) # NULL
head(fitted(parsnip::extract_fit_engine(pfit))) # the fitted values
Extract training residuals from a psvr model
Description
Three residual types are available. They are different quantities with different denominators, not interchangeable scalings of one another:
Usage
## S3 method for class 'psvr_mape'
residuals(object, type = c("response", "percentage", "multiplicative"), ...)
## S3 method for class 'psvr_mape_sym'
residuals(object, type = c("response", "percentage", "multiplicative"), ...)
## S3 method for class 'psvr_rmspe'
residuals(object, type = c("response", "percentage", "multiplicative"), ...)
## S3 method for class 'psvr_rmspe_sym'
residuals(object, type = c("response", "percentage", "multiplicative"), ...)
Arguments
object |
A fitted object of class |
type |
One of |
... |
Ignored. |
Details
"response"y - \hat{y}. The default, following the R convention forstats::residuals(). Units of the response."percentage"(y - \hat{y}) / y. Divides by the observed target. This is the per-observation contribution to the MAPE loss the epsilon-SVR models are fitted under, so it is the residual that corresponds to the estimated objective.mean(abs(.)) * 100is the training MAPE."multiplicative"(y - \hat{y}) / \hat{y}. Divides by the fitted value. This is the\hat{\eta}of the multiplicative-noise modelY = f(x)(1 + \eta), under which\eta = (Y - f(x))/f(x). Use it to inspect the assumed noise structure, e.g. checking whether\hat{\eta}is homoscedastic and centred at zero.
The denominators differ and the choice matters: "percentage" divides by
the observed target because that is what the MAPE loss does,
"multiplicative" divides by the fitted value because that is what the
noise model does. They agree only when y = \hat{y}, and
diverge as the fit degrades. Choose by the question being asked: the loss
actually minimised ("percentage"), or the noise model assumed
("multiplicative").
Value
Numeric vector of length N (the number of training
observations), in training-row order.
Near-zero fitted values
"multiplicative" divides by \hat{y}, which an SVR does not
constrain to be positive even though the targets are. Where
\hat{y} is at or below sqrt(.Machine$double.eps) * mean(abs(y)) - including zero and negative fitted values - the ratio is
inflated, infinite, or sign-flipped.
This function does not drop those observations: it always returns
exactly N values in training-row order, so the result stays aligned
with y_train, fitted(), and the training rows. The raw value
(possibly Inf or NaN) is returned and a single warning reports how
many observations are affected.
For pooled diagnostics (a mean multiplicative error, a variance, a histogram) the affected observations must be excluded, or one near-zero fitted value dominates the summary. This follows the standard treatment of percentage errors near zero (Makridakis): screen the fitted values against a threshold and drop the observations below it before pooling, rather than altering the per-observation values. Exclude at the point of aggregation, e.g.:
e <- residuals(fit, type = "multiplicative") mean(e[is.finite(e)])
Not reachable through parsnip
parsnip registers neither residuals.model_fit nor fitted.model_fit, so
calling either generic on a model_fit dispatches to the stats default and
returns NULL silently - no error, no warning. Reach the psvr object
first with parsnip::extract_fit_engine(), then call residuals() or
fitted() on that. psvr deliberately does not register S3 methods on
parsnip's class. Note also that parsnip::augment() recomputes predictions
on whatever new_data it is given and reports response residuals only, so
it is not a substitute for the "percentage" and "multiplicative" types.
See Also
fitted.psvr_mape() and the other fitted methods
Examples
set.seed(1)
X <- matrix(runif(40, 0.5, 3), 20, 2)
y <- 2 + X[, 1]^2
fit <- psvr_rmspe(X, y, kernel = make_kernel("rbf"), gamma = 100)
head(residuals(fit))
mean(abs(residuals(fit, type = "percentage"))) * 100 # training MAPE
# Through parsnip both generics return NULL on the model_fit wrapper;
# extract the engine object first.
df <- data.frame(x1 = X[, 1], x2 = X[, 2], y = y)
spec <- psvr_rmspe_rbf(cost = 10, rbf_sigma = 0.8)
pfit <- parsnip::fit(spec, y ~ x1 + x2, data = df)
residuals(pfit) # NULL
head(residuals(parsnip::extract_fit_engine(pfit))) # the residuals
Cross-validate psvr_mape() with automatic warm-start across folds
Description
Fits a psvr_mape() model on each split in splits, carrying the converged
dual variables (alpha, alpha_star) from one fold into the next as the SMO
warm-start, so each solve starts from the previous fold's optimum instead of
from zero. Because consecutive folds share most of their training rows, that
starting point is already close to feasible; before each solve the carried
vectors are projected back onto the constraint set (the equality
\sum_k \beta_k = 0 and the per-sample box), with the
residual violation absorbed by the rows that are new to this fold. The
warm-start procedure is Algorithm 1 of arXiv:2605.01446 v3. Returns a tibble
with one row per fold.
Usage
psvr_cv(
splits,
...,
X_var = NULL,
y_var = NULL,
warm_start = TRUE,
verbose = FALSE
)
Arguments
splits |
Either an |
... |
Arguments forwarded to |
X_var |
Character vector of predictor column names. |
y_var |
Single character giving the target column name. |
warm_start |
Logical; if |
verbose |
Logical; if |
Details
This helper is MAPE-only, and there is no loss argument. That is a
limitation of the implementation, not of the method: only psvr_mape() was
ever wired to it. LS-SVR cross-validates perfectly well, it simply has no
carryover state to exploit (each fold is a single linear-system solve), so
for psvr_rmspe() use tune::tune_grid() with parallel cold-start.
Value
A tibble with one row per split and columns:
split_id1-based fold index.
fitA list-column of
psvr_mapeobjects, orpsvr_mape_symwhensym_typeis"even"or"odd".predictionsA list-column of numeric vectors (predictions on the assessment set).
metricsA list-column of named numeric vectors (
mape,rmspe,mse,r2).iter_countInteger; SMO iterations from
fit$iterations.elapsed_secNumeric; wall-clock seconds for the fit.
warm_startedLogical;
TRUEfor fold > 1 whenwarm_start = TRUE.
Examples
if (requireNamespace("rsample", quietly = TRUE) &&
requireNamespace("tibble", quietly = TRUE)) {
set.seed(2026)
d <- data.frame(
y = stats::rlnorm(80, sdlog = 1.0),
x1 = stats::rnorm(80),
x2 = stats::rnorm(80)
)
folds <- rsample::vfold_cv(d, v = 5)
res <- psvr_cv(folds, X_var = c("x1", "x2"), y_var = "y",
kernel = make_kernel("rbf", sigma = 1),
C = 10, eps = 5)
median(vapply(res$metrics, function(m) m[["mape"]], numeric(1)))
}
Fit an epsilon-SVR with MAPE loss
Description
Fits the percentage-error epsilon-SVR of the paper: Model 1 when
sym_type = "none", and the symmetric-kernel Model 2 when sym_type is
"even" or "odd". The dual is a quadratic program with the
sample-dependent box |\beta_k| \le 100C/y_k
and \sum_k \beta_k = 0, solved by the built-in SMO
loop or by osqp.
Usage
psvr_mape(
X,
y,
sym_type = c("none", "even", "odd"),
kernel,
C,
eps,
solver = c("smo", "osqp"),
tol = 0.001,
max_iter = 100000L,
alpha_init = NULL,
alpha_star_init = NULL,
warm_start_check = TRUE,
block_k4_enabled = TRUE,
engine = c("rcpp", "r"),
...,
alpha_couple = 0.5,
precomputed_Omega = NULL,
precomputed_Omega_s = NULL
)
Arguments
X |
Numeric matrix of training inputs, one observation per row
( |
y |
Numeric vector of training targets, length |
sym_type |
Symmetry type, one of |
kernel |
A kernel function created by |
C |
Regularization parameter, |
eps |
Insensitivity tube half-width in percentage units,
|
solver |
Backend for the dual quadratic program, |
tol |
Numerical tolerance, default |
max_iter |
Maximum SMO iterations, default |
alpha_init, alpha_star_init |
Optional warm-start vectors for the SMO
solver, each a finite numeric vector of length |
warm_start_check |
Logical; if |
block_k4_enabled |
Logical; if |
engine |
One of |
... |
Must be empty. Present only so that |
alpha_couple |
Numeric in |
precomputed_Omega, precomputed_Omega_s |
INTERNAL – used by |
Details
For the least-squares / RMSPE family (Models 3 and 4) see psvr_rmspe().
The two are deliberately separate functions: they share no solver, no dual
structure and no hyperparameter search space, so a single signature would
make most of its own arguments conditional. The name psvr() is reserved
for a future automatic-selection front end and is not a synonym for
either.
Value
For sym_type = "none", an object of class "psvr_mape": a list
with components beta (the pruned dual differences
\beta = \alpha - \alpha^* over the
support-vector indices, used by predict()), alpha and alpha_star
(the length-N pre-pruning duals, retained for warm starts), b,
X_sv, y_sv, y_train, fitted_values, kernel, C, eps,
n_train, p_train, iterations, converged and block_k4.
For sym_type = "even" or "odd", an object of class "psvr_mape_sym":
the same components plus a (the symmetry parameter) and spectral
(adaptive spectral-shift diagnostics).
Methods are available for predict(), print(), coef(), summary(),
fitted() and residuals().
Choosing a solver
solver = "smo" (the default) uses the built-in sequential minimal
optimisation loop. On some problems it does not converge within
max_iter: it emits a warning(), converged is FALSE and iterations
reaches the cap. This was first observed with linear and polynomial
kernels, but it also occurs with the RBF kernel, so the kernel is not
what determines it, and what does has not been established. Check
converged on the returned fit, and refit with solver = "osqp" when it
is FALSE and accuracy matters.
See Also
psvr_rmspe() for the LS-SVR / RMSPE family, psvr_cv() for
cross-validation with warm-start carryover, make_kernel() for kernels.
Examples
set.seed(1)
X <- matrix(rnorm(40), 20, 2)
y <- rlnorm(20)
K <- make_kernel("rbf", sigma = 1)
fit <- psvr_mape(X, y, kernel = K, C = 10, eps = 5)
predict(fit, X[1:3, , drop = FALSE])
# Even-symmetric variant (Model 2): f(x) = f(-x).
fit_sym <- psvr_mape(X, y, sym_type = "even", kernel = K, C = 10, eps = 5)
predict(fit_sym, X[1:3, , drop = FALSE])
Parsnip model specs: epsilon-SVR with MAPE loss (Model 1)
Description
Create parsnip model specifications for psvr_mape() with a fixed kernel
type. Kernel parameters are tunable parsnip arguments; the symmetry
parameter a and solver tolerance are engine arguments passed via
set_engine().
Usage
psvr_mape_rbf(
mode = "regression",
engine = "psvr",
cost = NULL,
margin = NULL,
rbf_sigma = NULL,
sym_type = NULL
)
psvr_mape_poly(
mode = "regression",
engine = "psvr",
cost = NULL,
margin = NULL,
degree = NULL,
scale_factor = NULL,
sym_type = NULL
)
psvr_mape_linear(
mode = "regression",
engine = "psvr",
cost = NULL,
margin = NULL,
sym_type = NULL
)
Arguments
mode |
Only |
engine |
Only |
cost |
Regularization parameter |
margin |
Epsilon tube half-width |
rbf_sigma |
RBF bandwidth |
sym_type |
Symmetry type: |
degree |
Polynomial degree |
scale_factor |
Polynomial constant term ( |
Value
A parsnip model_spec object of the corresponding class.
Examples
library(parsnip)
spec <- psvr_mape_rbf(cost = 10, margin = 1, rbf_sigma = 1) |>
set_engine("psvr")
spec_poly <- psvr_mape_poly(cost = 10, margin = 1, degree = 2,
scale_factor = 1) |>
set_engine("psvr")
spec_lin <- psvr_mape_linear(cost = 10, margin = 1) |>
set_engine("psvr")
# Symmetric epsilon-SVR (Model 2) via the sym_type argument:
spec_sym <- psvr_mape_rbf(cost = 10, margin = 1, rbf_sigma = 1,
sym_type = "even") |>
set_engine("psvr")
Apply data-driven rbf_sigma to all psvr workflows in a workflow set
Description
A convenience wrapper that calls workflowsets::option_add() for every
psvr workflow in wf_set (those whose wflow_id contains "m1",
"m2", "m3", or "m4"), replacing the rbf_sigma dials parameter
with a data-driven one built from X via rbf_sigma_psvr_data().
Usage
psvr_option_add(wf_set, X, width = 10, sample_size = 500L, seed = NULL)
Arguments
wf_set |
A |
X |
A numeric matrix or data frame of preprocessed predictors. |
width |
Positive scalar. Passed to |
sample_size |
Integer. Passed to |
seed |
Integer seed for subsampling. Default |
Value
The updated workflow_set (the same object with option_add()
applied to each psvr workflow).
See Also
rbf_sigma_psvr_data(), sigma_heuristic()
Examples
## Not run:
# After building wf_set and preprocessing:
train_baked <- rec |> prep() |> bake(new_data = train)
wf_set <- psvr_option_add(wf_set, train_baked |> select(-outcome))
## End(Not run)
Apply data-driven LS-SVR cost range to all m3/m4 workflows in a workflow set
Description
A convenience wrapper that calls workflowsets::option_add() for
every LS-SVR psvr workflow in wf_set (those whose wflow_id
matches "m3" or "m4"), replacing the cost dials parameter
with one built from y via cost_psvr_ls_data().
Usage
psvr_option_add_cost_ls(wf_set, y, width_log2 = 4)
Arguments
wf_set |
A |
y |
Numeric vector of strictly positive training targets. |
width_log2 |
Passed to |
Details
Workflows for m1/m2 (\epsilon-SVR) are intentionally
skipped — for
those, cost maps to C and the static cost_psvr() range is
usually adequate.
Note: workflowsets::option_add() replaces the whole param_info
option for each matched workflow. If you also need a data-driven
rbf_sigma (via psvr_option_add()), build the full param_info
manually with tune::extract_parameter_set_dials() and call
workflowsets::option_add() in one shot, or call this helper
first and then psvr_option_add() (which only touches
rbf_sigma) — the latter currently overwrites the former, so
prefer the manual one-shot approach when both are needed.
Value
The updated workflow_set.
See Also
cost_psvr_ls_data(), psvr_option_add()
Examples
## Not run:
# After building wf_set with at least one m3 or m4 workflow:
wf_set <- psvr_option_add_cost_ls(wf_set, y = train_df$y)
## End(Not run)
Fit a least-squares SVR with RMSPE loss
Description
Fits the percentage-error LS-SVR of the paper: Model 3 when
sym_type = "none", and the symmetric-kernel Model 4 when sym_type is
"even" or "odd". There is no quadratic program and no sparsity: the fit
is a single solve of the (N+1) \times (N+1) augmented
linear system
\begin{pmatrix} 0 & 1^{\top} \\ 1 & \Omega + Y_{\Gamma}\end{pmatrix}
\begin{pmatrix} b \\ \alpha \end{pmatrix} =
\begin{pmatrix} 0 \\ y \end{pmatrix}
with Y_{\Gamma} = \mathrm{diag}(y_1^2/\Gamma, \ldots,
y_N^2/\Gamma), and
\Omega_s replacing \Omega in the symmetric case.
Every training point contributes to the prediction.
Usage
psvr_rmspe(
X,
y,
sym_type = c("none", "even", "odd"),
kernel,
gamma,
precondition = "auto",
...
)
Arguments
X |
Numeric matrix of training inputs, one observation per row
( |
y |
Numeric vector of training targets, length |
sym_type |
Symmetry type, one of |
kernel |
A kernel function created by |
gamma |
Regularization parameter |
precondition |
One of |
... |
Must be empty. Passing anything here is an error, which is how a mistyped argument name is caught. |
Details
For the epsilon-SVR / MAPE family (Models 1 and 2) see psvr_mape(). The two
are deliberately separate functions: they share no solver, no dual structure
and no hyperparameter search space. The name psvr() is reserved for a
future automatic-selection front end and is not a synonym for either.
Value
For sym_type = "none", an object of class "psvr_rmspe": a list
with components alpha (the length-N multipliers), b,
X_train, y_train, fitted_values, kernel, gamma, n_train,
p_train and precondition_applied.
For sym_type = "even" or "odd", an object of class "psvr_rmspe_sym":
the same components plus a (the symmetry parameter).
Methods are available for predict(), print(), coef(), summary(),
fitted() and residuals(). Note that coef() returns three components
here (alpha, b, support_data) against five for the MAPE classes:
LS-SVR has no alpha_star and no pruned beta, and the absent components
are not materialised as NULL.
See Also
psvr_mape() for the epsilon-SVR / MAPE family, make_kernel()
for kernels.
Examples
set.seed(1)
X <- matrix(rnorm(40), 20, 2)
y <- rlnorm(20)
K <- make_kernel("rbf", sigma = 1)
fit <- psvr_rmspe(X, y, kernel = K, gamma = 100)
predict(fit, X[1:3, , drop = FALSE])
# Even-symmetric variant (Model 4): f(x) = f(-x).
fit_sym <- psvr_rmspe(X, y, sym_type = "even", kernel = K, gamma = 100)
predict(fit_sym, X[1:3, , drop = FALSE])
Parsnip model specs: LS-SVR with RMSPE loss (Model 3)
Description
Create parsnip model specifications for psvr_rmspe() with a fixed kernel
type. cost maps to the regularization parameter \Gamma.
Usage
psvr_rmspe_rbf(
mode = "regression",
engine = "psvr",
cost = NULL,
rbf_sigma = NULL,
sym_type = NULL
)
psvr_rmspe_poly(
mode = "regression",
engine = "psvr",
cost = NULL,
degree = NULL,
scale_factor = NULL,
sym_type = NULL
)
psvr_rmspe_linear(
mode = "regression",
engine = "psvr",
cost = NULL,
sym_type = NULL
)
Arguments
mode |
Only |
engine |
Only |
cost |
Regularization parameter |
rbf_sigma |
RBF bandwidth |
sym_type |
Symmetry type: |
degree |
Polynomial degree |
scale_factor |
Polynomial constant term ( |
Value
A parsnip model_spec object of the corresponding class.
Engine arguments
The precondition argument of psvr_rmspe() is exposed as a non-tunable
engine argument. Pass it via parsnip::set_engine(), e.g.
set_engine("psvr", precondition = "always"). Default is "auto". See
psvr_rmspe() for accepted values and semantics.
Examples
library(parsnip)
spec <- psvr_rmspe_rbf(cost = 1000, rbf_sigma = 1) |>
set_engine("psvr")
spec_poly <- psvr_rmspe_poly(cost = 1000, degree = 2, scale_factor = 1) |>
set_engine("psvr")
spec_lin <- psvr_rmspe_linear(cost = 1000) |>
set_engine("psvr")
# Symmetric LS-SVR (Model 4) via the sym_type argument:
spec_sym <- psvr_rmspe_rbf(cost = 1000, rbf_sigma = 1,
sym_type = "even") |>
set_engine("psvr")
RBF sigma parameter for psvr models
Description
A dials parameter for the RBF kernel bandwidth in psvr models.
The default range [-3, 1] on the log10 scale is a conservative
fallback. For best results, override the range using
sigma_heuristic() computed on the preprocessed training data:
Usage
rbf_sigma_psvr(range = c(-3, 1), trans = scales::log10_trans())
Arguments
range |
Numeric vector of length 2 on the log10 scale.
Default |
trans |
A |
Details
train_baked <- rec |> prep() |> bake(new_data = train)
sigma_med <- sigma_heuristic(train_baked |> select(-outcome))
rbf_sigma_custom <- rbf_sigma_psvr(
range = c(log10(sigma_med / 10), log10(sigma_med * 10))
)
# Then inject via option_add():
wf_set |> option_add(
param_info = extract_parameter_set_dials(wf) |>
update(rbf_sigma = rbf_sigma_custom),
id = "your_workflow_id"
)
Value
A quant_param dials object.
See Also
Examples
rbf_sigma_psvr()
# Override with data-driven range:
X <- matrix(rnorm(200), ncol = 4)
sigma_med <- sigma_heuristic(X)
rbf_sigma_psvr(range = c(log10(sigma_med / 10), log10(sigma_med * 10)))
RBF sigma parameter with data-driven range for psvr models
Description
A convenience wrapper that combines sigma_heuristic() and
rbf_sigma_psvr() in a single call. It computes the median pairwise
distance from X and returns a quant_param whose search range spans
one order of magnitude either side of the heuristic value on the log10
scale (i.e., [log10(sigma_med / width), log10(sigma_med * width)]).
Usage
rbf_sigma_psvr_data(
X,
width = 10,
sample_size = 500L,
seed = NULL,
trans = scales::log10_trans()
)
Arguments
X |
A numeric matrix or data frame of predictors (already preprocessed — centred, scaled, etc.). |
width |
Positive scalar. Multiplier that sets the half-width of the
search range around the heuristic sigma. Default |
sample_size |
Integer. Passed to |
seed |
Integer seed for subsampling. Passed to |
trans |
A |
Value
A quant_param dials object with a data-driven search range.
See Also
sigma_heuristic(), rbf_sigma_psvr()
Examples
X <- matrix(rnorm(200), ncol = 4)
rbf_sigma_psvr_data(X)
rbf_sigma_psvr_data(X, width = 5)
Median-distance heuristic for RBF kernel bandwidth
Description
Returns the median pairwise Euclidean distance between rows of X,
which is a standard data-driven starting point for the RBF kernel
bandwidth (Schölkopf & Smola, 2002). Use the result to define a
sensible rbf_sigma search range centred on this value via
dials::rbf_sigma(range = c(log10(sigma / 10), log10(sigma * 10))).
Usage
sigma_heuristic(X, sample_size = 500L, seed = NULL)
Arguments
X |
A numeric matrix or data frame of predictors (already preprocessed — centred, scaled, etc.). |
sample_size |
Integer. If |
seed |
Integer seed for the subsample. Default |
Value
A scalar numeric: the median pairwise Euclidean distance.
Examples
X <- matrix(rnorm(200), ncol = 4)
sigma_heuristic(X)
Summarize a fitted epsilon-SVR with MAPE loss
Description
Prints the kernel, the training and support-vector counts, the hyperparameters, and the SMO iteration count with its convergence status. Every training point contributes for LS-SVR but not here: the support-vector percentage is the sparsity of the fit.
Usage
## S3 method for class 'psvr_mape'
summary(object, ...)
Arguments
object |
An object of class |
... |
Ignored. |
Value
object, invisibly. Called for the printed summary.
See Also
print.psvr_mape(), coef.psvr_mape()
Examples
set.seed(1)
X <- matrix(rnorm(40), 20, 2)
y <- rlnorm(20)
fit <- psvr_mape(X, y, kernel = make_kernel("rbf", sigma = 1),
C = 10, eps = 5)
summary(fit)
Summarize a fitted symmetric epsilon-SVR with MAPE loss
Description
As summary.psvr_mape(), with the symmetry parameter a reported.
Usage
## S3 method for class 'psvr_mape_sym'
summary(object, ...)
Arguments
object |
An object of class |
... |
Ignored. |
Value
object, invisibly. Called for the printed summary.
See Also
print.psvr_mape_sym(), coef.psvr_mape_sym()
Examples
set.seed(1)
X <- matrix(rnorm(40), 20, 2)
y <- rlnorm(20)
fit <- psvr_mape(X, y, sym_type = "even",
kernel = make_kernel("rbf", sigma = 1), C = 10, eps = 5)
summary(fit)
Summarize a fitted LS-SVR with RMSPE loss
Description
Prints the kernel, the training count, the hyperparameter, and whether the
diag(1/y) preconditioner fired. No support-vector count is reported: LS-SVR
performs no pruning, so every training point contributes to the prediction.
Usage
## S3 method for class 'psvr_rmspe'
summary(object, ...)
Arguments
object |
An object of class |
... |
Ignored. |
Value
object, invisibly. Called for the printed summary.
See Also
print.psvr_rmspe(), coef.psvr_rmspe()
Examples
set.seed(1)
X <- matrix(rnorm(40), 20, 2)
y <- rlnorm(20)
fit <- psvr_rmspe(X, y, kernel = make_kernel("rbf", sigma = 1), gamma = 100)
summary(fit)
Summarize a fitted symmetric LS-SVR with RMSPE loss
Description
As summary.psvr_rmspe(), with the symmetry parameter a reported.
Usage
## S3 method for class 'psvr_rmspe_sym'
summary(object, ...)
Arguments
object |
An object of class |
... |
Ignored. |
Value
object, invisibly. Called for the printed summary.
See Also
print.psvr_rmspe_sym(), coef.psvr_rmspe_sym()
Examples
set.seed(1)
X <- matrix(rnorm(40), 20, 2)
y <- rlnorm(20)
fit <- psvr_rmspe(X, y, sym_type = "even",
kernel = make_kernel("rbf", sigma = 1), gamma = 100)
summary(fit)
Compute a symmetric kernel block for prediction
Description
Block form of sym_kernel_vector(): entry [k, i] equals
½ * Ks(X[k, ], Xnew[i, ]) where Ks(xi, xj) = K(xi, xj) + a * K(xi, -xj).
Used by the predict() methods of the symmetric models (Models 2 and 4).
Usage
sym_kernel_block(K, X, Xnew, a)
Arguments
K |
A kernel function from |
X |
Numeric training matrix (N × p). |
Xnew |
Numeric matrix of new points (M × p). |
a |
Symmetry parameter: |
Details
Built from two kernel_matrix() calls rather than a nested R loop, so
built-in kernels reach the Rcpp implementations; user-defined closures
still fall through to .legacy_kernel_matrix(). Element-wise this is the
same 0.5 * (K + a * K_neg) arithmetic in the same order as the per-row
loop it replaces, so predictions are bit-identical.
Value
Numeric N × M matrix.
Compute the symmetrized kernel matrix Omega_s = (Omega + a Omega*) / 2
Description
Used by the symmetric LS-SVR model (Model 4). Entry [k, l] of
\Omega^* is K(xk, -xl), so negation is applied to the
columns of X (i.e., to X2).
Usage
sym_kernel_matrix(K, X, a)
Arguments
K |
A kernel function from |
X |
Numeric training matrix (N × p). |
a |
Symmetry parameter: |
Value
Numeric N × N matrix
\Omega_s = \frac{1}{2}(\Omega + a\Omega^*).
Compute a symmetric kernel vector for prediction
Description
For a new point x, returns the N-vector with entry k equal to
½ * Ks(X[k, ], x) where Ks(xi, xj) = K(xi, xj) + a * K(xi, -xj).
Thin wrapper over the single-column case of sym_kernel_block().
Usage
sym_kernel_vector(K, X, x, a)
Arguments
K |
A kernel function from |
X |
Numeric training matrix (N × p). |
x |
Numeric vector (length p), the new point to predict. |
a |
Symmetry parameter: |
Value
Numeric vector of length N.
Dials parameter for symmetry type
Description
Returns a qualitative dials::new_qual_param() describing the sym_type
argument of the psvr model specs. "none" fits the non-symmetric model;
"even" maps to a = 1L (standard symmetric kernel); "odd" maps to
a = -1L (anti-symmetric kernel).
Usage
sym_type_param(values = c("none", "even", "odd"))
Arguments
values |
Character vector of levels to search over. Any subset of
|
Value
A qual_param object.
Examples
sym_type_param()
sym_type_param(values = c("even", "odd"))