Getting Started

Estimators in sortedl1 are compatible with the scikit-learn interface. Here is a simple example of fitting a model to some random data.

We start by generating the data.

import numpy as np
from numpy.random import default_rng

from sortedl1 import Slope

# Generate some random data
n = 100
p = 10

seed = 31
rng = default_rng(seed)

x = rng.standard_normal((n, p))
beta = rng.standard_normal(p)
y = x @ beta + rng.standard_normal(n)

Next, we create the estimator by calling Slope() with all the desired parameters.

model = Slope(alpha=0.1)

Now we can fit the model to the data using the fit method, which provides a fitted model for the given value of alpha above.

model.fit(x, y)
model.coef_
array([ 0.57298856, -1.03709127,  2.55814536,  0.56922823, -1.22227224,
       -1.54242725,  0.        , -1.30545222,  0.        ,  0.49147967])

Path Fitting

The package also supports fitting the full SLOPE path via the path method to Slope. In this case, the value of alpha is ignored and unless path() is called with a specific sequence of alpha values, a sequence will automatically be generated to cover solutions from the point where the first coefficient enters the model

res = model.path(x, y)

Unlike the fit method, calling path() does not modify the model object and instead returns a named tuple of class PathResults, with the full set of coefficients and intercepts for each value of alpha.

PathResults also includes concise helpers for quick inspection:

res
res.summary()
{'n_alphas': 77,
 'n_features': 10,
 'n_targets': 1,
 'alpha_min': 0.0010078421223305043,
 'alpha_max': 1.1860406557259944,
 'coef_shape': (10, 1, 77),
 'intercepts_shape': (1, 77),
 'lambda_shape': (10,),
 'nnz_first_alpha': 0,
 'nnz_last_alpha': 10}

It also comes with a plot() method to visualize the path of coefficients:

fig, ax = res.plot()
_images/224de9c3c04fd10fbc7c579873d6ae52ee9f8c006ad055171cb6b557860d7cd6.png

Cross-Validation

It is also easy to cross-validate in the sortedl1 package. Since the estimator is scikit-learn compatible, we could use the functionality from scikit-learn directly, but sortedl1 also includes native cross-validation routines that are optimized for the SLOPE package.

In the following example, we cross-validate across different levels of the gamma parameter, which fits the relaxed SLOPE model (a linear combination of SLOPE and ordinary least squares fit to the cluster structure from SLOPE).

cv_res = model.cv(x, y, q=[0.1], gamma=[0.0,0.5, 1.0])
fig, ax = cv_res.plot()
cv_res
cv_res.summary()
{'metric': 'mse',
 'n_param_sets': 3,
 'best_ind': 1,
 'best_alpha_ind': 76,
 'best_score': 1.0,
 'best_alpha': 0.0010078421223305043,
 'n_alphas_per_param': [77, 77, 77],
 'param_keys': ['gamma', 'q']}
_images/7795c6c8aae4c354674c0ac9ee59a8a44e0dbc71daa395fd3430e089eac56689.png

If you want both cross-validation results and a best model fitted on the full data used in cross-validation, use refit=True:

cv_res, best_model = model.cv(x, y, q=[0.1], gamma=[0.0, 0.5, 1.0], refit=True)
best_model.coef_
array([ 0.6839064 , -1.35532396,  2.79170419,  0.77506653, -1.38496846,
       -1.64029643,  0.16912158, -1.55571321,  0.09289521,  0.78894816])

In this low-dimensional example, we see that there is, unsurprisingly, little benefit to regularization.

Using scikit-learn model selection

The Slope estimator can also be used directly with scikit-learn model-selection tools such as GridSearchCV.

from sklearn.model_selection import GridSearchCV

param_grid = {"alpha": [0.01, 0.1, 1.0], "q": [0.05, 0.1, 0.2]}
search = GridSearchCV(Slope(), param_grid=param_grid, cv=5)
search.fit(x, y)

search.best_params_
{'alpha': 0.01, 'q': 0.2}