ELASTIC_NET

Elastic net regression combines L1 and L2 regularization, balancing sparse feature selection against coefficient stability. It is a useful compromise when pure lasso is unstable on correlated predictors.

The model minimizes the following objective function over the samples and coefficients:

\frac{1}{2 n_{\text{samples}}} ||y - Xw||^2_2 + \alpha \rho ||w||_1 + \frac{\alpha(1-\rho)}{2} ||w||^2_2

where \alpha controls the overall regularization strength and \rho is the L1 mixing ratio.

This wrapper accepts tabular feature data with rows as samples and columns as features, plus a numeric target supplied as a single row or single column. It returns the training R^2 together with fitted predictions, residuals, and learned coefficient arrays.

Excel Usage

=ELASTIC_NET(data, target, alpha, enet_ratio, fit_intercept, max_iter, tol, coord_selection, random_state)
  • data (list[list], required): 2D array of numeric feature data with rows as samples and columns as features.
  • target (list[list], required): Numeric target values as a single row, single column, or scalar when only one sample is present.
  • alpha (float, optional, default: 1): Overall regularization strength applied to the regression model.
  • enet_ratio (float, optional, default: 0.5): Elastic net mixing ratio corresponding to sklearn’s l1_ratio parameter.
  • fit_intercept (bool, optional, default: true): Whether to include an intercept term in the linear model.
  • max_iter (int, optional, default: 1000): Maximum number of coordinate-descent iterations.
  • tol (float, optional, default: 0.0001): Optimization tolerance used for convergence checks.
  • coord_selection (str, optional, default: “cyclic”): Coordinate update order used by the optimizer.
  • random_state (int, optional, default: null): Integer seed used when random coordinate selection is enabled. Leave blank for the estimator default.

Returns (dict): Excel data type containing training R^2, predictions, residuals, and fitted coefficient arrays.

Example 1: Fit elastic net regression on a two-feature linear trend

Inputs:

data target alpha enet_ratio fit_intercept max_iter tol coord_selection random_state
0 0 1 0.01 0.5 true 5000 0.0001 cyclic 0
1 0 3
0 1 4
1 1 6
2 1 8
2 2 11

Excel formula:

=ELASTIC_NET({0,0;1,0;0,1;1,1;2,1;2,2}, {1;3;4;6;8;11}, 0.01, 0.5, TRUE, 5000, 0.0001, "cyclic", 0)

Expected output:

{"type":"Double","basicValue":0.999924,"properties":{"training_r2":{"type":"Double","basicValue":0.999924},"mean_squared_error":{"type":"Double","basicValue":0.000832226},"sample_count":{"type":"Double","basicValue":6},"feature_count":{"type":"Double","basicValue":2},"predictions":{"type":"Array","elements":[[{"type":"Double","basicValue":1.03586}],[{"type":"Double","basicValue":3.03362}],[{"type":"Double","basicValue":3.99552}],[{"type":"Double","basicValue":5.99328}],[{"type":"Double","basicValue":7.99103}],[{"type":"Double","basicValue":10.9507}]]},"residuals":{"type":"Array","elements":[[{"type":"Double","basicValue":-0.0358611}],[{"type":"Double","basicValue":-0.0336196}],[{"type":"Double","basicValue":0.00448235}],[{"type":"Double","basicValue":0.00672392}],[{"type":"Double","basicValue":0.00896548}],[{"type":"Double","basicValue":0.049309}]]},"coefficients":{"type":"Array","elements":[[{"type":"Double","basicValue":1.99776},{"type":"Double","basicValue":2.95966}]]},"intercepts":{"type":"Array","elements":[[{"type":"Double","basicValue":1.03586}]]},"dual_gap":{"type":"Double","basicValue":0.0000930618},"iteration_count":{"type":"Double","basicValue":10}}}

Example 2: Flatten a single-row numeric target range for elastic net regression

Inputs:

data target alpha enet_ratio fit_intercept max_iter tol coord_selection random_state
0 1 3 5 7 9 11 0.01 0.5 true 5000 0.0001 cyclic 0
1
2
3
4
5

