Example #1
0
    def __init__(self,
                 X=None,
                 Y=None,
                 feature_headers=None,
                 label_headers=None,
                 groups=None,
                 type='regressor',
                 cfg=False):

        if X is not None:
            self.X = X

        if Y is not None:
            self.Y = Y

        self.type = type
        self.cfg = cfg

        self.mapping_dict = None
        self.label_headers = label_headers
        self.no_inputs = len(feature_headers)

        if groups is None:
            groups = [1 for i in range(self.no_inputs)]
        else:
            groups = groups
        self.model = GroupLasso(groups=groups, supress_warning=True)
Example #2
0
class lasso_transformer:
    def __init__(self,r,groups_ids):
        self.lasso = GroupLasso(    groups=groups_ids,    group_reg=r,     l1_reg=r,    n_iter = 1000,
                                       scale_reg="None",       supress_warning=True,    tol=1e-04,
    )
    def fit(self,X,y):
        self.lasso.fit(X,y.values.reshape(-1, 1))

    def transform(self,X,y=None):
        return self.lasso.transform(X)


    def fit_transform(self,X,y):
        self.fit(X,y)
        return self.transform(X,y)
Example #3
0
def single_gene_GLG(X, ptime, L, Dt, g, sigma, lamb, mask, queue, K, Ksum,
                    groups, group_reg):
    A, y, K = convert_to_FISTA(X, ptime, L, Dt, g, mask, queue, K, Ksum)
    nSamp, nFea = A.shape
    NL = int(L / Dt)
    #out = training(A,y,np.random.rand(A.shape[1]),0)
    gl = GroupLasso(
        groups=groups,
        group_reg=group_reg,
        l1_reg=lamb,
        frobenius_lipschitz=True,
        scale_reg="inverse_group_size",
        subsampling_scheme=1,
        supress_warning=True,
        n_iter=10000,
        tol=1e-3,
    )
    gl.fit(A, y.reshape(-1, 1))
    return gl.coef_.reshape(-1)
