Title: | Constrained Multivariate Least Squares |
---|---|
Description: | Solves multivariate least squares (MLS) problems subject to constraints on the coefficients, e.g., non-negativity, orthogonality, equality, inequality, monotonicity, unimodality, smoothness, etc. Includes flexible functions for solving MLS problems subject to user-specified equality and/or inequality constraints, as well as a wrapper function that implements 24 common constraint options. Also does k-fold or generalized cross-validation to tune constraint options for MLS problems. See ten Berge (1993, ISBN:9789066950832) for an overview of MLS problems, and see Goldfarb and Idnani (1983) <doi:10.1007/BF02591962> for a discussion of the underlying quadratic programming algorithm. |
Authors: | Nathaniel E. Helwig <[email protected]> |
Maintainer: | Nathaniel E. Helwig <[email protected]> |
License: | GPL (>= 2) |
Version: | 1.0-1 |
Built: | 2024-10-31 06:22:41 UTC |
Source: | CRAN |
Solves multivariate least squares (MLS) problems subject to constraints on the coefficients, e.g., non-negativity, orthogonality, equality, inequality, monotonicity, unimodality, smoothness, etc. Includes flexible functions for solving MLS problems subject to user-specified equality and/or inequality constraints, as well as a wrapper function that implements 24 common constraint options. Also does k-fold or generalized cross-validation to tune constraint options for MLS problems. See ten Berge (1993, ISBN:9789066950832) for an overview of MLS problems, and see Goldfarb and Idnani (1983) <doi:10.1007/BF02591962> for a discussion of the underlying quadratic programming algorithm.
The DESCRIPTION file:
Package: | CMLS |
Type: | Package |
Title: | Constrained Multivariate Least Squares |
Version: | 1.0-1 |
Date: | 2023-03-29 |
Author: | Nathaniel E. Helwig <[email protected]> |
Maintainer: | Nathaniel E. Helwig <[email protected]> |
Depends: | quadprog, parallel |
Description: | Solves multivariate least squares (MLS) problems subject to constraints on the coefficients, e.g., non-negativity, orthogonality, equality, inequality, monotonicity, unimodality, smoothness, etc. Includes flexible functions for solving MLS problems subject to user-specified equality and/or inequality constraints, as well as a wrapper function that implements 24 common constraint options. Also does k-fold or generalized cross-validation to tune constraint options for MLS problems. See ten Berge (1993, ISBN:9789066950832) for an overview of MLS problems, and see Goldfarb and Idnani (1983) <doi:10.1007/BF02591962> for a discussion of the underlying quadratic programming algorithm. |
License: | GPL (>= 2) |
NeedsCompilation: | no |
Packaged: | 2023-03-29 15:23:47 UTC; nate |
Repository: | CRAN |
Date/Publication: | 2023-03-31 17:30:02 UTC |
Index of help topics:
CMLS-package Constrained Multivariate Least Squares IsplineBasis I-Spline Basis for Monotonic Polynomial Splines MsplineBasis M-Spline Basis for Polynomial Splines cmls Solve a Constrained Multivariate Least Squares Problem const Print or Return Constraint Options for cmls cv.cmls Cross-Validation for cmls mlsei Multivariate Least Squares with Equality/Inequality Constraints mlsun Multivariate Least Squares with Unimodality (and E/I) Constraints
The cmls
function provides a user-friendly interface for solving the MLS problem with 24 common constraint options (the const
function prints or returns the different contraint options). The cv.cmls
function does k-fold or generalized cross-validation to tune the constraint options of the cmls
function. The mlsei
function solves the MLS problem subject to user-specified equality and/or inequality (E/I) constraints on the coefficients. The mlsun
function solves the MLS problem subject to unimodality constraints and user-specified E/I constraints on the coefficients.
Nathaniel E. Helwig <[email protected]>
Maintainer: Nathaniel E. Helwig <[email protected]>
Goldfarb, D., & Idnani, A. (1983). A numerically stable dual method for solving strictly convex quadratic programs. Mathematical Programming, 27, 1-33. doi:10.1007/BF02591962
Helwig, N. E. (in prep). Constrained multivariate least squares in R.
Ten Berge, J. M. F. (1993). Least Squares Optimization in Multivariate Analysis. Volume 25 of M & T Series. DSWO Press, Leiden University. ISBN: 9789066950832
Turlach, B. A., & Weingessel, A. (2019). quadprog: Functions to solve Quadratic Programming Problems. R package version 1.5-8. https://CRAN.R-project.org/package=quadprog
# See examples for cmls, cv.cmls, mlsei, and mlsun
# See examples for cmls, cv.cmls, mlsei, and mlsun
Finds the x
matrix
B
that minimizes the multivariate least squares problem
sum(( Y - X %*% B )^2)
|
subject to the specified constraints on the rows of B
.
cmls(X, Y, const = "uncons", struc = NULL, z = NULL, df = 10, degree = 3, intercept = TRUE, backfit = FALSE, maxit = 1e3, eps = 1e-10, del = 1e-6, XtX = NULL, mode.range = NULL)
cmls(X, Y, const = "uncons", struc = NULL, z = NULL, df = 10, degree = 3, intercept = TRUE, backfit = FALSE, maxit = 1e3, eps = 1e-10, del = 1e-6, XtX = NULL, mode.range = NULL)
X |
Matrix of dimension |
Y |
Matrix of dimension |
const |
Constraint code. See |
struc |
Structural constraints (defaults to unstructured). See Note. |
z |
Predictor values for the spline basis (for smoothness constraints). See Note. |
df |
Degrees of freedom for the spline basis (for smoothness constraints). See Note. |
degree |
Polynomial degree for the spline basis (for smoothness constraints). See Note. |
intercept |
Logical indicating whether the spline basis should contain an intercept (for smoothness constraints). See Note. |
backfit |
Estimate |
maxit |
Maximum number of iterations for back-fitting algorithm. Ignored if |
eps |
Convergence tolerance for back-fitting algorithm. Ignored if |
del |
Stability tolerance for back-fitting algorithm. Ignored if |
XtX |
Crossproduct matrix: |
mode.range |
Mode search ranges (for unimodal constraints). See Note. |
If backfit = FALSE
(default), a closed-form solution is used to estimate B
whenever possible. Otherwise a back-fitting algorithm is used, where the rows of B
are updated sequentially until convergence. The backfitting algorithm is determined to have converged when
mean((B.new - B.old)^2) < eps * (mean(B.old^2) + del)
,
where B.old
and B.new
denote the parameter estimates at iterations and
of the backfitting algorithm.
Returns the estimated matrix B
with attribute "df" (degrees of freedom), which gives the df for each row of B
.
Structure constraints (struc
) should be specified with a x
matrix of logicals (TRUE/FALSE), such that FALSE elements indicate a weight should be constrained to be zero. Default uses unstructured weights, i.e., a
x
matrix of all TRUE values.
Inputs z
, df
, degree
, and intercept
are only applicable when using one of the 12 constraints that involves a spline basis, i.e., "smooth", "smonon", "smoper", "smpeno", "ortsmo", "orsmpe", "monsmo", "mosmno", "unismo", "unsmno", "unsmpe", "unsmpn".
Input mode.range
is only applicable when using one of the 8 constraints that enforces unimodality: "unimod", "uninon", "uniper", "unpeno", "unismo", "unsmno", "unsmpe", "unsmpn". Mode search ranges (mode.range
) should be specified with a 2 x matrix of integers such that
1 <= mode.range[1,j] <= mode.range[2,j] <= m
for all j = 1:p
.
Default is mode.range = matrix(c(1, m), 2, p)
.
Nathaniel E. Helwig <[email protected]>
Goldfarb, D., & Idnani, A. (1983). A numerically stable dual method for solving strictly convex quadratic programs. Mathematical Programming, 27, 1-33. doi:10.1007/BF02591962
Helwig, N. E. (in prep). Constrained multivariate least squares in R.
Ten Berge, J. M. F. (1993). Least Squares Optimization in Multivariate Analysis. Volume 25 of M & T Series. DSWO Press, Leiden University. ISBN: 9789066950832
Turlach, B. A., & Weingessel, A. (2019). quadprog: Functions to solve Quadratic Programming Problems. R package version 1.5-8. https://CRAN.R-project.org/package=quadprog
const
prints/returns the contraint options.
cv.cmls
performs k-fold cross-validation to tune the constraint options.
mlsei
and mlsun
are used to implement several of the constraints.
######***###### GENERATE DATA ######***###### # make X set.seed(2) n <- 50 m <- 20 p <- 2 Xmat <- matrix(rnorm(n*p), nrow = n, ncol = p) # make B (which satisfies all constraints except monotonicity) x <- seq(0, 1, length.out = m) Bmat <- rbind(sin(2*pi*x), sin(2*pi*x+pi)) / sqrt(4.75) struc <- rbind(rep(c(TRUE, FALSE), each = m / 2), rep(c(FALSE, TRUE), each = m / 2)) Bmat <- Bmat * struc # make noisy data set.seed(1) Ymat <- Xmat %*% Bmat + rnorm(n*m, sd = 0.25) ######***###### UNCONSTRAINED ######***###### # unconstrained Bhat <- cmls(X = Xmat, Y = Ymat, const = "uncons") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unconstrained and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "uncons", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### NON-NEGATIVITY ######***###### # non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "nonneg") mean((Bhat - Bmat)^2) attr(Bhat, "df") # non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "nonneg", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### PERIODICITY ######***###### # periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "period") mean((Bhat - Bmat)^2) attr(Bhat, "df") # periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "period", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # periodic and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "pernon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # periodic and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "pernon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### SMOOTHNESS ######***###### # smooth Bhat <- cmls(X = Xmat, Y = Ymat, const = "smooth") mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "smooth", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "smoper") mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "smoper", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "smonon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "smonon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and periodic and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "smpeno") mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and periodic and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "smpeno", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### ORTHOGONALITY ######***###### # orthogonal Bhat <- cmls(X = Xmat, Y = Ymat, const = "orthog") mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "orthog", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthgonal and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "ortnon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthgonal and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "ortnon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and smooth Bhat <- cmls(X = Xmat, Y = Ymat, const = "ortsmo") mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and smooth and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "ortsmo", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and smooth and periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "orsmpe") mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and smooth and periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "orsmpe", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### UNIMODALITY ######***###### # unimodal Bhat <- cmls(X = Xmat, Y = Ymat, const = "unimod") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unimod", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "uninon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "uninon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "uniper") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "uniper", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and periodic and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "unpeno") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and periodic and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unpeno", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### UNIMODALITY AND SMOOTHNESS ######***###### # unimodal and smooth Bhat <- cmls(X = Xmat, Y = Ymat, const = "unismo") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unismo", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmno") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmno", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmpe") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmpe", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and periodic and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmpn") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and periodic and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmpn", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### MONOTONICITY ######***###### # make B x <- 1:m Bmat <- rbind(1 / (1 + exp(-(x - quantile(x, 0.5)))), 1 / (1 + exp(-(x - quantile(x, 0.8))))) struc <- rbind(rep(c(FALSE, TRUE), c(1 * m, 3 * m) / 4), rep(c(FALSE, TRUE), c(m, m) / 2)) Bmat <- Bmat * struc # make noisy data set.seed(1) Ymat <- Xmat %*% Bmat + rnorm(m*n, sd = 0.25) # monotonic increasing Bhat <- cmls(X = Xmat, Y = Ymat, const = "moninc") mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "moninc", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "monnon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "monnon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and smooth Bhat <- cmls(X = Xmat, Y = Ymat, const = "monsmo") mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and smooth and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "monsmo", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and smooth and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "mosmno") mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and smooth and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "mosmno", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df")
######***###### GENERATE DATA ######***###### # make X set.seed(2) n <- 50 m <- 20 p <- 2 Xmat <- matrix(rnorm(n*p), nrow = n, ncol = p) # make B (which satisfies all constraints except monotonicity) x <- seq(0, 1, length.out = m) Bmat <- rbind(sin(2*pi*x), sin(2*pi*x+pi)) / sqrt(4.75) struc <- rbind(rep(c(TRUE, FALSE), each = m / 2), rep(c(FALSE, TRUE), each = m / 2)) Bmat <- Bmat * struc # make noisy data set.seed(1) Ymat <- Xmat %*% Bmat + rnorm(n*m, sd = 0.25) ######***###### UNCONSTRAINED ######***###### # unconstrained Bhat <- cmls(X = Xmat, Y = Ymat, const = "uncons") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unconstrained and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "uncons", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### NON-NEGATIVITY ######***###### # non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "nonneg") mean((Bhat - Bmat)^2) attr(Bhat, "df") # non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "nonneg", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### PERIODICITY ######***###### # periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "period") mean((Bhat - Bmat)^2) attr(Bhat, "df") # periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "period", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # periodic and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "pernon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # periodic and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "pernon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### SMOOTHNESS ######***###### # smooth Bhat <- cmls(X = Xmat, Y = Ymat, const = "smooth") mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "smooth", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "smoper") mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "smoper", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "smonon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "smonon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and periodic and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "smpeno") mean((Bhat - Bmat)^2) attr(Bhat, "df") # smooth and periodic and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "smpeno", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### ORTHOGONALITY ######***###### # orthogonal Bhat <- cmls(X = Xmat, Y = Ymat, const = "orthog") mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "orthog", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthgonal and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "ortnon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthgonal and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "ortnon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and smooth Bhat <- cmls(X = Xmat, Y = Ymat, const = "ortsmo") mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and smooth and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "ortsmo", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and smooth and periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "orsmpe") mean((Bhat - Bmat)^2) attr(Bhat, "df") # orthogonal and smooth and periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "orsmpe", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### UNIMODALITY ######***###### # unimodal Bhat <- cmls(X = Xmat, Y = Ymat, const = "unimod") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unimod", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "uninon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "uninon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "uniper") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "uniper", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and periodic and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "unpeno") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and periodic and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unpeno", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### UNIMODALITY AND SMOOTHNESS ######***###### # unimodal and smooth Bhat <- cmls(X = Xmat, Y = Ymat, const = "unismo") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unismo", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmno") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmno", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and periodic Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmpe") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and periodic and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmpe", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and periodic and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmpn") mean((Bhat - Bmat)^2) attr(Bhat, "df") # unimodal and smooth and periodic and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "unsmpn", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") ######***###### MONOTONICITY ######***###### # make B x <- 1:m Bmat <- rbind(1 / (1 + exp(-(x - quantile(x, 0.5)))), 1 / (1 + exp(-(x - quantile(x, 0.8))))) struc <- rbind(rep(c(FALSE, TRUE), c(1 * m, 3 * m) / 4), rep(c(FALSE, TRUE), c(m, m) / 2)) Bmat <- Bmat * struc # make noisy data set.seed(1) Ymat <- Xmat %*% Bmat + rnorm(m*n, sd = 0.25) # monotonic increasing Bhat <- cmls(X = Xmat, Y = Ymat, const = "moninc") mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "moninc", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "monnon") mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "monnon", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and smooth Bhat <- cmls(X = Xmat, Y = Ymat, const = "monsmo") mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and smooth and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "monsmo", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and smooth and non-negative Bhat <- cmls(X = Xmat, Y = Ymat, const = "mosmno") mean((Bhat - Bmat)^2) attr(Bhat, "df") # monotonic increasing and smooth and non-negative and structured Bhat <- cmls(X = Xmat, Y = Ymat, const = "mosmno", struc = struc) mean((Bhat - Bmat)^2) attr(Bhat, "df")
Prints or returns six letter constraint codes for cmls
, along with corresponding descriptions.
const(x, print = TRUE)
const(x, print = TRUE)
x |
Vector of six letter constraint codes. If missing, prints/returns all 24 options. |
print |
Should constraint information be printed ( |
Prints (or returns) constraint codes and descriptions.
Nathaniel E. Helwig <[email protected]>
Helwig, N. E. (in prep). Constrained multivariate least squares in R.
Constraints are used in the cmls
function.
# print some constraints const(c("uncons", "smpeno")) # return some constraints const(c("uncons", "smpeno"), print = FALSE) # print all constraints const() # return all constraints const(print = FALSE)
# print some constraints const(c("uncons", "smpeno")) # return some constraints const(c("uncons", "smpeno"), print = FALSE) # print all constraints const() # return all constraints const(print = FALSE)
Does k-fold or generalized cross-validation to tune the constraint options for cmls
. Tunes the model with respect to any combination of the arguments const
, df
, degree
, and/or intercept
.
cv.cmls(X, Y, nfolds = 2, foldid = NULL, parameters = NULL, const = "uncons", df = 10, degree = 3, intercept = TRUE, mse = TRUE, parallel = FALSE, cl = NULL, verbose = TRUE, ...)
cv.cmls(X, Y, nfolds = 2, foldid = NULL, parameters = NULL, const = "uncons", df = 10, degree = 3, intercept = TRUE, mse = TRUE, parallel = FALSE, cl = NULL, verbose = TRUE, ...)
X |
Matrix of dimension |
Y |
Matrix of dimension |
nfolds |
Number of folds for k-fold cross-validation. Ignored if |
foldid |
Factor or integer vector of length |
parameters |
Parameters for tuning. Data frame with columns |
const |
Parameters for tuning. Character vector specifying constraints for tuning. See Details. |
df |
Parameters for tuning. Integer vector specifying degrees of freedom for tuning. See Details. |
degree |
Parameters for tuning. Integer vector specifying polynomial degrees for tuning. See Details. |
intercept |
Parameters for tuning. Logical vector specifying intercepts for tuning. See Details. |
mse |
If |
parallel |
Logical indicating if |
cl |
Cluster created by |
verbose |
If |
... |
Additional arguments to the |
The parameters for tuning can be supplied via one of two options:
(A) Using the parameters
argument. In this case, the argument parameters
must be a data frame with columns const
, df
, degree
, and intercept
, where each row gives a combination of parameters for the CV tuning.
(B) Using the const
, df
, degree
, and intercept
arguments. In this case, the expand.grid
function is used to create the parameters
data frame, which contains all combinations of the arguments const
, df
, degree
, and intercept
. Duplicates are removed before the CV tuning.
best.parameters |
Best combination of parameters, i.e., the combination that minimizes the |
top5.parameters |
Top five combinations of parameters, i.e., the combinations that give the five smallest values of the |
full.parameters |
Full set of parameters. Data frame with |
Nathaniel E. Helwig <[email protected]>
Helwig, N. E. (in prep). Constrained multivariate least squares in R.
See the cmls
and const
functions for further details on the available constraint options.
# make X set.seed(1) n <- 50 m <- 20 p <- 2 Xmat <- matrix(rnorm(n*p), nrow = n, ncol = p) # make B (which satisfies all constraints except monotonicity) x <- seq(0, 1, length.out = m) Bmat <- rbind(sin(2*pi*x), sin(2*pi*x+pi)) / sqrt(4.75) struc <- rbind(rep(c(TRUE, FALSE), each = m / 2), rep(c(FALSE, TRUE), each = m / 2)) Bmat <- Bmat * struc # make noisy data Ymat <- Xmat %*% Bmat + rnorm(n*m, sd = 0.5) # 5-fold CV: tune df (5,...,15) for const = "smooth" kcv <- cv.cmls(X = Xmat, Y = Ymat, nfolds = 5, const = "smooth", df = 5:15) kcv$best.parameters kcv$top5.parameters plot(kcv$full.parameters$df, kcv$full.parameters$cvloss, t = "b") ## Not run: # sample foldid for 5-fold CV set.seed(2) foldid <- sample(rep(1:5, length.out = n)) # 5-fold CV: tune df (5,...,15) w/ all 20 relevant constraints (no struc) # using sequential computation (default) myconst <- as.character(const(print = FALSE)$label[-c(13:16)]) system.time({ kcv <- cv.cmls(X = Xmat, Y = Ymat, foldid = foldid, const = myconst, df = 5:15) }) kcv$best.parameters kcv$top5.parameters # 5-fold CV: tune df (5,...,15) w/ all 20 relevant constraints (no struc) # using parallel package for parallel computations myconst <- as.character(const(print = FALSE)$label[-c(13:16)]) system.time({ cl <- makeCluster(2L) # using 2 cores kcv <- cv.cmls(X = Xmat, Y = Ymat, foldid = foldid, const = myconst, df = 5:15, parallel = TRUE, cl = cl) stopCluster(cl) }) kcv$best.parameters kcv$top5.parameters # 5-fold CV: tune df (5,...,15) w/ all 20 relevant constraints (w/ struc) # using sequential computation (default) myconst <- as.character(const(print = FALSE)$label[-c(13:16)]) system.time({ kcv <- cv.cmls(X = Xmat, Y = Ymat, foldid = foldid, const = myconst, df = 5:15, struc = struc) }) kcv$best.parameters kcv$top5.parameters # 5-fold CV: tune df (5,...,15) w/ all 20 relevant constraints (w/ struc) # using parallel package for parallel computations myconst <- as.character(const(print = FALSE)$label[-c(13:16)]) system.time({ cl <- makeCluster(2L) # using 2 cores kcv <- cv.cmls(X = Xmat, Y = Ymat, foldid = foldid, const = myconst, df = 5:15, struc = struc, parallel = TRUE, cl = cl) stopCluster(cl) }) kcv$best.parameters kcv$top5.parameters ## End(Not run)
# make X set.seed(1) n <- 50 m <- 20 p <- 2 Xmat <- matrix(rnorm(n*p), nrow = n, ncol = p) # make B (which satisfies all constraints except monotonicity) x <- seq(0, 1, length.out = m) Bmat <- rbind(sin(2*pi*x), sin(2*pi*x+pi)) / sqrt(4.75) struc <- rbind(rep(c(TRUE, FALSE), each = m / 2), rep(c(FALSE, TRUE), each = m / 2)) Bmat <- Bmat * struc # make noisy data Ymat <- Xmat %*% Bmat + rnorm(n*m, sd = 0.5) # 5-fold CV: tune df (5,...,15) for const = "smooth" kcv <- cv.cmls(X = Xmat, Y = Ymat, nfolds = 5, const = "smooth", df = 5:15) kcv$best.parameters kcv$top5.parameters plot(kcv$full.parameters$df, kcv$full.parameters$cvloss, t = "b") ## Not run: # sample foldid for 5-fold CV set.seed(2) foldid <- sample(rep(1:5, length.out = n)) # 5-fold CV: tune df (5,...,15) w/ all 20 relevant constraints (no struc) # using sequential computation (default) myconst <- as.character(const(print = FALSE)$label[-c(13:16)]) system.time({ kcv <- cv.cmls(X = Xmat, Y = Ymat, foldid = foldid, const = myconst, df = 5:15) }) kcv$best.parameters kcv$top5.parameters # 5-fold CV: tune df (5,...,15) w/ all 20 relevant constraints (no struc) # using parallel package for parallel computations myconst <- as.character(const(print = FALSE)$label[-c(13:16)]) system.time({ cl <- makeCluster(2L) # using 2 cores kcv <- cv.cmls(X = Xmat, Y = Ymat, foldid = foldid, const = myconst, df = 5:15, parallel = TRUE, cl = cl) stopCluster(cl) }) kcv$best.parameters kcv$top5.parameters # 5-fold CV: tune df (5,...,15) w/ all 20 relevant constraints (w/ struc) # using sequential computation (default) myconst <- as.character(const(print = FALSE)$label[-c(13:16)]) system.time({ kcv <- cv.cmls(X = Xmat, Y = Ymat, foldid = foldid, const = myconst, df = 5:15, struc = struc) }) kcv$best.parameters kcv$top5.parameters # 5-fold CV: tune df (5,...,15) w/ all 20 relevant constraints (w/ struc) # using parallel package for parallel computations myconst <- as.character(const(print = FALSE)$label[-c(13:16)]) system.time({ cl <- makeCluster(2L) # using 2 cores kcv <- cv.cmls(X = Xmat, Y = Ymat, foldid = foldid, const = myconst, df = 5:15, struc = struc, parallel = TRUE, cl = cl) stopCluster(cl) }) kcv$best.parameters kcv$top5.parameters ## End(Not run)
Generate the I-spline basis matrix for a monotonic polynomial spline.
IsplineBasis(x, df = NULL, knots = NULL, degree = 3, intercept = FALSE, Boundary.knots = range(x))
IsplineBasis(x, df = NULL, knots = NULL, degree = 3, intercept = FALSE, Boundary.knots = range(x))
x |
the predictor variable. Missing values are not allowed. |
df |
degrees of freedom; if specified the number of |
knots |
the internal breakpoints that define the spline (typically the quantiles of |
degree |
degree of the M-spline basis—default is 3 for cubic splines |
intercept |
if |
Boundary.knots |
boundary points for M-spline basis; defaults to min and max of |
Syntax is adapted from the bs
function in the splines package (R Core Team, 2021).
Used for implementing monotonic smoothness constraints in the cmls
fucntion.
A matrix of dimension c(length(x), df)
where either df
was supplied or df = length(knots) + degree + ifelse(intercept, 1, 0)
I-spline basis functions are created by integrating M-spline basis functions.
Nathaniel E. Helwig <[email protected]>
R Core Team (2023). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/
Ramsay, J. O. (1988). Monotone regression splines in action. Statistical Science, 3, 425-441. doi:10.1214/ss/1177012761
x <- seq(0, 1, length.out = 101) I <- IsplineBasis(x, df = 8, intercept = TRUE) plot(x, I[,1], ylim = c(0, 1), t = "l") for(j in 2:8) lines(x, I[,j], col = j)
x <- seq(0, 1, length.out = 101) I <- IsplineBasis(x, df = 8, intercept = TRUE) plot(x, I[,1], ylim = c(0, 1), t = "l") for(j in 2:8) lines(x, I[,j], col = j)
Finds the x
matrix
B
that minimizes the multivariate least squares problem
sum(( Y - X %*% t(Z %*% B) )^2)
|
subject to t(A) %*% B[,j] >= b
for all j = 1:p
. Unique basis functions and constraints are allowed for each column of B
.
mlsei(X, Y, Z, A, b, meq, backfit = FALSE, maxit = 1000, eps = 1e-10, del = 1e-6, XtX = NULL, ZtZ = NULL, simplify = TRUE, catchError = FALSE)
mlsei(X, Y, Z, A, b, meq, backfit = FALSE, maxit = 1000, eps = 1e-10, del = 1e-6, XtX = NULL, ZtZ = NULL, simplify = TRUE, catchError = FALSE)
X |
Matrix of dimension |
Y |
Matrix of dimension |
Z |
Matrix of dimension |
A |
Constraint matrix of dimension |
b |
Consraint vector of dimension |
meq |
The first |
backfit |
Estimate |
maxit |
Maximum number of iterations for back-fitting algorithm. Ignored if |
eps |
Convergence tolerance for back-fitting algorithm. Ignored if |
del |
Stability tolerance for back-fitting algorithm. Ignored if |
XtX |
Crossproduct matrix: |
ZtZ |
Crossproduct matrix: |
simplify |
If |
catchError |
If |
If backfit = FALSE
(default), a closed-form solution is used to estimate B
whenever possible. Otherwise a back-fitting algorithm is used, where the columns of B
are updated sequentially until convergence. The backfitting algorithm is determined to have converged when
mean((B.new - B.old)^2) < eps * (mean(B.old^2) + del)
,
where B.old
and B.new
denote the parameter estimates at iterations and
of the backfitting algorithm.
If Z
is a list with for all
, then...
B |
is returned as a |
B |
is returned as a list of length |
If Z
is a list with for some
, then
B
is returned as a list of length .
Otherwise B
is returned as a x
matrix.
The Z
input can also be a list of length where
Z[[j]]
contains a x
matrix. If
for all
and
simplify = TRUE
, the output B
will be a matrix. Otherwise B
will be a list of length where
B[[j]]
contains a x 1 vector.
The A
and b
inputs can also be lists of length where
t(A[[j]]) %*% B[,j] >= b[[j]]
for all . If
A
and b
are lists of length , the
meq
input should be a vector of length indicating the number of equality constraints for each element of
A
.
Nathaniel E. Helwig <[email protected]>
Goldfarb, D., & Idnani, A. (1983). A numerically stable dual method for solving strictly convex quadratic programs. Mathematical Programming, 27, 1-33. doi:10.1007/BF02591962
Helwig, N. E. (in prep). Constrained multivariate least squares in R.
Ten Berge, J. M. F. (1993). Least Squares Optimization in Multivariate Analysis. Volume 25 of M & T Series. DSWO Press, Leiden University. ISBN: 9789066950832
Turlach, B. A., & Weingessel, A. (2019). quadprog: Functions to solve Quadratic Programming Problems. R package version 1.5-8. https://CRAN.R-project.org/package=quadprog
cmls
calls this function for several of the constraints.
######***###### GENERATE DATA ######***###### # make X set.seed(2) n <- 50 m <- 20 p <- 2 Xmat <- matrix(rnorm(n*p), nrow = n, ncol = p) # make B (which satisfies all constraints except monotonicity) x <- seq(0, 1, length.out = m) Bmat <- rbind(sin(2*pi*x), sin(2*pi*x+pi)) / sqrt(4.75) struc <- rbind(rep(c(TRUE, FALSE), each = m / 2), rep(c(FALSE, TRUE), each = m / 2)) Bmat <- Bmat * struc # make noisy data set.seed(1) Ymat <- Xmat %*% Bmat + rnorm(n*m, sd = 0.25) ######***###### UNCONSTRAINED ######***###### # unconstrained Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "uncons") Bhat.mlsei <- t(mlsei(X = Xmat, Y = Ymat)) mean((Bhat.cmls - Bhat.mlsei)^2) # unconstrained and structured (note: cmls is more efficient) Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "uncons", struc = struc) Amat <- vector("list", p) meq <- rep(0, p) for(j in 1:p){ meq[j] <- sum(!struc[j,]) if(meq[j] > 0){ A <- matrix(0, nrow = m, ncol = meq[j]) A[!struc[j,],] <- diag(meq[j]) Amat[[j]] <- A } else { Amat[[j]] <- matrix(0, nrow = m, ncol = 1) } } Bhat.mlsei <- t(mlsei(X = Xmat, Y = Ymat, A = Amat, meq = meq)) mean((Bhat.cmls - Bhat.mlsei)^2) ######***###### NON-NEGATIVITY ######***###### # non-negative Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "nonneg") Bhat.mlsei <- t(mlsei(X = Xmat, Y = Ymat, A = diag(m))) mean((Bhat.cmls - Bhat.mlsei)^2) # non-negative and structured (note: cmls is more efficient) Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "nonneg", struc = struc) eye <- diag(m) meq <- rep(0, p) for(j in 1:p){ meq[j] <- sum(!struc[j,]) Amat[[j]] <- eye[,sort(struc[j,], index.return = TRUE)$ix] } Bhat.mlsei <- t(mlsei(X = Xmat, Y = Ymat, A = Amat, meq = meq)) mean((Bhat.cmls - Bhat.mlsei)^2) # see internals of cmls.R for further examples
######***###### GENERATE DATA ######***###### # make X set.seed(2) n <- 50 m <- 20 p <- 2 Xmat <- matrix(rnorm(n*p), nrow = n, ncol = p) # make B (which satisfies all constraints except monotonicity) x <- seq(0, 1, length.out = m) Bmat <- rbind(sin(2*pi*x), sin(2*pi*x+pi)) / sqrt(4.75) struc <- rbind(rep(c(TRUE, FALSE), each = m / 2), rep(c(FALSE, TRUE), each = m / 2)) Bmat <- Bmat * struc # make noisy data set.seed(1) Ymat <- Xmat %*% Bmat + rnorm(n*m, sd = 0.25) ######***###### UNCONSTRAINED ######***###### # unconstrained Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "uncons") Bhat.mlsei <- t(mlsei(X = Xmat, Y = Ymat)) mean((Bhat.cmls - Bhat.mlsei)^2) # unconstrained and structured (note: cmls is more efficient) Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "uncons", struc = struc) Amat <- vector("list", p) meq <- rep(0, p) for(j in 1:p){ meq[j] <- sum(!struc[j,]) if(meq[j] > 0){ A <- matrix(0, nrow = m, ncol = meq[j]) A[!struc[j,],] <- diag(meq[j]) Amat[[j]] <- A } else { Amat[[j]] <- matrix(0, nrow = m, ncol = 1) } } Bhat.mlsei <- t(mlsei(X = Xmat, Y = Ymat, A = Amat, meq = meq)) mean((Bhat.cmls - Bhat.mlsei)^2) ######***###### NON-NEGATIVITY ######***###### # non-negative Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "nonneg") Bhat.mlsei <- t(mlsei(X = Xmat, Y = Ymat, A = diag(m))) mean((Bhat.cmls - Bhat.mlsei)^2) # non-negative and structured (note: cmls is more efficient) Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "nonneg", struc = struc) eye <- diag(m) meq <- rep(0, p) for(j in 1:p){ meq[j] <- sum(!struc[j,]) Amat[[j]] <- eye[,sort(struc[j,], index.return = TRUE)$ix] } Bhat.mlsei <- t(mlsei(X = Xmat, Y = Ymat, A = Amat, meq = meq)) mean((Bhat.cmls - Bhat.mlsei)^2) # see internals of cmls.R for further examples
Finds the x
matrix
B
that minimizes the multivariate least squares problem
sum(( Y - X %*% t(Z %*% B) )^2)
|
subject to Z %*% B[,j]
is unimodal and t(A) %*% B[,j] >= b
for all j = 1:p
. Unique basis functions and constraints are allowed for each column of B
.
mlsun(X, Y, Z, A, b, meq, mode.range = NULL, maxit = 1000, eps = 1e-10, del = 1e-6, XtX = NULL, ZtZ = NULL, simplify = TRUE, catchError = FALSE)
mlsun(X, Y, Z, A, b, meq, mode.range = NULL, maxit = 1000, eps = 1e-10, del = 1e-6, XtX = NULL, ZtZ = NULL, simplify = TRUE, catchError = FALSE)
X |
Matrix of dimension |
Y |
Matrix of dimension |
Z |
Matrix of dimension |
A |
Constraint matrix of dimension |
b |
Consraint vector of dimension |
meq |
The first |
mode.range |
Mode search ranges, which should be a 2 x |
maxit |
Maximum number of iterations for back-fitting algorithm. Ignored if |
eps |
Convergence tolerance for back-fitting algorithm. Ignored if |
del |
Stability tolerance for back-fitting algorithm. Ignored if |
XtX |
Crossproduct matrix: |
ZtZ |
Crossproduct matrix: |
simplify |
If |
catchError |
If |
A back-fitting algorithm is used to estimate B
, where the columns of B
are updated sequentially until convergence (outer loop). For each column of B
, (the inner loop of) the algorithm searches for the j-th mode across the search range specified by the j-th column of mode.range
. The backfitting algorithm is determined to have converged when
mean((B.new - B.old)^2) < eps * (mean(B.old^2) + del)
,
where B.old
and B.new
denote the parameter estimates at outer iterations and
of the backfitting algorithm.
If Z
is a list with for all
, then...
B |
is returned as a |
B |
is returned as a list of length |
If Z
is a list with for some
, then
B
is returned as a list of length .
Otherwise B
is returned as a x
matrix.
The Z
input can also be a list of length where
Z[[j]]
contains a x
matrix. If
for all
and
simplify = TRUE
, the output B
will be a matrix. Otherwise B
will be a list of length where
B[[j]]
contains a x 1 vector.
The A
and b
inputs can also be lists of length where
t(A[[j]]) %*% B[,j] >= b[[j]]
for all . If
A
and b
are lists of length , the
meq
input should be a vector of length indicating the number of equality constraints for each element of
A
.
Nathaniel E. Helwig <[email protected]>
Goldfarb, D., & Idnani, A. (1983). A numerically stable dual method for solving strictly convex quadratic programs. Mathematical Programming, 27, 1-33. doi:10.1007/BF02591962
Helwig, N. E. (in prep). Constrained multivariate least squares in R.
Ten Berge, J. M. F. (1993). Least Squares Optimization in Multivariate Analysis. Volume 25 of M & T Series. DSWO Press, Leiden University. ISBN: 9789066950832
Turlach, B. A., & Weingessel, A. (2019). quadprog: Functions to solve Quadratic Programming Problems. R package version 1.5-8. https://CRAN.R-project.org/package=quadprog
cmls
calls this function for the unimodality constraints.
######***###### GENERATE DATA ######***###### # make X set.seed(2) n <- 50 m <- 20 p <- 2 Xmat <- matrix(rnorm(n*p), nrow = n, ncol = p) # make B (which satisfies all constraints except monotonicity) x <- seq(0, 1, length.out = m) Bmat <- rbind(sin(2*pi*x), sin(2*pi*x+pi)) / sqrt(4.75) struc <- rbind(rep(c(TRUE, FALSE), each = m / 2), rep(c(FALSE, TRUE), each = m / 2)) Bmat <- Bmat * struc # make noisy data set.seed(1) Ymat <- Xmat %*% Bmat + rnorm(n*m, sd = 0.25) ######***###### UNIMODALITY ######***###### # unimodal Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "unimod") Bhat.mlsun <- t(mlsun(X = Xmat, Y = Ymat)) mean((Bhat.cmls - Bhat.mlsun)^2) # unimodal and structured Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "unimod", struc = struc) Amat <- vector("list", p) meq <- rep(0, p) for(j in 1:p){ meq[j] <- sum(!struc[j,]) if(meq[j] > 0){ A <- matrix(0, nrow = m, ncol = meq[j]) A[!struc[j,],] <- diag(meq[j]) Amat[[j]] <- A } else { Amat[[j]] <- matrix(0, nrow = m, ncol = 1) } } Bhat.mlsun <- t(mlsun(X = Xmat, Y = Ymat, A = Amat, meq = meq)) mean((Bhat.cmls - Bhat.mlsun)^2) # unimodal and non-negative Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "uninon") Bhat.mlsun <- t(mlsun(X = Xmat, Y = Ymat, A = diag(m))) mean((Bhat.cmls - Bhat.mlsun)^2) # unimodal and non-negative and structured Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "uninon", struc = struc) eye <- diag(m) meq <- rep(0, p) for(j in 1:p){ meq[j] <- sum(!struc[j,]) Amat[[j]] <- eye[,sort(struc[j,], index.return = TRUE)$ix] } Bhat.mlsun <- t(mlsun(X = Xmat, Y = Ymat, A = Amat, meq = meq)) mean((Bhat.cmls - Bhat.mlsun)^2) # see internals of cmls.R for further examples
######***###### GENERATE DATA ######***###### # make X set.seed(2) n <- 50 m <- 20 p <- 2 Xmat <- matrix(rnorm(n*p), nrow = n, ncol = p) # make B (which satisfies all constraints except monotonicity) x <- seq(0, 1, length.out = m) Bmat <- rbind(sin(2*pi*x), sin(2*pi*x+pi)) / sqrt(4.75) struc <- rbind(rep(c(TRUE, FALSE), each = m / 2), rep(c(FALSE, TRUE), each = m / 2)) Bmat <- Bmat * struc # make noisy data set.seed(1) Ymat <- Xmat %*% Bmat + rnorm(n*m, sd = 0.25) ######***###### UNIMODALITY ######***###### # unimodal Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "unimod") Bhat.mlsun <- t(mlsun(X = Xmat, Y = Ymat)) mean((Bhat.cmls - Bhat.mlsun)^2) # unimodal and structured Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "unimod", struc = struc) Amat <- vector("list", p) meq <- rep(0, p) for(j in 1:p){ meq[j] <- sum(!struc[j,]) if(meq[j] > 0){ A <- matrix(0, nrow = m, ncol = meq[j]) A[!struc[j,],] <- diag(meq[j]) Amat[[j]] <- A } else { Amat[[j]] <- matrix(0, nrow = m, ncol = 1) } } Bhat.mlsun <- t(mlsun(X = Xmat, Y = Ymat, A = Amat, meq = meq)) mean((Bhat.cmls - Bhat.mlsun)^2) # unimodal and non-negative Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "uninon") Bhat.mlsun <- t(mlsun(X = Xmat, Y = Ymat, A = diag(m))) mean((Bhat.cmls - Bhat.mlsun)^2) # unimodal and non-negative and structured Bhat.cmls <- cmls(X = Xmat, Y = Ymat, const = "uninon", struc = struc) eye <- diag(m) meq <- rep(0, p) for(j in 1:p){ meq[j] <- sum(!struc[j,]) Amat[[j]] <- eye[,sort(struc[j,], index.return = TRUE)$ix] } Bhat.mlsun <- t(mlsun(X = Xmat, Y = Ymat, A = Amat, meq = meq)) mean((Bhat.cmls - Bhat.mlsun)^2) # see internals of cmls.R for further examples
Generate the M-spline basis matrix for a polynomial spline.
MsplineBasis(x, df = NULL, knots = NULL, degree = 3, intercept = FALSE, Boundary.knots = range(x), periodic = FALSE)
MsplineBasis(x, df = NULL, knots = NULL, degree = 3, intercept = FALSE, Boundary.knots = range(x), periodic = FALSE)
x |
the predictor variable. Missing values are not allowed. |
df |
degrees of freedom; if specified the number of |
knots |
the internal breakpoints that define the spline (typically the quantiles of |
degree |
degree of the piecewise polynomial—default is 3 for cubic splines |
intercept |
if |
Boundary.knots |
boundary points for M-spline basis; defaults to min and max of |
periodic |
if |
Syntax is adapted from the bs
function in the splines package (R Core Team, 2021).
Used for implementing various types of smoothness constraints in the cmls
fucntion.
A matrix of dimension c(length(x), df)
where either df
was supplied or df = length(knots) + degree + ifelse(intercept, 1, 0)
Nathaniel E. Helwig <[email protected]>
R Core Team (2023). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/
Ramsay, J. O. (1988). Monotone regression splines in action. Statistical Science, 3, 425-441. doi:10.1214/ss/1177012761
x <- seq(0, 1, length.out = 101) M <- MsplineBasis(x, df = 8, intercept = TRUE) M <- scale(M, center = FALSE) plot(x, M[,1], ylim = range(M), t = "l") for(j in 2:8) lines(x, M[,j], col = j)
x <- seq(0, 1, length.out = 101) M <- MsplineBasis(x, df = 8, intercept = TRUE) M <- scale(M, center = FALSE) plot(x, M[,1], ylim = range(M), t = "l") for(j in 2:8) lines(x, M[,j], col = j)