Excel formula:

=ELASTIC_NET({0;1;2;3;4;5}, {1,3,5,7,9,11}, 0.01, 0.5, TRUE, 5000, 0.0001, "cyclic", 0)

Expected output:

{"type":"Double","basicValue":0.999993,"properties":{"training_r2":{"type":"Double","basicValue":0.999993},"mean_squared_error":{"type":"Double","basicValue":0.000076879},"sample_count":{"type":"Double","basicValue":6},"feature_count":{"type":"Double","basicValue":1},"predictions":{"type":"Array","elements":[[{"type":"Double","basicValue":1.01284}],[{"type":"Double","basicValue":3.0077}],[{"type":"Double","basicValue":5.00257}],[{"type":"Double","basicValue":6.99743}],[{"type":"Double","basicValue":8.9923}],[{"type":"Double","basicValue":10.9872}]]},"residuals":{"type":"Array","elements":[[{"type":"Double","basicValue":-0.0128351}],[{"type":"Double","basicValue":-0.00770108}],[{"type":"Double","basicValue":-0.00256703}],[{"type":"Double","basicValue":0.00256703}],[{"type":"Double","basicValue":0.00770108}],[{"type":"Double","basicValue":0.0128351}]]},"coefficients":{"type":"Array","elements":[[{"type":"Double","basicValue":1.99487}]]},"intercepts":{"type":"Array","elements":[[{"type":"Double","basicValue":1.01284}]]},"dual_gap":{"type":"Double","basicValue":-1.91542e-18},"iteration_count":{"type":"Double","basicValue":2}}}

Example 3: Fit a no-intercept elastic net model on a two-feature plane

Inputs:

data target alpha enet_ratio fit_intercept max_iter tol coord_selection random_state
1 0 2 0.01 0.7 false 5000 0.0001 cyclic 0
0 1 3
1 1 5
2 1 7
1 2 8
2 2 10

Excel formula:

=ELASTIC_NET({1,0;0,1;1,1;2,1;1,2;2,2}, {2;3;5;7;8;10}, 0.01, 0.7, FALSE, 5000, 0.0001, "cyclic", 0)

Expected output:

{"type":"Double","basicValue":0.999982,"properties":{"training_r2":{"type":"Double","basicValue":0.999982},"mean_squared_error":{"type":"Double","basicValue":0.000139382},"sample_count":{"type":"Double","basicValue":6},"feature_count":{"type":"Double","basicValue":2},"predictions":{"type":"Array","elements":[[{"type":"Double","basicValue":2.00061}],[{"type":"Double","basicValue":2.99079}],[{"type":"Double","basicValue":4.9914}],[{"type":"Double","basicValue":6.99201}],[{"type":"Double","basicValue":7.98219}],[{"type":"Double","basicValue":9.9828}]]},"residuals":{"type":"Array","elements":[[{"type":"Double","basicValue":-0.000612489}],[{"type":"Double","basicValue":0.00921332}],[{"type":"Double","basicValue":0.00860083}],[{"type":"Double","basicValue":0.00798835}],[{"type":"Double","basicValue":0.0178142}],[{"type":"Double","basicValue":0.0172017}]]},"coefficients":{"type":"Array","elements":[[{"type":"Double","basicValue":2.00061},{"type":"Double","basicValue":2.99079}]]},"intercepts":{"type":"Array","elements":[[{"type":"Double","basicValue":0}]]},"dual_gap":{"type":"Double","basicValue":0.000609683},"iteration_count":{"type":"Double","basicValue":22}}}

Example 4: Use random coordinate updates on correlated features with elastic net

Inputs:

data target alpha enet_ratio fit_intercept max_iter tol coord_selection random_state
0 0.1 1 0.05 0.4 true 5000 0.0001 random 0
1 0.9 3.1
2 2.1 5.8
3 2.9 7.9
4 4.1 10.2
5 4.9 12.1

Excel formula:

