Skip to content

Addresses #24085 - Gaussian mixture weights #24117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions sklearn/manifold/_spectral_embedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from scipy import sparse
from scipy.linalg import eigh
from scipy.sparse.linalg import eigsh
from numbers import Integral, Real
from scipy.sparse.csgraph import connected_components
from scipy.sparse.csgraph import laplacian as csgraph_laplacian

Expand All @@ -22,6 +23,7 @@
)
from ..utils._arpack import _init_arpack_v0
from ..utils.extmath import _deterministic_vector_sign_flip
from ..utils._param_validation import Interval, StrOptions
from ..utils.fixes import lobpcg
from ..metrics.pairwise import rbf_kernel
from ..neighbors import kneighbors_graph, NearestNeighbors
Expand Down Expand Up @@ -542,6 +544,27 @@ class SpectralEmbedding(BaseEstimator):
(100, 2)
"""

_parameter_constraints = {
"n_components": [Interval(Integral, 1, None, closed="left")],
"affinity": [
StrOptions(
{
"nearest_neighbors",
"rbf",
"precomputed",
"precomputed_nearest_neighbors",
},
),
callable,
],
"gamma": [Interval(Real, 0, None, closed="left"), None],
"random_state": ["random_state", None],
"eigen_solver": [StrOptions({"arpack", "lobpcg", "amg"}), None],
"eigen_tol": [Interval(Real, 0, None, closed="left"), StrOptions({"auto"})],
"n_neighbors": [Interval(Integral, 1, None, closed="left"), None],
"n_jobs": [None, Integral],
}

def __init__(
self,
n_components=2,
Expand Down Expand Up @@ -649,6 +672,7 @@ def fit(self, X, y=None):
self : object
Returns the instance itself.
"""
self._validate_params()

X = self._validate_data(X, accept_sparse="csr", ensure_min_samples=2)

Expand Down
2 changes: 1 addition & 1 deletion sklearn/mixture/_gaussian_mixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,10 +715,10 @@ def _initialize(self, X, resp):
weights, means, covariances = _estimate_gaussian_parameters(
X, resp, self.reg_covar, self.covariance_type
)
weights /= n_samples

self.weights_ = weights if self.weights_init is None else self.weights_init
self.means_ = means if self.means_init is None else self.means_init
self.weights_ /= self.weights_.sum()

if self.precisions_init is None:
self.covariances_ = covariances
Expand Down
16 changes: 15 additions & 1 deletion sklearn/preprocessing/_polynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import collections
import numbers
from numbers import Integral
from itertools import chain, combinations
from itertools import combinations_with_replacement as combinations_w_r

Expand All @@ -15,6 +16,7 @@
from ..utils import check_array
from ..utils.deprecation import deprecated
from ..utils.validation import check_is_fitted, FLOAT_DTYPES, _check_sample_weight
from ..utils._param_validation import Interval, StrOptions
from ..utils.validation import _check_feature_names_in
from ..utils.stats import _weighted_percentile

Expand Down Expand Up @@ -627,6 +629,17 @@ class SplineTransformer(TransformerMixin, BaseEstimator):
[0. , 0. , 0.5 , 0.5 ]])
"""

_parameter_constraints = {
"n_knots": [Interval(Integral, 2, None, closed="left")],
"degree": [Interval(Integral, 0, None, closed="left")],
"knots": [StrOptions({"uniform", "quantile"}), "array-like"],
"extrapolation": [
StrOptions({"error", "constant", "linear", "continue", "periodic"})
],
"include_bias": ["boolean"],
"order": [StrOptions({"C", "F"})],
}

def __init__(
self,
n_knots=5,
Expand Down Expand Up @@ -767,6 +780,8 @@ def fit(self, X, y=None, sample_weight=None):
self : object
Fitted transformer.
"""
self._validate_params()