Example #4
0
class GLasso(Model):

    # X represents the features, Y represents the labels
    X = None
    Y = None
    prediction = None
    model = None

    def __init__(self,
                 X=None,
                 Y=None,
                 feature_headers=None,
                 label_headers=None,
                 groups=None,
                 type='regressor',
                 cfg=False):

        if X is not None:
            self.X = X

        if Y is not None:
            self.Y = Y

        self.type = type
        self.cfg = cfg

        self.mapping_dict = None
        self.label_headers = label_headers
        self.no_inputs = len(feature_headers)

        if groups is None:
            groups = [1 for i in range(self.no_inputs)]
        else:
            groups = groups
        self.model = GroupLasso(groups=groups, supress_warning=True)

    def fit(self, X=None, Y=None):
        if X is not None:
            self.X = X

        if Y is not None:
            self.Y = Y

        if self.type == 'classifier':
            self.Y = self.map_str_to_number(self.Y)

        print('Group Lasso Train started............')
        self.model.fit(self.X, self.Y)
        print('Group Lasso completed..........')

        return self.model

    def predict(self, test_features):
        print('Prediction started............')
        self.predictions = self.model.predict(test_features)
        if self.type == 'classifier':
            predictions = predictions.round()
        print('Prediction completed..........')
        return self.predictions

    def save(self):
        if self.cfg:
            f = open('grouplasso_configs.txt', 'w')
            f.write(json.dumps(self.model.get_params()))
            f.close()
        print('No models will be saved for Group lasso')

    def featureImportance(self):
        return self.model.coef_

    def map_str_to_number(self, Y):
        mapping_flag = False
        if self.mapping_dict is not None:
            for label_header in self.label_headers:
                Y[label_header] = Y[label_header].map(self.mapping_dict)
            return Y

        mapping_dict = None
        for label_header in self.label_headers:
            check_list = pd.Series(Y[label_header])
            for item in check_list:
                if type(item) == str:
                    mapping_flag = True
                    break
            if mapping_flag:
                classes = Y[label_header].unique()
                mapping_dict = {}
                index = 0
                for c in classes:
                    mapping_dict[c] = index
                    index += 1

                Y[label_header] = Y[label_header].map(mapping_dict)
                mapping_flag = False

        self.mapping_dict = mapping_dict
        return Y

    def map_number_to_str(self, Y, classes):
        Y = Y.round()
        Y = Y.astype(int)
        if self.mapping_dict is not None:
            mapping_dict = self.mapping_dict
        else:
            mapping_dict = {}
            index = 0
            for c in classes:
                mapping_dict[index] = c
                index += 1

        inv_map = {v: k for k, v in mapping_dict.items()}
        return Y.map(inv_map)

    def getAccuracy(self, test_labels, predictions, origin=0, hitmissr=0.8):
        if self.type == 'classifier':
            correct = 0
            df = pd.DataFrame(data=predictions.flatten())
            test_labels = self.map_str_to_number(test_labels.copy())
            for i in range(len(df)):
                if (df.values[i] == test_labels.values[i]):
                    correct = correct + 1
        else:
            correct = 0
            df = pd.DataFrame(data=predictions.flatten())
            for i in range(len(df)):
                if 1 - abs(df.values[i] - test_labels.values[i]) / abs(
                        df.values[i]) >= hitmissr:
                    correct = correct + 1
        return float(correct) / len(df)

    def getConfusionMatrix(self, test_labels, predictions, label_headers):
        df = pd.DataFrame(data=predictions.flatten())
        if self.type == 'classifier':
            index = 0
            for label_header in label_headers:
                classes = test_labels[label_header].unique()
                df_tmp = self.map_number_to_str(df.ix[:, index], classes)
                title = 'Normalized confusion matrix for Group Lasso (' + label_header + ')'
                self.plot_confusion_matrix(test_labels.ix[:, index],
                                           df_tmp,
                                           classes=classes,
                                           normalize=True,
                                           title=title)
                index = index + 1
        else:
            return 'No Confusion Matrix for Regression'

    def getROC(self, test_labels, predictions, label_headers):
        predictions = pd.DataFrame(data=predictions.flatten())
        predictions.columns = test_labels.columns.values
        if self.type == 'classifier':
            test_labels = self.map_str_to_number(test_labels)
            fpr, tpr, _ = roc_curve(test_labels, predictions)
            plt.figure(1)
            plt.plot([0, 1], [0, 1], 'k--')
            plt.plot(fpr, tpr)
            plt.xlabel('False positive rate')
            plt.ylabel('True positive rate')
            plt.title('ROC curve')
            plt.show()
        else:
            return 'No Confusion Matrix for Regression'

    def getRSquare(self, test_labels, predictions, mode='single'):
        df = pd.DataFrame(data=predictions.flatten())
        if self.type == 'regressor':
            if mode == 'multiple':
                errors = r2_score(test_labels,
                                  df,
                                  multioutput='variance_weighted')
            else:
                errors = r2_score(test_labels, df)
            return errors
        else:
            return 'No RSquare for Classification'

    def getMSE(self, test_labels, predictions):
        df = pd.DataFrame(data=predictions.flatten())
        if self.type == 'regressor':
            errors = mean_squared_error(test_labels, df)
            return errors
        else:
            return 'No MSE for Classification'

    def getMAPE(self, test_labels, predictions):
        df = pd.DataFrame(data=predictions.flatten())
        if self.type == 'regressor':
            errors = np.mean(np.abs(
                (test_labels - df.values) / test_labels)) * 100
            return errors.values[0]
        else:
            return 'No MAPE for Classification'

    def getRMSE(self, test_labels, predictions):
        df = pd.DataFrame(data=predictions.flatten())
        if self.type == 'regressor':
            errors = sqrt(mean_squared_error(test_labels, df))
            return errors
        else:
            return 'No RMSE for Classification'
    w1 = generate_group_lasso_coefficients(group_sizes)
    w2 = generate_group_lasso_coefficients(group_sizes)
    w = np.hstack((w1, w2))
    w *= np.random.random((len(w), 1)) > 0.4
    w += np.random.randn(*w.shape) * coeff_noise_level

    print("Generating targets")
    y = X @ w
    y += np.random.randn(*y.shape) * noise_level * y
    y += intercept

    gl = GroupLasso(
        groups=groups,
        n_iter=10,
        tol=1e-8,
        l1_reg=0.05,
        group_reg=0.08,
        frobenius_lipschitz=True,
        subsampling_scheme=None,
        fit_intercept=True,
    )
    print("Starting fit")
    gl.LOG_LOSSES = True
    gl.fit(X, y)

    for i in range(w.shape[1]):
        plt.figure()
        plt.subplot(211)
        plt.plot(w[:, i], ".", label="True weights")
        plt.plot(gl.coef_[:, i], ".", label="Estimated weights")

        plt.subplot(212)