=ELASTIC_NET({0,0.1;1,0.9;2,2.1;3,2.9;4,4.1;5,4.9}, {1;3.1;5.8;7.9;10.2;12.1}, 0.05, 0.4, TRUE, 5000, 0.0001, "random", 0)

Expected output:

{"type":"Double","basicValue":0.998847,"properties":{"training_r2":{"type":"Double","basicValue":0.998847},"mean_squared_error":{"type":"Double","basicValue":0.0171298},"sample_count":{"type":"Double","basicValue":6},"feature_count":{"type":"Double","basicValue":2},"predictions":{"type":"Array","elements":[[{"type":"Double","basicValue":1.15865}],[{"type":"Double","basicValue":3.18584}],[{"type":"Double","basicValue":5.66974}],[{"type":"Double","basicValue":7.69693}],[{"type":"Double","basicValue":10.1808}],[{"type":"Double","basicValue":12.208}]]},"residuals":{"type":"Array","elements":[[{"type":"Double","basicValue":-0.158646}],[{"type":"Double","basicValue":-0.0858364}],[{"type":"Double","basicValue":0.130262}],[{"type":"Double","basicValue":0.203072}],[{"type":"Double","basicValue":0.0191697}],[{"type":"Double","basicValue":-0.108021}]]},"coefficients":{"type":"Array","elements":[[{"type":"Double","basicValue":1.11377},{"type":"Double","basicValue":1.14178}]]},"intercepts":{"type":"Array","elements":[[{"type":"Double","basicValue":1.04447}]]},"dual_gap":{"type":"Double","basicValue":0.00131021},"iteration_count":{"type":"Double","basicValue":353}}}

Python Code

import numpy as np
from sklearn.linear_model import ElasticNet as SklearnElasticNet

