Skip to content

Commit

Permalink
Merge pull request #388 from dynamicslab/remove-fit-intercept
Browse files Browse the repository at this point in the history
CLN: Remove fit_intercept in optimizers
  • Loading branch information
Jacob-Stevens-Haas authored Aug 14, 2023
2 parents d86e375 + b0a4693 commit a5dfc4a
Show file tree
Hide file tree
Showing 13 changed files with 22 additions and 93 deletions.
19 changes: 4 additions & 15 deletions pysindy/optimizers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,9 @@ class BaseOptimizer(LinearRegression, ComplexityMixin):
Parameters
----------
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
normalize_columns : boolean, optional (default False)
Normalize the columns of x (the SINDy library terms) before regression
by dividing by the L2-norm. Note that the 'normalize' option in sklearn
is deprecated in sklearn versions >= 1.0 and will be removed.
by dividing by the L2-norm.
copy_X : boolean, optional (default True)
If True, X will be copied; else, it may be overwritten.
Expand Down Expand Up @@ -97,12 +92,11 @@ def __init__(
self,
max_iter=20,
normalize_columns=False,
fit_intercept=False,
initial_guess=None,
copy_X=True,
unbias: bool = True,
):
super().__init__(fit_intercept=fit_intercept, copy_X=copy_X)
super().__init__(fit_intercept=False, copy_X=copy_X)

if max_iter <= 0:
raise ValueError("max_iter must be positive")
Expand Down Expand Up @@ -157,7 +151,7 @@ def fit(self, x_, y, sample_weight=None, **reduce_kws):
x, y, X_offset, y_offset, X_scale = _preprocess_data(
x_,
y,
fit_intercept=self.fit_intercept,
fit_intercept=False,
copy=self.copy_X,
sample_weight=sample_weight,
)
Expand Down Expand Up @@ -212,14 +206,10 @@ def fit(self, x_, y, sample_weight=None, **reduce_kws):