Example #6
0
def groupLasso_demo(signal_type, fig_start):
  X,Y,W_actual,groups = generate_data(signal_type)
  #Plotting the actual W
  plt.figure(0+fig_start)
  plt.plot(W_actual)
  plt.title("Original (D = 4096, number groups = 64, active groups = 8)")
  plt.savefig("W_actual_{}.png".format(signal_type) , dpi=300)
  ##### Applying Lasso Regression #####
  # L1 norm is the sum of absolute values of coefficients
  lasso_reg = linear_model.Lasso(alpha=0.5)
  lasso_reg.fit(X, Y)
  W_lasso_reg = lasso_reg.coef_
  ##### Debiasing step #####
  ba = np.argwhere(W_lasso_reg != 0) #Finding where the coefficients are not zero
  X_debiased = X[:, ba]
  W_lasso_reg_debiased = np.linalg.lstsq(X_debiased[:,:,0],Y) #Re-estimate the chosen coefficients using least squares
  W_lasso_reg_debiased_2 = np.zeros((4096))
  W_lasso_reg_debiased_2[ba] = W_lasso_reg_debiased[0]
  lasso_reg_mse = mean_squared_error(W_actual, W_lasso_reg_debiased_2)
  plt.figure(1+fig_start)
  plt.plot(W_lasso_reg_debiased_2)
  plt.title('Standard L1 (debiased 1, regularization param(L1 = 0.5), MSE = {:.4f})'.format(lasso_reg_mse))
  plt.savefig("W_lasso_reg_{}.png".format(signal_type), dpi=300)
  ##### Applying Group Lasso L2 regression #####
  # L2 norm is the square root of sum of squares of coefficients 
  # PNLL(W) = NLL(W) + regularization_parameter * Σ(groups)L2-norm
  group_lassoL2_reg = GroupLasso(
    groups=groups,
    group_reg=3,
    l1_reg=1,
    frobenius_lipschitz=True,
    scale_reg="inverse_group_size",
    subsampling_scheme=1,
    supress_warning=True,
    n_iter=1000,
    tol=1e-3,
  )
  group_lassoL2_reg.fit(X, Y)
  W_groupLassoL2_reg = group_lassoL2_reg.coef_
  ##### Debiasing step #####
  ba = np.argwhere(W_groupLassoL2_reg != 0) #Finding where the coefficients are not zero
  X_debiased = X[:, ba]
  W_group_lassoL2_reg_debiased = np.linalg.lstsq(X_debiased[:,:,0],Y) #Re-estimate the chosen coefficients using least squares
  W_group_lassoL2_reg_debiased_2 = np.zeros((4096))
  W_group_lassoL2_reg_debiased_2[ba] = W_group_lassoL2_reg_debiased[0]
  groupLassoL2_mse = mean_squared_error(W_actual, W_group_lassoL2_reg_debiased_2)
  plt.figure(2+fig_start)
  plt.plot(W_group_lassoL2_reg_debiased_2)
  plt.title('Block-L2 (debiased 1, regularization param(L2 = 3, L1=1), MSE = {:.4f})'.format(groupLassoL2_mse))
  plt.savefig("W_groupLassoL2_reg_{}.png".format(signal_type), dpi=300)
  ##### Applying Group Lasso Linf regression #####
  # To use spams library, it is necessary to convert data to fortran normalized arrays
  # visit http://spams-devel.gforge.inria.fr/ for the documentation of spams library
  # Linf is the supremum of all the coeifficients
  # PNLL(W) = NLL(W) + regularization_parameter * Σ(groups)Linf-norm
  X_normalized = np.asfortranarray(X - np.tile(np.mean(X,0),(X.shape[0],1)),dtype=float)
  X_normalized = spams.normalize(X_normalized)
  Y_normalized = np.asfortranarray(Y - np.tile(np.mean(Y,0),(Y.shape[0],1)),dtype=float)
  Y_normalized = spams.normalize(Y_normalized)
  groups_modified = np.concatenate([[i] for i in groups]).reshape(-1, 1)
  W_initial = np.zeros((X_normalized.shape[1],Y_normalized.shape[1]),dtype=float,order="F")
  param = {'numThreads' : -1,'verbose' : True,
  'lambda2' : 3, 'lambda1' : 1, 'max_it' : 500,
  'L0' : 0.1, 'tol' : 1e-2, 'intercept' : False,
  'pos' : False, 'loss' : 'square'}
  param['regul'] = "group-lasso-linf"
  param2=param.copy()
  param['size_group'] = 64
  param2['groups'] = groups_modified
  (W_groupLassoLinf_reg, optim_info) = spams.fistaFlat(Y_normalized,X_normalized,W_initial,True,**param)
  ##### Debiasing step #####
  ba = np.argwhere(W_groupLassoLinf_reg != 0) #Finding where the coefficients are not zero
  X_debiased = X[:, ba[:,0]]
  W_groupLassoLinf_reg_debiased = np.linalg.lstsq(X_debiased,Y) #Re-estimate the chosen coefficients using least squares
  W_group_lassoLinf_reg_debiased_2 = np.zeros((4096))
  W_group_lassoLinf_reg_debiased_2[ba] = W_groupLassoLinf_reg_debiased[0]
  groupLassoLinf_mse = mean_squared_error(W_actual, W_group_lassoLinf_reg_debiased_2)
  plt.figure(3+fig_start)
  axes = plt.gca()
  plt.plot(W_group_lassoLinf_reg_debiased_2)
  plt.title('Block-Linf (debiased 1, regularization param(L2 = 3, L1=1), MSE = {:.4f})'.format(groupLassoLinf_mse))
  plt.savefig("W_groupLassoLinf_reg_{}.png".format(signal_type), dpi=300)
  plt.show()