def elastic_net(data, target, alpha=1, enet_ratio=0.5, fit_intercept=True, max_iter=1000, tol=0.0001, coord_selection='cyclic', random_state=None):
    """
    Fit an elastic net regression model and return training predictions.

    See: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.ElasticNet.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        data (list[list]): 2D array of numeric feature data with rows as samples and columns as features.
        target (list[list]): Numeric target values as a single row, single column, or scalar when only one sample is present.
        alpha (float, optional): Overall regularization strength applied to the regression model. Default is 1.
        enet_ratio (float, optional): Elastic net mixing ratio corresponding to sklearn's l1_ratio parameter. Default is 0.5.
        fit_intercept (bool, optional): Whether to include an intercept term in the linear model. Default is True.
        max_iter (int, optional): Maximum number of coordinate-descent iterations. Default is 1000.
        tol (float, optional): Optimization tolerance used for convergence checks. Default is 0.0001.
        coord_selection (str, optional): Coordinate update order used by the optimizer. Valid options: Cyclic, Random. Default is 'cyclic'.
        random_state (int, optional): Integer seed used when random coordinate selection is enabled. Leave blank for the estimator default. Default is None.

    Returns:
        dict: Excel data type containing training $R^2$, predictions, residuals, and fitted coefficient arrays.
    """
    def py(value):
        return value.item() if isinstance(value, np.generic) else value

    def cell(value):
        value = py(value)
        if isinstance(value, bool):
            return {"type": "Boolean", "basicValue": bool(value)}
        if isinstance(value, (int, float)) and not isinstance(value, bool):
            return {"type": "Double", "basicValue": float(value)}
        return {"type": "String", "basicValue": str(value)}

    def col(values):
        return [[cell(value)] for value in values]

    def mat(values):
        return [[cell(value) for value in row] for row in values]

    def parse_data(value):
        value = [[value]] if not isinstance(value, list) else value
        if not isinstance(value, list) or not value or not all(isinstance(row, list) and row for row in value):
            return None, "Error: data must be a non-empty 2D list"
        if len({len(row) for row in value}) != 1:
            return None, "Error: data must be a rectangular 2D list"
        data_np = np.array(value, dtype=float)
        if data_np.ndim != 2 or data_np.size == 0:
            return None, "Error: data must be a non-empty 2D list"
        if not np.isfinite(data_np).all():
            return None, "Error: data must contain only finite numeric values"
        return data_np, None

    def parse_target(value, sample_count):
        if not isinstance(value, list):
            labels = [value]
        elif not value:
            return None, "Error: target must be non-empty"
        elif all(not isinstance(item, list) for item in value):
            labels = value
        elif len(value) == 1:
            labels = value[0]
        elif all(isinstance(row, list) and len(row) == 1 for row in value):
            labels = [row[0] for row in value]
        else:
            return None, "Error: target must be a single row or column"

        if len(labels) != sample_count:
            return None, "Error: target length must match sample count"

        parsed = []
        for item in labels:
            item = py(item)
            if isinstance(item, bool) or not isinstance(item, (int, float)):
                return None, "Error: target values must be finite numeric scalars"
            if not np.isfinite(float(item)):
                return None, "Error: target values must be finite numeric scalars"
            parsed.append(float(item))
        return np.array(parsed, dtype=float), None

    def flat_float_list(values):
        return [float(py(item)) for item in np.asarray(values).reshape(-1).tolist()]

    try:
        data_np, error = parse_data(data)
        if error:
            return error

        target_np, error = parse_target(target, data_np.shape[0])
        if error:
            return error

        selection_value = str(coord_selection).strip().lower()
        if selection_value not in {"cyclic", "random"}:
            return "Error: coord_selection must be 'cyclic' or 'random'"
        if float(alpha) < 0:
            return "Error: alpha must be non-negative"
        if float(enet_ratio) < 0 or float(enet_ratio) > 1:
            return "Error: enet_ratio must be between 0 and 1"
        if int(max_iter) < 1:
            return "Error: max_iter must be at least 1"
        if float(tol) <= 0:
            return "Error: tol must be greater than 0"

        fitted = SklearnElasticNet(
            alpha=float(alpha),
            l1_ratio=float(enet_ratio),
            fit_intercept=bool(fit_intercept),
            max_iter=int(max_iter),
            tol=float(tol),
            selection=selection_value,
            random_state=None if random_state in (None, "") else int(random_state)
        ).fit(data_np, target_np)

        prediction_array = np.asarray(fitted.predict(data_np), dtype=float)
        residual_array = target_np - prediction_array
        predictions = flat_float_list(prediction_array)
        residuals = flat_float_list(residual_array)
        training_r2 = float(fitted.score(data_np, target_np))
        mse = float(np.mean(np.square(residual_array)))
        dual_gap = float(np.atleast_1d(fitted.dual_gap_).reshape(-1)[0])
        iteration_count = float(np.atleast_1d(fitted.n_iter_).reshape(-1)[0])

        return {
            "type": "Double",
            "basicValue": training_r2,
            "properties": {
                "training_r2": {"type": "Double", "basicValue": training_r2},
                "mean_squared_error": {"type": "Double", "basicValue": mse},
                "sample_count": {"type": "Double", "basicValue": float(data_np.shape[0])},
                "feature_count": {"type": "Double", "basicValue": float(data_np.shape[1])},
                "predictions": {"type": "Array", "elements": col(predictions)},
                "residuals": {"type": "Array", "elements": col(residuals)},
                "coefficients": {"type": "Array", "elements": mat(np.atleast_2d(fitted.coef_).tolist())},
                "intercepts": {"type": "Array", "elements": col(np.atleast_1d(fitted.intercept_).tolist())},
                "dual_gap": {"type": "Double", "basicValue": dual_gap},
                "iteration_count": {"type": "Double", "basicValue": iteration_count}
            }
        }
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D array of numeric feature data with rows as samples and columns as features.
Numeric target values as a single row, single column, or scalar when only one sample is present.
Overall regularization strength applied to the regression model.
Elastic net mixing ratio corresponding to sklearn's l1_ratio parameter.
Whether to include an intercept term in the linear model.
Maximum number of coordinate-descent iterations.
Optimization tolerance used for convergence checks.
Coordinate update order used by the optimizer.
Integer seed used when random coordinate selection is enabled. Leave blank for the estimator default.