Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ README.qmd
^memcheck
^\.positai$
^\.claude$
^vignettes/*_files$
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ docs
.vscode/
tools/
.positai
inst/doc
14 changes: 9 additions & 5 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ Version: 1.0-0
Date: 2026-05-xx
Authors@R: person("Julien", "Chiquet", , "julien.chiquet@inrae.fr", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-3629-3429"))
Description: This package fits the solution paths of classical sparse regression
models with efficient active set algorithms by solving small sub-problems.
Include LASSO, SCAD, MCP, (Sparse) Group-LASSO, Cooperative-LASSO, LAVA and
Elastic-Net variants. Also provides a few methods for model selection purpose
Description: This package fits the solution paths of classical sparse regression
models with efficient active set algorithms by solving small sub-problems.
Include LASSO, SCAD, MCP, (Sparse) Group-LASSO, Cooperative-LASSO, LAVA and
Elastic-Net variants. Also provides a few methods for model selection purpose
(cross-validation, stability selection).
URL: https://github.com/jchiquet/quadrupen, https://jchiquet.github.io/quadrupen/
BugReports: https://github.com/jchiquet/quadrupen/issues
Expand Down Expand Up @@ -36,11 +36,14 @@ Suggests:
elasticnet,
glmnet,
igraph,
knitr,
lars,
MASS,
ncvreg,
grpreg,
rmarkdown,
testthat
LinkingTo:
LinkingTo:
Rcpp,
RcppArmadillo
Collate:
Expand All @@ -67,3 +70,4 @@ Collate:
Packaged: 2013-03-25 19:41:00 UTC; jchiquet
Roxygen: list(markdown = TRUE)
Config/roxygen2/version: 8.0.0
VignetteBuilder: knitr
3 changes: 2 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
NEWS/Changelog

# quadrupen dev version (2026-05-xx)
# quadrupen dev version (2026-06-xx)

- major updates
- complete rewriting of R code using R6 classes
Expand All @@ -13,6 +13,7 @@ NEWS/Changelog
- added mcp and scad (concave penalties, Chernozukov et al, 2017)
- added refit version of Lasso/Elastic-Net ("relaxed" Lasso/Enet)
- changing many parameters (badly) named, do not expect backward compatibility
- added vignettes
- minor updates
- Integration of changes from CRAN versions from 0.2-4 to 0.2-13
- set up github workflow for pkgdown page
Expand Down
5 changes: 3 additions & 2 deletions R/CrossValidation-R6Class.R
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ CrossValidation <- R6::R6Class(
print = function() { self$show() },
#' @description Plot 1-dimensional cross-validation
#' @param log_scale logical, should a log-scale be used for the x-axis
#' @param se logical, should confidence band be displayed (TRUE by default)
#' @param title graph title
#' @return a ggplot object
plotCV_1D = function(log_scale=TRUE, title = "Cross-validation error") {
plotCV_1D = function(log_scale=TRUE, title = "Cross-validation error", se = TRUE) {
## SIMPLE CROSS-VALIDATION GRAPH
if (length(self$lambda1) > length(self$lambda2)) {
d <- ggplot(self$data, aes(x=.data$lambda1,y=.data$mean)) + theme_bw()
Expand All @@ -97,7 +98,7 @@ CrossValidation <- R6::R6Class(
d <- d + xlab(xlab) + ylab("Mean square error") +
geom_point(alpha=0.3) +
geom_smooth(aes(ymin=.data$mean-.data$serr, ymax=.data$mean+.data$serr, group=as.factor(.data$lambda2),
colour=as.factor(.data$lambda2)), data=self$data, alpha=0.2, stat="identity")
colour=as.factor(.data$lambda2)), se=se, data=self$data, alpha=0.2, stat="identity")
if (log_scale) {
d <- d + scale_x_log10() + annotation_logticks(sides="b")
}
Expand Down
2 changes: 1 addition & 1 deletion R/QuadrupenFit-R6Class.R
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ QuadrupenFit <- R6::R6Class(
"path" = self$plot_path(log_scale = log_scale, labels = labels),
"criteria" = self$information_criteria$plot(log_scale = log_scale),
"crossval" = self$cross_validation$plot(log_scale = log_scale),
"stability" = self$stability_path$plot(log_scale = log_scale, labels = labels)
"stability" = self$stability_path$plot(labels = labels)
)
d

Expand Down
4 changes: 1 addition & 3 deletions R/StabilityPath-R6Class.R
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ StabilityPath <- R6::R6Class(
#' (first penalty level) or `"fraction"` (fraction of the
#' penalty level applied tune by \eqn{\lambda_1}{lambda1}). Default
#' is `"lambda"`.
#' @param log_scale logical; indicates if a log-scale should be used
#' when \code{xvar="lambda"}. Default is `TRUE`.
#' @param plot logical; indicates if the graph should be
#' plotted. Default is `TRUE`. If `FALSE`, only the
#' \pkg{ggplot2} object is sent back.
Expand Down Expand Up @@ -135,7 +133,7 @@ StabilityPath <- R6::R6Class(
#'
plot = function(
xvar = "lambda", title = "Stability path", labels = rep("unknown status",self$nvar),
sel_mode = c("rank", "PFER"), cutoff=0.75, PFER=2, nvarsel=floor(self$nobs/log(self$nvar))) {
sel_mode = c("rank", "PFER"), cutoff=0.75, PFER=2, nvarsel=min(self$nvar, floor(self$nobs/log(self$nvar)))) {

sel_mode <- match.arg(sel_mode)
selection <- rep("unselected",length(self$nonzero))
Expand Down
12 changes: 12 additions & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ template:
mathjax: true
math-rendering: mathjax

articles:
- title: "Getting started"
navbar: ~
contents:
- sparse-regression
- group-sparse-regression
- title: "Advanced topics"
navbar: ~
contents:
- structured-signal-recovery
- lava

reference:
- title: "Main functions for user"
desc: >
Expand Down
55 changes: 34 additions & 21 deletions inst/examples/ridge.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
library(quadrupen)
require(Matrix)

beta <- rep(c(0,1,0,-1,0), c(25,10,25,10,25))
cor <- 0.75
Expand All @@ -10,39 +11,51 @@ n <- 50
x <- as.matrix(matrix(rnorm(95*n),n,95) %*% chol(Sigma))
y <- 10 + x %*% beta + rnorm(n,0,10)
p <- ncol(x)
plot(beta, type = "s")


## neighborhood prior
C <- bandSparse(p,k=0:1,diagonals=list(rep(1,p),rep(-1,p-1)))
L1 <- t(C) %*% C

## clique prior
## Structuring matrix :
# Laplacian of a community graph
# (clique prior)
Ioo <- matrix(1,25,25)
Iww <- matrix(1,10,10)
A <- bdiag(Ioo,Iww,Ioo,Iww,Ioo)
diag(A) <- 0
L2 <- -A
diag(L2) <- colSums(A) + 1e-2

ridge.classical <- ridge(x,y,intercept=F)
plot(ridge.classical)
ridge.neighborhood <- ridge(x,y, struct=L1, lambda_max=1000)
plot(ridge.neighborhood)
ridge.block <- ridge(x,y, struct=L2, lambda_max=1000)
plot(ridge.block)


labels <- paste("segment", rep(1:5, c(25,10,25,10,25)), sep="-" )
lasso_fit <- lasso(x,y,intercept=F)
plot(lasso_fit, labels=labels)
fused_lasso_fit <- fused_lasso(x,y,lambda2=5,intercept=F)
plot(fused_lasso_fit, labels=labels)
ridge_fit <- ridge(x,y,intercept=F)
plot(ridge_fit, labels=labels)
ridge_struct <- ridge(x,y, struct=L2, lambda_max=1000)
plot(ridge_struct, labels=labels)
enet_fit <- elastic_net(x,y, lambda2 = 5, intercept=F)
plot(enet_fit, labels=labels)
enet_struct <- elastic_net(x,y, lambda2 = 5, struct=L2)
plot(enet_struct, labels=labels)
enet_struct$debias <- TRUE
plot(enet_struct, labels=labels)

beta_lasso <- as.numeric(lasso(x,y,lambda=10)$coefficients)
beta_fused_lasso <- as.numeric(fused_lasso(x,y,lambda1=20, lambda2 = 5)$coefficients)
beta_ridge <- as.numeric(ridge(x,y,lambda=1)$coefficients)
beta_ridge_neighbor <- as.numeric(ridge(x,y,lambda=10,struct=L1)$coefficients)
beta_ridge_block <- as.numeric(ridge(x,y,lambda=10,struct=L2)$coefficients)
beta_enet_block <- as.numeric(elastic_net(x,y,lambda2=5,lambda1=20,struct=L2,refit=TRUE)$coefficients)
beta_ridge_struct <- as.numeric(ridge(x,y,lambda=10,struct=L2)$coefficients)
beta_enet_struct <- as.numeric(elastic_net(x,y,lambda2=5,lambda1=20,struct=L2)$coefficients)
beta_enet_struct_refit <- as.numeric(elastic_net(x,y,lambda2=5,lambda1=20,struct=L2,refit=TRUE)$coefficients)

par(mfrow=c(2,2))
par(mfrow=c(3,2))
plot(beta_lasso, type="b", ylim=c(-1,1))
points(beta, pch="+",col="red")
plot(beta_fused_lasso, type="b", ylim=c(-1,1))
points(beta, pch="+",col="red")
plot(beta_ridge, type="b", ylim=c(-1,1))
points(beta, pch="+",col="red")
plot(beta_ridge_neighbor, type="b", ylim=c(-1,1))
plot(beta_ridge_struct, type="b", ylim=c(-1,1))
points(beta, pch="+",col="red")
plot(beta_ridge_block, type="b", ylim=c(-1,1))
plot(beta_enet_struct, type="b", ylim=c(-1,1))
points(beta, pch="+",col="red")
plot(beta_enet_block, type="b", ylim=c(-1,1))
plot(beta_enet_struct_refit, type="b", ylim=c(-1,1))
points(beta, pch="+",col="red")
Loading
Loading