Example #7
0
def fit_group_lasso(
    X,
    knockoffs,
    y,
    groups,
    use_pyglm=True,
    y_dist=None,
    group_lasso=True,
    **kwargs,
):
    """ Fits a group lasso model.
	:param X: n x p design matrix
	:param knockoffs: n x p knockoff matrix
	:param groups: p length numpy array of groups
	:param use_pyglm: If true, use the pyglmnet grouplasso
	Else use the regular one
	:param y_dist: Either "gaussian" or "binomial" (for logistic regression)
	:param group_lasso: If False, do not use group regularization.
	:param kwargs: kwargs for group-lasso GroupLasso class.
	In particular includes reg_vals, a list of regularizations
	(lambda values) which defaults to [(0.05, 0.05)]. In each
	tuple of the list, the first value is the group regularization,
	the second value is the individual regularization.
	"""

    warnings.filterwarnings("ignore")

    # Parse some kwargs/defaults
    if "max_iter" in kwargs:
        max_iter = kwargs.pop("max_iter")
    else:
        max_iter = 100
    if "tol" in kwargs:
        tol = kwargs.pop("tol")
    else:
        tol = 1e-2
    if "cv" in kwargs:
        cv = kwargs.pop("cv")
    else:
        cv = 5
    if "learning_rate" in kwargs:
        learning_rate = kwargs.pop("learning_rate")
    else:
        learning_rate = 2
    if y_dist is None:
        y_dist = parse_y_dist(y)

    # Bind data
    n = X.shape[0]
    p = X.shape[1]
    features = np.concatenate([X, knockoffs], axis=1)

    # By default, all variables are their own group
    if groups is None:
        groups = np.arange(1, p + 1, 1)
    m = np.unique(groups).shape[0]

    # If m == p, meaning each variable is their own group,
    # just fit a regular lasso
    if m == p or not group_lasso:
        return fit_lasso(X, knockoffs, y, y_dist, **kwargs)

    # Make sure variables and their knockoffs are in the same group
    # This is necessary for antisymmetry
    doubled_groups = np.concatenate([groups, groups], axis=0)

    # Randomize coordinates to make sure everything is symmetric
    inds, rev_inds = random_permutation_inds(2 * p)
    features = features[:, inds]
    doubled_groups = doubled_groups[inds]

    # Standardize - important for pyglmnet performance,
    # highly detrimental for group_lasso performance
    if use_pyglm:
        features = (features - features.mean()) / features.std()
        if y_dist == "gaussian":
            y = (y - y.mean()) / y.std()

    # Get regularizations
    if "reg_vals" in kwargs:
        reg_vals = kwargs.pop("reg_vals")
    else:
        reg_vals = [(x, x) for x in DEFAULT_REG_VALS]

    # Fit pyglm model using warm starts
    if use_pyglm:

        l1_regs = [x[0] for x in reg_vals]

        gl = GLMCV(
            distr=y_dist,
            tol=tol,
            group=doubled_groups,
            alpha=1.0,
            learning_rate=learning_rate,
            max_iter=max_iter,
            reg_lambda=l1_regs,
            cv=cv,
            solver="cdfast",
        )
        gl.fit(features, y)

        # Pull score, rename
        best_score = -1 * calc_mse(gl, features, y)
        best_gl = gl

    # Fit model
    if not use_pyglm:
        best_gl = None
        best_score = -1 * np.inf
        for group_reg, l1_reg in reg_vals:

            # Fit logistic/gaussian group lasso
            if not use_pyglm:
                if y_dist.lower() == "gaussian":
                    gl = GroupLasso(
                        groups=doubled_groups,
                        tol=tol,
                        group_reg=group_reg,
                        l1_reg=l1_reg,
                        **kwargs,
                    )
                elif y_dist.lower() == "binomial":
                    gl = LogisticGroupLasso(
                        groups=doubled_groups,
                        tol=tol,
                        group_reg=group_reg,
                        l1_reg=l1_reg,
                        **kwargs,
                    )
                else:
                    raise ValueError(
                        f"y_dist must be one of gaussian, binomial, not {y_dist}"
                    )

                gl.fit(features, y.reshape(n, 1))
                score = -1 * calc_mse(gl, features, y.reshape(n, 1))

            # Score, possibly select
            if score > best_score:
                best_score = score
                best_gl = gl

    warnings.resetwarnings()

    return best_gl, inds, rev_inds