X = self._validate_data(
X,
reset=True,
Expand Down Expand Up @@ -936,7 +951,6 @@ def transform(self, X):
spl = self.bsplines_[i]

if self.extrapolation in ("continue", "error", "periodic"):

if self.extrapolation == "periodic":
# With periodic extrapolation we map x to the segment
# [spl.t[k], spl.t[n]].
Expand Down
99 changes: 0 additions & 99 deletions sklearn/preprocessing/tests/test_polynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,80 +28,6 @@ def is_c_contiguous(a):
assert np.isfortran(est(order="F").fit_transform(X))


@pytest.mark.parametrize(
"params, err_msg",
[
({"degree": -1}, "degree must be a non-negative integer"),
({"degree": 2.5}, "degree must be a non-negative integer"),
({"degree": "string"}, "degree must be a non-negative integer"),
({"n_knots": 1}, "n_knots must be a positive integer >= 2."),
({"n_knots": 1}, "n_knots must be a positive integer >= 2."),
({"n_knots": 2.5}, "n_knots must be a positive integer >= 2."),
({"n_knots": "string"}, "n_knots must be a positive integer >= 2."),
({"knots": 1}, "Expected 2D array, got scalar array instead:"),
({"knots": [1, 2]}, "Expected 2D array, got 1D array instead:"),
(
{"knots": [[1]]},
r"Number of knots, knots.shape\[0\], must be >= 2.",
),
(
{"knots": [[1, 5], [2, 6]]},
r"knots.shape\[1\] == n_features is violated.",
),
(
{"knots": [[1], [1], [2]]},
"knots must be sorted without duplicates.",
),
({"knots": [[2], [1]]}, "knots must be sorted without duplicates."),
(
{"extrapolation": None},
"extrapolation must be one of 'error', 'constant', 'linear', "
"'continue' or 'periodic'.",
),
(
{"extrapolation": 1},
"extrapolation must be one of 'error', 'constant', 'linear', "
"'continue' or 'periodic'.",
),
(
{"extrapolation": "string"},
"extrapolation must be one of 'error', 'constant', 'linear', "
"'continue' or 'periodic'.",
),
({"include_bias": None}, "include_bias must be bool."),
({"include_bias": 1}, "include_bias must be bool."),
({"include_bias": "string"}, "include_bias must be bool."),
(
{"extrapolation": "periodic", "n_knots": 3, "degree": 3},
"Periodic splines require degree < n_knots. Got n_knots=3 and degree=3.",
),
(
{"extrapolation": "periodic", "knots": [[0], [1]], "degree": 2},
"Periodic splines require degree < n_knots. Got n_knots=2 and degree=2.",
),
],
)
def test_spline_transformer_input_validation(params, err_msg):
"""Test that we raise errors for invalid input in SplineTransformer."""
X = [[1], [2]]

with pytest.raises(ValueError, match=err_msg):
SplineTransformer(**params).fit(X)


def test_spline_transformer_manual_knot_input():
"""
Test that array-like knot positions in SplineTransformer are accepted.
"""
X = np.arange(20).reshape(10, 2)
knots = [[0.5, 1], [1.5, 2], [5, 10]]
st1 = SplineTransformer(degree=3, knots=knots, n_knots=None).fit(X)
knots = np.asarray(knots)
st2 = SplineTransformer(degree=3, knots=knots, n_knots=None).fit(X)
for i in range(X.shape[1]):
assert_allclose(st1.bsplines_[i].t, st2.bsplines_[i].t)


@pytest.mark.parametrize("extrapolation", ["continue", "periodic"])
def test_spline_transformer_integer_knots(extrapolation):
"""Test that SplineTransformer accepts integer value knot positions."""
Expand Down Expand Up @@ -238,31 +164,6 @@ def test_spline_transformer_get_base_knot_positions(
assert_allclose(base_knots, expected_knots)


@pytest.mark.parametrize(
"knots, n_knots, degree",
[
("uniform", 5, 3),
("uniform", 12, 8),
(
[[-1.0, 0.0], [0, 1.0], [0.1, 2.0], [0.2, 3.0], [0.3, 4.0], [1, 5.0]],
None,
3,
),
],
)
def test_spline_transformer_periodicity_of_extrapolation(knots, n_knots, degree):
"""Test that the SplineTransformer is periodic for multiple features."""
X_1 = np.linspace((-1, 0), (1, 5), 10)
X_2 = np.linspace((1, 5), (3, 10), 10)

splt = SplineTransformer(
knots=knots, n_knots=n_knots, degree=degree, extrapolation="periodic"
)
splt.fit(X_1)

assert_allclose(splt.transform(X_1), splt.transform(X_2))


@pytest.mark.parametrize(["bias", "intercept"], [(True, False), (False, True)])
def test_spline_transformer_periodic_linear_regression(bias, intercept):
"""Test that B-splines fit a periodic curve pretty well."""
Expand Down
2 changes: 0 additions & 2 deletions sklearn/tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,6 @@ def test_estimators_do_not_raise_errors_in_init_or_set_params(Estimator):
"SkewedChi2Sampler",
"SpectralBiclustering",
"SpectralCoclustering",
"SpectralEmbedding",
"SplineTransformer",
"TransformedTargetRegressor",
]

Expand Down