Skip to content

Commit

Permalink
feat: Added alpha parameter to RidgeRegression (#231)
Browse files Browse the repository at this point in the history
Closes #164 .

### Summary of Changes

Added alpha parameter to `RidgeRegression` for regularization.

---------

Co-authored-by: sibre28 <86068340+sibre28@users.noreply.github.com>
Co-authored-by: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com>
Co-authored-by: Lars Reimann <mail@larsreimann.com>
  • Loading branch information
4 people committed Apr 28, 2023
1 parent 9ffaf55 commit 1ddc948
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 8 deletions.
6 changes: 2 additions & 4 deletions src/safeds/ml/classical/regression/_elastic_net_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ class ElasticNetRegression(Regressor):
----------
alpha : float
Controls the regularization of the model. The higher the value, the more regularized it becomes.
lasso_ratio: float
Number between 0 and 1 that controls the ratio between Lasso- and Ridge regularization.
lasso_ratio=0 is essentially RidgeRegression
lasso_ratio=1 is essentially LassoRegression
Number between 0 and 1 that controls the ratio between Lasso and Ridge regularization. If 0, only Ridge
regularization is used. If 1, only Lasso regularization is used.
Raises
------
Expand Down
33 changes: 29 additions & 4 deletions src/safeds/ml/classical/regression/_ridge_regression.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import warnings
from typing import TYPE_CHECKING

from sklearn.linear_model import Ridge as sk_Ridge
Expand All @@ -13,12 +14,36 @@


class RidgeRegression(Regressor):
"""Ridge regression."""
"""
Ridge regression.
def __init__(self) -> None:
Parameters
----------
alpha : float
Controls the regularization of the model. The higher the value, the more regularized it becomes.
Raises
------
ValueError
If alpha is negative.
"""

def __init__(self, alpha: float = 1.0) -> None:
self._wrapped_regressor: sk_Ridge | None = None
self._feature_names: list[str] | None = None
self._target_name: str | None = None
self._alpha = alpha
if self._alpha < 0:
raise ValueError("alpha must be non-negative")
if self._alpha == 0.0:
warnings.warn(
(
"Setting alpha to zero makes this model equivalent to LinearRegression. You should use "
"LinearRegression instead for better numerical stability."
),
UserWarning,
stacklevel=2,
)

def fit(self, training_set: TaggedTable) -> RidgeRegression:
"""
Expand All @@ -41,10 +66,10 @@ def fit(self, training_set: TaggedTable) -> RidgeRegression:
LearningError
If the training data contains invalid values or if the training failed.
"""
wrapped_regressor = sk_Ridge()
wrapped_regressor = sk_Ridge(alpha=self._alpha)
fit(wrapped_regressor, training_set)

result = RidgeRegression()
result = RidgeRegression(alpha=self._alpha)
result._wrapped_regressor = wrapped_regressor
result._feature_names = training_set.features.column_names
result._target_name = training_set.target.name
Expand Down
32 changes: 32 additions & 0 deletions tests/safeds/ml/classical/regression/test_ridge_regression.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest
from safeds.data.tabular.containers import Table
from safeds.ml.classical.regression import RidgeRegression


def test_should_raise_if_alpha_is_negative() -> None:
with pytest.raises(ValueError, match="alpha must be non-negative"):
RidgeRegression(alpha=-1.0)


def test_should_warn_if_alpha_is_zero() -> None:
with pytest.warns(
UserWarning,
match=(
"Setting alpha to zero makes this model equivalent to LinearRegression. You "
"should use LinearRegression instead for better numerical stability."
),
):
RidgeRegression(alpha=0.0)


def test_should_pass_alpha_to_fitted_regressor() -> None:
regressor = RidgeRegression(alpha=1.0)
fitted_regressor = regressor.fit(Table.from_dict({"A": [1, 2, 4], "B": [1, 2, 3]}).tag_columns("B"))
assert regressor._alpha == fitted_regressor._alpha


def test_should_pass_alpha_to_sklearn() -> None:
regressor = RidgeRegression(alpha=1.0)
fitted_regressor = regressor.fit(Table.from_dict({"A": [1, 2, 4], "B": [1, 2, 3]}).tag_columns("B"))
assert fitted_regressor._wrapped_regressor is not None
assert fitted_regressor._wrapped_regressor.alpha == fitted_regressor._alpha

0 comments on commit 1ddc948

Please sign in to comment.