Example #8
0
# Use noisy y as true because that is what we would have access
# to in a real-life setting.
R2_best = r2_score(y, y_true)

###############################################################################
# Generate pipeline and train it
# ------------------------------
pipe = Pipeline(
    memory=None,
    steps=[
        (
            "variable_selection",
            GroupLasso(
                groups=groups,
                group_reg=20,
                l1_reg=0,
                scale_reg="inverse_group_size",
                subsampling_scheme=1,
                supress_warning=True,
            ),
        ),
        ("regressor", Ridge(alpha=0.1)),
    ],
)
pipe.fit(X, y)

###############################################################################
# Extract results and compute performance metrics
# -----------------------------------------------

# Extract from pipeline
yhat = pipe.predict(X)
    X_train, X_test, y_train, y_test = train_test_split(X,
                                                        y,
                                                        test_size=0.25,
                                                        random_state=10)

    sgl = gpr.SGL(groups=groups,
                  l1_ratio=0.5,
                  alpha=1.0,
                  max_iter=1000,
                  tol=1e-3)

    gl = GroupLasso(
        groups=gl_groups,
        group_reg=0.5,
        l1_reg=0.5,
        frobenius_lipschitz=True,
        scale_reg="group_size",
        n_iter=1000,
        tol=1e-3,
        supress_warning=True,
    )

    gpr_time = timeit("sgl.fit(X_train, y_train)", globals=globals(), number=3)
    gl_time = timeit("gl.fit(X_train, y_train)", globals=globals(), number=3)

    speedup.append(gpr_time / gl_time)

fig, ax = plt.subplots(1, 1, figsize=(8, 5))

_ = ax.plot(np.array(n_features) * 50, 1 / np.array(speedup))
_ = ax.set_xlabel(r"Number of features", fontsize=16)
_ = ax.set_ylabel(r"$t$(group-lasso) / $t$(groupyr)", fontsize=16)
Example #10
0
plt.plot(y, y_true, ".")
plt.xlabel("Noisy targets")
plt.ylabel("Noise-free targets")
# Use noisy y as true because that is what we would have access
# to in a real-life setting.
R2_best = r2_score(y, y_true)

###############################################################################
# Generate estimator and train it
# -------------------------------
gl = GroupLasso(
    groups=groups,
    group_reg=5,
    l1_reg=0,
    frobenius_lipschitz=True,
    scale_reg="inverse_group_size",
    subsampling_scheme=1,
    supress_warning=True,
    n_iter=1000,
    tol=1e-3,
)
gl.fit(X, y)