def _unbias(self, x, y):
coef = np.zeros((y.shape[1], x.shape[1]))
if hasattr(self, "fit_intercept"):
fit_intercept = self.fit_intercept
else:
fit_intercept = False
for i in range(self.ind_.shape[0]):
if np.any(self.ind_[i]):
coef[i, self.ind_[i]] = (
LinearRegression(fit_intercept=fit_intercept)
LinearRegression(fit_intercept=False)
.fit(x[:, self.ind_[i]], y[:, i])
.coef_
)
Expand Down Expand Up @@ -303,7 +293,6 @@ def __init__(

super().__init__(
max_iter=opt.max_iter,
fit_intercept=opt.fit_intercept,
initial_guess=opt.initial_guess,
copy_X=opt.copy_X,
)
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/constrained_sr3.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ class ConstrainedSR3(SR3):
max_iter : int, optional (default 30)
Maximum iterations of the optimization algorithm.
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
constraint_lhs : numpy ndarray, optional (default None)
Shape should be (n_constraints, n_features * n_targets),
The left hand side matrix C of Cw <= d.
Expand Down Expand Up @@ -157,7 +153,6 @@ def __init__(
constraint_rhs=None,
constraint_order="target",
normalize_columns=False,
fit_intercept=False,
copy_X=True,
initial_guess=None,
thresholds=None,
Expand All @@ -178,7 +173,6 @@ def __init__(
trimming_step_size=trimming_step_size,
max_iter=max_iter,
initial_guess=initial_guess,
fit_intercept=fit_intercept,
copy_X=copy_X,
normalize_columns=normalize_columns,
verbose=verbose,
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/frols.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ class FROLS(BaseOptimizer):
Parameters
----------
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
normalize_columns : boolean, optional (default False)
Normalize the columns of x (the SINDy library terms) before regression
by dividing by the L2-norm. Note that the 'normalize' option in sklearn
Expand Down Expand Up @@ -84,7 +80,6 @@ class FROLS(BaseOptimizer):
def __init__(
self,
normalize_columns=False,
fit_intercept=False,
copy_X=True,
kappa=None,
max_iter=10,
Expand All @@ -94,7 +89,6 @@ def __init__(
unbias=True,
):
super().__init__(
fit_intercept=fit_intercept,
copy_X=copy_X,
max_iter=max_iter,
normalize_columns=normalize_columns,
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/miosr.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ class MIOSR(BaseOptimizer):
optimality (either per dimension or jointly depending on the
above sparsity settings).
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
constraint_lhs : numpy ndarray, optional (default None)
Shape should be (n_constraints, n_features * n_targets),
The left hand side matrix C of Cw <= d.
Expand Down Expand Up @@ -115,7 +111,6 @@ def __init__(
group_sparsity=None,
alpha=0.01,
regression_timeout=10,
fit_intercept=False,
constraint_lhs=None,
constraint_rhs=None,
constraint_order="target",
Expand All @@ -127,7 +122,6 @@ def __init__(
):
super().__init__(
normalize_columns=normalize_columns,
fit_intercept=fit_intercept,
copy_X=copy_X,
unbias=unbias,
)
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/sindy_pi.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ class SINDyPI(SR3):
max_iter : int, optional (default 10000)
Maximum iterations of the optimization algorithm.
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
normalize_columns : boolean, optional (default False)
This parameter normalizes the columns of Theta before the
optimization is done. This tends to standardize the columns
Expand Down Expand Up @@ -97,7 +93,6 @@ def __init__(
tol=1e-5,
thresholder="l1",
max_iter=10000,
fit_intercept=False,
copy_X=True,
thresholds=None,
model_subset=None,
Expand All @@ -111,7 +106,6 @@ def __init__(
tol=tol,
thresholder=thresholder,
max_iter=max_iter,
fit_intercept=fit_intercept,
copy_X=copy_X,
normalize_columns=normalize_columns,
unbias=unbias,
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/sr3.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@ class SR3(BaseOptimizer):
Initial guess for coefficients ``coef_``.
If None, least-squares is used to obtain an initial guess.
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
normalize_columns : boolean, optional (default False)
Normalize the columns of x (the SINDy library terms) before regression
by dividing by the L2-norm. Note that the 'normalize' option in sklearn
Expand Down Expand Up @@ -151,7 +147,6 @@ def __init__(
trimming_fraction=0.0,
trimming_step_size=1.0,
max_iter=30,
fit_intercept=False,
copy_X=True,
initial_guess=None,
normalize_columns=False,
Expand All @@ -161,7 +156,6 @@ def __init__(
super(SR3, self).__init__(
max_iter=max_iter,
initial_guess=initial_guess,
fit_intercept=fit_intercept,
copy_X=copy_X,
normalize_columns=normalize_columns,
unbias=unbias,
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/ssr.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ class SSR(BaseOptimizer):
max_iter : int, optional (default 20)
Maximum iterations of the optimization algorithm.
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
normalize_columns : boolean, optional (default False)
Normalize the columns of x (the SINDy library terms) before regression
by dividing by the L2-norm. Note that the 'normalize' option in sklearn
Expand Down Expand Up @@ -94,7 +90,6 @@ def __init__(
max_iter=20,
ridge_kw=None,
normalize_columns=False,
fit_intercept=False,
copy_X=True,
criteria="coefficient_value",
kappa=None,
Expand All @@ -103,7 +98,6 @@ def __init__(
):
super(SSR, self).__init__(
max_iter=max_iter,
fit_intercept=fit_intercept,
copy_X=copy_X,
normalize_columns=normalize_columns,
unbias=unbias,
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/stable_linear_sr3.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ class StableLinearSR3(ConstrainedSR3):
max_iter : int, optional (default 30)
Maximum iterations of the optimization algorithm.
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
constraint_lhs : numpy ndarray, optional (default None)
Shape should be (n_constraints, n_features * n_targets),
The left hand side matrix C of Cw <= d.
Expand Down Expand Up @@ -155,7 +151,6 @@ def __init__(
constraint_rhs=None,
constraint_order="target",
normalize_columns=False,
fit_intercept=False,
copy_X=True,
initial_guess=None,
thresholds=None,
Expand All @@ -177,7 +172,6 @@ def __init__(
trimming_step_size=trimming_step_size,
max_iter=max_iter,
initial_guess=initial_guess,
fit_intercept=fit_intercept,
copy_X=copy_X,
normalize_columns=normalize_columns,
verbose=verbose,
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/stlsq.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ class STLSQ(BaseOptimizer):
ridge_kw : dict, optional (default None)
Optional keyword arguments to pass to the ridge regression.
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
normalize_columns : boolean, optional (default False)
Normalize the columns of x (the SINDy library terms) before regression
by dividing by the L2-norm. Note that the 'normalize' option in sklearn
Expand Down Expand Up @@ -103,15 +99,13 @@ def __init__(
max_iter=20,
ridge_kw=None,
normalize_columns=False,
fit_intercept=False,
copy_X=True,
initial_guess=None,
verbose=False,
unbias=True,
):
super().__init__(
max_iter=max_iter,
fit_intercept=fit_intercept,
copy_X=copy_X,
normalize_columns=normalize_columns,
unbias=unbias,
Expand Down
6 changes: 0 additions & 6 deletions pysindy/optimizers/trapping_sr3.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,6 @@ class TrappingSR3(SR3):
Initial guess for vector A in the optimization. Otherwise
A is initialized as A = diag(gamma).
fit_intercept : boolean, optional (default False)
Whether to calculate the intercept for this model. If set to false, no
intercept will be used in calculations.
copy_X : boolean, optional (default True)
If True, X will be copied; else, it may be overwritten.
Expand Down Expand Up @@ -239,7 +235,6 @@ def __init__(
max_iter=30,
accel=False,
normalize_columns=False,
fit_intercept=False,
copy_X=True,
m0=None,
A0=None,
Expand All @@ -255,7 +250,6 @@ def __init__(
threshold=threshold,
max_iter=max_iter,
normalize_columns=normalize_columns,
fit_intercept=fit_intercept,
copy_X=copy_X,
thresholder=thresholder,
thresholds=thresholds,
Expand Down
20 changes: 8 additions & 12 deletions pysindy/optimizers/wrapped_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ class WrappedOptimizer(BaseOptimizer):
Enables single target regressors (i.e. those whose predictions are
1-dimensional) to perform multi target regression (i.e. predictions
are 2-dimensional). Also allows unbiasing optimizers that would
otherwise prohibit it.
are 2-dimensional). Also allows unbiasing & normalization for
optimizers that would otherwise not include it.
Args:
optimizer: wrapped optimizer/sparse regression method
Expand All @@ -21,15 +21,14 @@ class WrappedOptimizer(BaseOptimizer):
----------
optimizer: estimator object
The optimizer/sparse regressor to be wrapped, implementing ``fit`` and
``predict``. ``optimizer`` should also have the attributes ``coef_``,
``fit_intercept``, and ``intercept_``. Note that attribute
``normalize`` is deprecated as of sklearn versions >= 1.0 and will be
removed in future versions.
``predict``. ``optimizer`` should also have the attribute ``coef_``.
Any optimizer that supports a ``fit_intercept`` argument should
be initialized to False.
"""

def __init__(self, optimizer, unbias: bool = True):
super().__init__(unbias=unbias)
def __init__(self, optimizer, *args, **kwargs):
super().__init__(*args, **kwargs)
self.optimizer = MultiOutputRegressor(optimizer)

def _reduce(self, x, y):
Expand All @@ -43,10 +42,7 @@ def _reduce(self, x, y):
]
self.coef_ = np.concatenate(coef_list, axis=0)
self.ind_ = np.abs(self.coef_) > COEF_THRESHOLD
if hasattr(self.optimizer, "intercept_"):
self.intercept_ = self.optimizer.intercept_
else:
self.intercept_ = 0.0
self.intercept_ = 0.0
return self

def predict(self, x):
Expand Down
4 changes: 1 addition & 3 deletions test/test_optimizers.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,7 @@ def test_complexity_not_fitted(optimizer, data_derivative_2d):
assert optimizer.complexity > 0


@pytest.mark.parametrize(
"kwargs", [{"normalize_columns": True}, {"fit_intercept": True}, {"copy_X": False}]
)
@pytest.mark.parametrize("kwargs", [{"normalize_columns": True}, {"copy_X": False}])
def test_alternate_parameters(data_derivative_1d, kwargs):
x, x_dot = data_derivative_1d
x = x.reshape(-1, 1)
Expand Down
Loading

0 comments on commit a5dfc4a

Please sign in to comment.