###############################################################################
# Extract results and compute performance metrics
# -----------------------------------------------

# Extract info from estimator
yhat = gl.predict(X)
sparsity_mask = gl.sparsity_mask_
w_hat = gl.coef_
Example #11
0
    print("Generating coefficients")
    w1 = generate_group_lasso_coefficients(group_sizes)
    w2 = generate_group_lasso_coefficients(group_sizes)
    w = np.hstack((w1, w2))
    w += np.random.randn(*w.shape) * coeff_noise_level

    print("Generating targets")
    y = X @ w
    y += np.random.randn(*y.shape) * noise_level * y
    y += intercept

    gl = GroupLasso(
        groups=groups,
        n_iter=10,
        tol=1e-8,
        reg=0.08,
        frobenius_lipschitz=True,
        subsampling_scheme=1,
        fit_intercept=True,
    )
    print("Starting fit")
    gl.fit(X, y)

    for i in range(w.shape[1]):
        plt.figure()
        plt.plot(w[:, i], ".", label="True weights")
        plt.plot(gl.coef_[:, i], ".", label="Estimated weights")
        plt.legend()

    plt.figure()
    plt.plot(gl.losses_)
Example #12
0
SNR = np.linalg.norm(np.dot(X, beta)) / np.linalg.norm(e)
print("SNR value: {}".format(SNR))

beta[0:nZeros] = 0  # First nZero features have no correlation to response
beta_bool = np.ndarray(shape=(p, 1), dtype=bool)
beta_bool[0:nZeros] = False
beta_bool[nZeros:] = True

Y = np.dot(X, beta) + e
Y = Y.reshape(-1, 1)

# l1_reg is the regularisation coeff. for coeffcient sparsiy pen.
# l2_reg is the regularisation coefficient(s) for the group sparsity penalty

gl = GroupLasso(groups=F_groups,
                l1_reg=0,
                group_reg=0.35,
                supress_warning=True)

gl.fit(X, Y)
yhat = gl.predict(X)
beta_hat = gl.coef_

conf_m = confusion_matrix(beta_bool, gl.sparsity_mask_)

print("Number of variables: {}".format(p))
print("Number of zero coefficients: {}".format(nZeros))
print("Number of choosen variables: {}".format(gl.sparsity_mask_.sum()))
print(conf_m)

group_bool = np.ndarray(shape=(3, nGroups), dtype=int)
group_bool[0, :] = [0, 1, 2, 3, 4]
Example #13
0
 def __init__(self,r,groups_ids):
     self.lasso = GroupLasso(    groups=groups_ids,    group_reg=r,     l1_reg=r,    n_iter = 1000,
                                    scale_reg="None",       supress_warning=True,    tol=1e-04,
 )
R2_best = r2_score(y, y_true)


###############################################################################
# Generate pipeline and train it
# ------------------------------
pipe = pipe = Pipeline(
    memory=None,
    steps=[
        (
            "variable_selection",
            GroupLasso(
                groups=groups,
                group_reg=0.1,
                l1_reg=0,
                scale_reg=None,
                supress_warning=True,
                n_iter=100000,
                frobenius_lipschitz=False,
            ),
        ),
        ("regressor", Ridge(alpha=1)),
    ],
)
pipe.fit(X, y)


###############################################################################
# Extract results and compute performance metrics
# -----------------------------------------------
Example #15
0
y_true = X @ w + intercept
y = y_true + np.random.randn(*y_true.shape) * noise_std


###############################################################################
# Generate estimator and train it
# -------------------------------
num_regs = 10
regularisations = np.logspace(-0.5, 1.5, num_regs)
weights = np.empty((num_regs, w.shape[0],))
gl = GroupLasso(
    groups=groups,
    group_reg=5,
    l1_reg=0,
    frobenius_lipschitz=True,
    scale_reg="inverse_group_size",
    subsampling_scheme=1,
    supress_warning=True,
    n_iter=1000,
    tol=1e-3,
    warm_start=True,  # Warm start to start each subsequent fit with previous weights
)

for i, group_reg in enumerate(regularisations[::-1]):
    gl.group_reg = group_reg
    gl.fit(X, y)
    weights[-(i + 1)] = gl.sparsity_mask_.squeeze()


###############################################################################
# Visualise chosen covariate groups
# ---------------------------------