From 061dff5abb2828e93d2adce8ed7059b068397c5f Mon Sep 17 00:00:00 2001 From: Itay Date: Sun, 12 Mar 2023 22:57:48 +0200 Subject: [PATCH 001/230] typo fix --- doc/modules/ensemble.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/modules/ensemble.rst b/doc/modules/ensemble.rst index 0c4159165e181..c8e4a87ff98a3 100644 --- a/doc/modules/ensemble.rst +++ b/doc/modules/ensemble.rst @@ -962,7 +962,7 @@ Available losses for regression are 'squared_error', 'absolute_error', which is less sensitive to outliers, and 'poisson', which is well suited to model counts and frequencies. For classification, 'log_loss' is the only option. For binary classification it uses the -binary log loss, also kown as binomial deviance or binary cross-entropy. For +binary log loss, also known as binomial deviance or binary cross-entropy. For `n_classes >= 3`, it uses the multi-class log loss function, with multinomial deviance and categorical cross-entropy as alternative names. The appropriate loss version is selected based on :term:`y` passed to :term:`fit`. From aa5e7f7519765d2f8dc2f5d73c3eca092b2f2633 Mon Sep 17 00:00:00 2001 From: Itay Date: Sun, 12 Mar 2023 23:12:59 +0200 Subject: [PATCH 002/230] more typo fixes --- doc/faq.rst | 2 +- doc/modules/grid_search.rst | 2 +- doc/modules/multiclass.rst | 2 +- doc/modules/tree.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/faq.rst b/doc/faq.rst index 8ffe1a717a4cc..dab775de819e7 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -387,7 +387,7 @@ DBSCAN with Levenshtein distances:: array([[0], [1], [2]]) - >>> # We need to specify algoritum='brute' as the default assumes + >>> # We need to specify algorithm='brute' as the default assumes >>> # a continuous feature space. >>> dbscan(X, metric=lev_metric, eps=5, min_samples=2, algorithm='brute') ... # doctest: +SKIP diff --git a/doc/modules/grid_search.rst b/doc/modules/grid_search.rst index 60ca577096b10..ab84f872bb263 100644 --- a/doc/modules/grid_search.rst +++ b/doc/modules/grid_search.rst @@ -433,7 +433,7 @@ ways: :class:`HalvingGridSearchCV`; - by setting `n_candidates='exhaust'`. -Both options are mutally exclusive: using `min_resources='exhaust'` requires +Both options are mutually exclusive: using `min_resources='exhaust'` requires knowing the number of candidates, and symmetrically `n_candidates='exhaust'` requires knowing `min_resources`. diff --git a/doc/modules/multiclass.rst b/doc/modules/multiclass.rst index 70bab7a1075ec..19e4c6f0ec936 100644 --- a/doc/modules/multiclass.rst +++ b/doc/modules/multiclass.rst @@ -464,7 +464,7 @@ Note that all classifiers handling multiclass-multioutput (also known as multitask classification) tasks, support the multilabel classification task as a special case. Multitask classification is similar to the multioutput classification task with different model formulations. For more information, -see the relevant estimator documentat +see the relevant estimator documentation. Below is an example of multiclass-multioutput classification: diff --git a/doc/modules/tree.rst b/doc/modules/tree.rst index 28bcd07ab978d..789b0bab616ca 100644 --- a/doc/modules/tree.rst +++ b/doc/modules/tree.rst @@ -508,7 +508,7 @@ Log Loss or Entropy: leaf :math:`m` as their probability. Using the **Shannon entropy as tree node splitting criterion is equivalent to minimizing the log loss** (also known as cross-entropy and multinomial deviance) between the true labels :math:`y_i` - and the probalistic predictions :math:`T_k(x_i)` of the tree model :math:`T` for class :math:`k`. + and the probabilistic predictions :math:`T_k(x_i)` of the tree model :math:`T` for class :math:`k`. To see this, first recall that the log loss of a tree model :math:`T` computed on a dataset :math:`D` is defined as follows: From 95c15552cd97373414820cea5bf7aedfcbd19c74 Mon Sep 17 00:00:00 2001 From: Itay Date: Sun, 12 Mar 2023 23:44:10 +0200 Subject: [PATCH 003/230] more typo fixes --- doc/developers/maintainer.rst | 2 +- doc/tutorial/machine_learning_map/index.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/developers/maintainer.rst b/doc/developers/maintainer.rst index 506813a7973f5..6b49103774d9c 100644 --- a/doc/developers/maintainer.rst +++ b/doc/developers/maintainer.rst @@ -375,7 +375,7 @@ Before merging, the `Co-authored-by: name ` tags in the detailed description. This will mark the PR as having `multiple co-authors `_. - Whether code contributions are significanly enough to merit co-authorship is + Whether code contributions are significantly enough to merit co-authorship is left to the maintainer's discretion, same as for the "what's new" entry. diff --git a/doc/tutorial/machine_learning_map/index.rst b/doc/tutorial/machine_learning_map/index.rst index 257bad51b42b4..708f8bc43bf73 100644 --- a/doc/tutorial/machine_learning_map/index.rst +++ b/doc/tutorial/machine_learning_map/index.rst @@ -27,8 +27,8 @@ Click on any estimator in the chart below to see its documentation. - - + + From 0b410990509b40847fc854b091990eaa36727dba Mon Sep 17 00:00:00 2001 From: Itay Date: Fri, 17 Mar 2023 17:08:57 +0200 Subject: [PATCH 004/230] using global random seeds instead of fixed seeds. --- sklearn/tests/test_naive_bayes.py | 48 +++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/sklearn/tests/test_naive_bayes.py b/sklearn/tests/test_naive_bayes.py index 979ae4caed407..c3ba2e653f4b0 100644 --- a/sklearn/tests/test_naive_bayes.py +++ b/sklearn/tests/test_naive_bayes.py @@ -31,15 +31,23 @@ X = np.array([[-2, -1], [-1, -1], [-1, -2], [1, 1], [1, 2], [2, 1]]) y = np.array([1, 1, 1, 2, 2, 2]) -# A bit more random tests -rng = np.random.RandomState(0) -X1 = rng.normal(size=(10, 3)) -y1 = (rng.normal(size=(10)) > 0).astype(int) -# Data is 6 random integer points in a 100 dimensional space classified to -# three classes. -X2 = rng.randint(5, size=(6, 100)) -y2 = np.array([1, 1, 2, 2, 3, 3]) +def get_random_normal_x_binary_y(global_random_seed): + # A bit more random tests + rng = np.random.RandomState(global_random_seed) + X1 = rng.normal(size=(10, 3)) + y1 = (rng.normal(size=10) > 0).astype(int) + return X1, y1 + + +def get_random_integer_x_three_classes_y(global_random_seed): + # Data is 6 random integer points in a 100 dimensional space classified to + # three classes. + rng = np.random.RandomState(global_random_seed) + X2 = rng.randint(5, size=(6, 100)) + y2 = np.array([1, 1, 2, 2, 3, 3]) + return X2, y2 + def test_gnb(): @@ -64,16 +72,17 @@ def test_gnb(): GaussianNB().partial_fit(X, y, classes=[0, 1]) -def test_gnb_prior(): +def test_gnb_prior(global_random_seed): # Test whether class priors are properly set. clf = GaussianNB().fit(X, y) assert_array_almost_equal(np.array([3, 3]) / 6.0, clf.class_prior_, 8) + X1,y1 = get_random_normal_x_binary_y(global_random_seed) clf = GaussianNB().fit(X1, y1) # Check that the class priors sum to 1 assert_array_almost_equal(clf.class_prior_.sum(), 1) -def test_gnb_sample_weight(): +def test_gnb_sample_weight(global_random_seed): """Test whether sample weights are properly used in GNB.""" # Sample weights all being 1 should not change results sw = np.ones(6) @@ -85,6 +94,8 @@ def test_gnb_sample_weight(): # Fitting twice with half sample-weights should result # in same result as fitting once with full weights + rng = np.random.RandomState(global_random_seed) + sw = rng.rand(y.shape[0]) clf1 = GaussianNB().fit(X, y, sample_weight=sw) clf2 = GaussianNB().partial_fit(X, y, classes=[1, 2], sample_weight=sw / 2) @@ -215,8 +226,9 @@ def test_gnb_naive_bayes_scale_invariance(): @pytest.mark.parametrize("DiscreteNaiveBayes", DISCRETE_NAIVE_BAYES_CLASSES) -def test_discretenb_prior(DiscreteNaiveBayes): +def test_discretenb_prior(DiscreteNaiveBayes,global_random_seed): # Test whether class priors are properly set. + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) clf = DiscreteNaiveBayes().fit(X2, y2) assert_array_almost_equal( np.log(np.array([2, 2, 2]) / 6.0), clf.class_log_prior_, 8 @@ -274,8 +286,10 @@ def test_discretenb_partial_fit(DiscreteNaiveBayes): @pytest.mark.parametrize("NaiveBayes", ALL_NAIVE_BAYES_CLASSES) -def test_NB_partial_fit_no_first_classes(NaiveBayes): +def test_NB_partial_fit_no_first_classes(NaiveBayes,global_random_seed): # classes is required for first call to partial fit + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) + with pytest.raises( ValueError, match="classes must be passed on the first call to partial_fit." ): @@ -452,10 +466,11 @@ def test_discretenb_degenerate_one_class_case( @pytest.mark.parametrize("kind", ("dense", "sparse")) -def test_mnnb(kind): +def test_mnnb(kind,global_random_seed): # Test Multinomial Naive Bayes classification. # This checks that MultinomialNB implements fit and predict and returns # correct values for a simple toy dataset. + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) if kind == "dense": X = X2 @@ -676,9 +691,11 @@ def test_cnb(): assert_array_almost_equal(clf.feature_log_prob_, normed_weights) -def test_categoricalnb(): +def test_categoricalnb(global_random_seed): # Check the ability to predict the training set. clf = CategoricalNB() + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) + y_pred = clf.fit(X2, y2).predict(X2) assert_array_equal(y_pred, y2) @@ -966,7 +983,8 @@ def test_check_alpha(): @pytest.mark.parametrize("Estimator", ALL_NAIVE_BAYES_CLASSES) -def test_predict_joint_proba(Estimator): +def test_predict_joint_proba(Estimator,global_random_seed): + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) est = Estimator().fit(X2, y2) jll = est.predict_joint_log_proba(X2) log_prob_x = logsumexp(jll, axis=1) From daae304325cafe5a1a4a70e59d528bc4eda6494b Mon Sep 17 00:00:00 2001 From: Itay Date: Fri, 17 Mar 2023 17:10:01 +0200 Subject: [PATCH 005/230] black formatting --- sklearn/tests/test_naive_bayes.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sklearn/tests/test_naive_bayes.py b/sklearn/tests/test_naive_bayes.py index c3ba2e653f4b0..4516fabb8961d 100644 --- a/sklearn/tests/test_naive_bayes.py +++ b/sklearn/tests/test_naive_bayes.py @@ -49,7 +49,6 @@ def get_random_integer_x_three_classes_y(global_random_seed): return X2, y2 - def test_gnb(): # Gaussian Naive Bayes classification. # This checks that GaussianNB implements fit and predict and returns @@ -76,7 +75,7 @@ def test_gnb_prior(global_random_seed): # Test whether class priors are properly set. clf = GaussianNB().fit(X, y) assert_array_almost_equal(np.array([3, 3]) / 6.0, clf.class_prior_, 8) - X1,y1 = get_random_normal_x_binary_y(global_random_seed) + X1, y1 = get_random_normal_x_binary_y(global_random_seed) clf = GaussianNB().fit(X1, y1) # Check that the class priors sum to 1 assert_array_almost_equal(clf.class_prior_.sum(), 1) @@ -226,9 +225,9 @@ def test_gnb_naive_bayes_scale_invariance(): @pytest.mark.parametrize("DiscreteNaiveBayes", DISCRETE_NAIVE_BAYES_CLASSES) -def test_discretenb_prior(DiscreteNaiveBayes,global_random_seed): +def test_discretenb_prior(DiscreteNaiveBayes, global_random_seed): # Test whether class priors are properly set. - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) clf = DiscreteNaiveBayes().fit(X2, y2) assert_array_almost_equal( np.log(np.array([2, 2, 2]) / 6.0), clf.class_log_prior_, 8 @@ -286,9 +285,9 @@ def test_discretenb_partial_fit(DiscreteNaiveBayes): @pytest.mark.parametrize("NaiveBayes", ALL_NAIVE_BAYES_CLASSES) -def test_NB_partial_fit_no_first_classes(NaiveBayes,global_random_seed): +def test_NB_partial_fit_no_first_classes(NaiveBayes, global_random_seed): # classes is required for first call to partial fit - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) with pytest.raises( ValueError, match="classes must be passed on the first call to partial_fit." @@ -466,11 +465,11 @@ def test_discretenb_degenerate_one_class_case( @pytest.mark.parametrize("kind", ("dense", "sparse")) -def test_mnnb(kind,global_random_seed): +def test_mnnb(kind, global_random_seed): # Test Multinomial Naive Bayes classification. # This checks that MultinomialNB implements fit and predict and returns # correct values for a simple toy dataset. - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) if kind == "dense": X = X2 @@ -694,7 +693,7 @@ def test_cnb(): def test_categoricalnb(global_random_seed): # Check the ability to predict the training set. clf = CategoricalNB() - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) y_pred = clf.fit(X2, y2).predict(X2) assert_array_equal(y_pred, y2) @@ -801,7 +800,6 @@ def test_categoricalnb_with_min_categories( ], ) def test_categoricalnb_min_categories_errors(min_categories, error_msg): - X = np.array([[0, 0], [0, 1], [0, 0], [1, 1]]) y = np.array([1, 1, 2, 2]) @@ -983,8 +981,8 @@ def test_check_alpha(): @pytest.mark.parametrize("Estimator", ALL_NAIVE_BAYES_CLASSES) -def test_predict_joint_proba(Estimator,global_random_seed): - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) +def test_predict_joint_proba(Estimator, global_random_seed): + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) est = Estimator().fit(X2, y2) jll = est.predict_joint_log_proba(X2) log_prob_x = logsumexp(jll, axis=1) From 7f4d0aec072f3b7c6eadfc8846828909d1a8eae0 Mon Sep 17 00:00:00 2001 From: Itay Date: Fri, 17 Mar 2023 17:27:52 +0200 Subject: [PATCH 006/230] global random seed, replaced two functions with static seeds --- sklearn/svm/tests/test_svm.py | 10 +++++----- sklearn/tests/test_naive_bayes.py | 22 ++++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index 838ded31ba23c..4011c6ae6a58f 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -704,9 +704,9 @@ def test_bad_input(): clf.predict(Xt) -def test_svc_nonfinite_params(): +def test_svc_nonfinite_params(global_random_seed): # Check SVC throws ValueError when dealing with non-finite parameter values - rng = np.random.RandomState(0) + rng = np.random.RandomState(global_random_seed) n_samples = 10 fmax = np.finfo(np.float64).max X = fmax * rng.uniform(size=(n_samples, 2)) @@ -1070,11 +1070,11 @@ def test_linear_svm_convergence_warnings(): assert lsvr.n_iter_ == 2 -def test_svr_coef_sign(): +def test_svr_coef_sign(global_random_seed): # Test that SVR(kernel="linear") has coef_ with the right sign. # Non-regression test for #2933. - X = np.random.RandomState(21).randn(10, 3) - y = np.random.RandomState(12).randn(10) + X = np.random.RandomState(global_random_seed).randn(10, 3) + y = np.random.RandomState(global_random_seed + 1).randn(10) for svr in [svm.SVR(kernel="linear"), svm.NuSVR(kernel="linear"), svm.LinearSVR()]: svr.fit(X, y) diff --git a/sklearn/tests/test_naive_bayes.py b/sklearn/tests/test_naive_bayes.py index 4516fabb8961d..c3ba2e653f4b0 100644 --- a/sklearn/tests/test_naive_bayes.py +++ b/sklearn/tests/test_naive_bayes.py @@ -49,6 +49,7 @@ def get_random_integer_x_three_classes_y(global_random_seed): return X2, y2 + def test_gnb(): # Gaussian Naive Bayes classification. # This checks that GaussianNB implements fit and predict and returns @@ -75,7 +76,7 @@ def test_gnb_prior(global_random_seed): # Test whether class priors are properly set. clf = GaussianNB().fit(X, y) assert_array_almost_equal(np.array([3, 3]) / 6.0, clf.class_prior_, 8) - X1, y1 = get_random_normal_x_binary_y(global_random_seed) + X1,y1 = get_random_normal_x_binary_y(global_random_seed) clf = GaussianNB().fit(X1, y1) # Check that the class priors sum to 1 assert_array_almost_equal(clf.class_prior_.sum(), 1) @@ -225,9 +226,9 @@ def test_gnb_naive_bayes_scale_invariance(): @pytest.mark.parametrize("DiscreteNaiveBayes", DISCRETE_NAIVE_BAYES_CLASSES) -def test_discretenb_prior(DiscreteNaiveBayes, global_random_seed): +def test_discretenb_prior(DiscreteNaiveBayes,global_random_seed): # Test whether class priors are properly set. - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) clf = DiscreteNaiveBayes().fit(X2, y2) assert_array_almost_equal( np.log(np.array([2, 2, 2]) / 6.0), clf.class_log_prior_, 8 @@ -285,9 +286,9 @@ def test_discretenb_partial_fit(DiscreteNaiveBayes): @pytest.mark.parametrize("NaiveBayes", ALL_NAIVE_BAYES_CLASSES) -def test_NB_partial_fit_no_first_classes(NaiveBayes, global_random_seed): +def test_NB_partial_fit_no_first_classes(NaiveBayes,global_random_seed): # classes is required for first call to partial fit - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) with pytest.raises( ValueError, match="classes must be passed on the first call to partial_fit." @@ -465,11 +466,11 @@ def test_discretenb_degenerate_one_class_case( @pytest.mark.parametrize("kind", ("dense", "sparse")) -def test_mnnb(kind, global_random_seed): +def test_mnnb(kind,global_random_seed): # Test Multinomial Naive Bayes classification. # This checks that MultinomialNB implements fit and predict and returns # correct values for a simple toy dataset. - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) if kind == "dense": X = X2 @@ -693,7 +694,7 @@ def test_cnb(): def test_categoricalnb(global_random_seed): # Check the ability to predict the training set. clf = CategoricalNB() - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) y_pred = clf.fit(X2, y2).predict(X2) assert_array_equal(y_pred, y2) @@ -800,6 +801,7 @@ def test_categoricalnb_with_min_categories( ], ) def test_categoricalnb_min_categories_errors(min_categories, error_msg): + X = np.array([[0, 0], [0, 1], [0, 0], [1, 1]]) y = np.array([1, 1, 2, 2]) @@ -981,8 +983,8 @@ def test_check_alpha(): @pytest.mark.parametrize("Estimator", ALL_NAIVE_BAYES_CLASSES) -def test_predict_joint_proba(Estimator, global_random_seed): - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) +def test_predict_joint_proba(Estimator,global_random_seed): + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) est = Estimator().fit(X2, y2) jll = est.predict_joint_log_proba(X2) log_prob_x = logsumexp(jll, axis=1) From caedb03b0d31212326ab182951e3330b29a79fbe Mon Sep 17 00:00:00 2001 From: Itay Date: Fri, 17 Mar 2023 17:28:31 +0200 Subject: [PATCH 007/230] revert other changes --- sklearn/tests/test_naive_bayes.py | 48 ++++++++++--------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/sklearn/tests/test_naive_bayes.py b/sklearn/tests/test_naive_bayes.py index c3ba2e653f4b0..979ae4caed407 100644 --- a/sklearn/tests/test_naive_bayes.py +++ b/sklearn/tests/test_naive_bayes.py @@ -31,23 +31,15 @@ X = np.array([[-2, -1], [-1, -1], [-1, -2], [1, 1], [1, 2], [2, 1]]) y = np.array([1, 1, 1, 2, 2, 2]) +# A bit more random tests +rng = np.random.RandomState(0) +X1 = rng.normal(size=(10, 3)) +y1 = (rng.normal(size=(10)) > 0).astype(int) -def get_random_normal_x_binary_y(global_random_seed): - # A bit more random tests - rng = np.random.RandomState(global_random_seed) - X1 = rng.normal(size=(10, 3)) - y1 = (rng.normal(size=10) > 0).astype(int) - return X1, y1 - - -def get_random_integer_x_three_classes_y(global_random_seed): - # Data is 6 random integer points in a 100 dimensional space classified to - # three classes. - rng = np.random.RandomState(global_random_seed) - X2 = rng.randint(5, size=(6, 100)) - y2 = np.array([1, 1, 2, 2, 3, 3]) - return X2, y2 - +# Data is 6 random integer points in a 100 dimensional space classified to +# three classes. +X2 = rng.randint(5, size=(6, 100)) +y2 = np.array([1, 1, 2, 2, 3, 3]) def test_gnb(): @@ -72,17 +64,16 @@ def test_gnb(): GaussianNB().partial_fit(X, y, classes=[0, 1]) -def test_gnb_prior(global_random_seed): +def test_gnb_prior(): # Test whether class priors are properly set. clf = GaussianNB().fit(X, y) assert_array_almost_equal(np.array([3, 3]) / 6.0, clf.class_prior_, 8) - X1,y1 = get_random_normal_x_binary_y(global_random_seed) clf = GaussianNB().fit(X1, y1) # Check that the class priors sum to 1 assert_array_almost_equal(clf.class_prior_.sum(), 1) -def test_gnb_sample_weight(global_random_seed): +def test_gnb_sample_weight(): """Test whether sample weights are properly used in GNB.""" # Sample weights all being 1 should not change results sw = np.ones(6) @@ -94,8 +85,6 @@ def test_gnb_sample_weight(global_random_seed): # Fitting twice with half sample-weights should result # in same result as fitting once with full weights - rng = np.random.RandomState(global_random_seed) - sw = rng.rand(y.shape[0]) clf1 = GaussianNB().fit(X, y, sample_weight=sw) clf2 = GaussianNB().partial_fit(X, y, classes=[1, 2], sample_weight=sw / 2) @@ -226,9 +215,8 @@ def test_gnb_naive_bayes_scale_invariance(): @pytest.mark.parametrize("DiscreteNaiveBayes", DISCRETE_NAIVE_BAYES_CLASSES) -def test_discretenb_prior(DiscreteNaiveBayes,global_random_seed): +def test_discretenb_prior(DiscreteNaiveBayes): # Test whether class priors are properly set. - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) clf = DiscreteNaiveBayes().fit(X2, y2) assert_array_almost_equal( np.log(np.array([2, 2, 2]) / 6.0), clf.class_log_prior_, 8 @@ -286,10 +274,8 @@ def test_discretenb_partial_fit(DiscreteNaiveBayes): @pytest.mark.parametrize("NaiveBayes", ALL_NAIVE_BAYES_CLASSES) -def test_NB_partial_fit_no_first_classes(NaiveBayes,global_random_seed): +def test_NB_partial_fit_no_first_classes(NaiveBayes): # classes is required for first call to partial fit - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) - with pytest.raises( ValueError, match="classes must be passed on the first call to partial_fit." ): @@ -466,11 +452,10 @@ def test_discretenb_degenerate_one_class_case( @pytest.mark.parametrize("kind", ("dense", "sparse")) -def test_mnnb(kind,global_random_seed): +def test_mnnb(kind): # Test Multinomial Naive Bayes classification. # This checks that MultinomialNB implements fit and predict and returns # correct values for a simple toy dataset. - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) if kind == "dense": X = X2 @@ -691,11 +676,9 @@ def test_cnb(): assert_array_almost_equal(clf.feature_log_prob_, normed_weights) -def test_categoricalnb(global_random_seed): +def test_categoricalnb(): # Check the ability to predict the training set. clf = CategoricalNB() - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) - y_pred = clf.fit(X2, y2).predict(X2) assert_array_equal(y_pred, y2) @@ -983,8 +966,7 @@ def test_check_alpha(): @pytest.mark.parametrize("Estimator", ALL_NAIVE_BAYES_CLASSES) -def test_predict_joint_proba(Estimator,global_random_seed): - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) +def test_predict_joint_proba(Estimator): est = Estimator().fit(X2, y2) jll = est.predict_joint_log_proba(X2) log_prob_x = logsumexp(jll, axis=1) From 7b050542625f06cf80c44754d2e2f3e276aa4573 Mon Sep 17 00:00:00 2001 From: Itay Date: Tue, 21 Mar 2023 22:10:28 +0200 Subject: [PATCH 008/230] adding global random seeds instead of static randoms --- sklearn/svm/tests/test_svm.py | 250 +++++++++++++++++++--------------- 1 file changed, 138 insertions(+), 112 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index 4011c6ae6a58f..6cd8f0aa85cdb 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -36,12 +36,14 @@ T = [[-1, -1], [2, 2], [3, 2]] true_result = [1, 2, 2] -# also load the iris dataset -iris = datasets.load_iris() -rng = check_random_state(42) -perm = rng.permutation(iris.target.size) -iris.data = iris.data[perm] -iris.target = iris.target[perm] + +def get_iris_dataset(global_random_seed): + iris = datasets.load_iris() + rng = check_random_state(global_random_seed) + perm = rng.permutation(iris.target.size) + iris.data = iris.data[perm] + iris.target = iris.target[perm] + return iris def test_libsvm_parameters(): @@ -54,9 +56,9 @@ def test_libsvm_parameters(): assert_array_equal(clf.predict(X), Y) -def test_libsvm_iris(): +def test_libsvm_iris(global_random_seed): # Check consistency on dataset iris. - + iris = get_iris_dataset(global_random_seed) # shuffle the dataset so that labels are not ordered for k in ("linear", "rbf"): clf = svm.SVC(kernel=k).fit(iris.data, iris.target) @@ -134,7 +136,7 @@ def test_libsvm_iris(): assert_array_equal(pred, pred2) -def test_precomputed(): +def test_precomputed(global_random_seed): # SVC with a precomputed kernel. # We test it with a toy dataset and with iris. clf = svm.SVC(kernel="precomputed") @@ -183,6 +185,7 @@ def kfunc(x, y): # and check parameters against a linear SVC clf = svm.SVC(kernel="precomputed") clf2 = svm.SVC(kernel="linear") + iris = get_iris_dataset(global_random_seed) K = np.dot(iris.data, iris.data.T) clf.fit(K, iris.target) clf2.fit(iris.data, iris.target) @@ -212,11 +215,11 @@ def test_svr(): diabetes = datasets.load_diabetes() for clf in ( - svm.NuSVR(kernel="linear", nu=0.4, C=1.0), - svm.NuSVR(kernel="linear", nu=0.4, C=10.0), - svm.SVR(kernel="linear", C=10.0), - svm.LinearSVR(C=10.0), - svm.LinearSVR(C=10.0), + svm.NuSVR(kernel="linear", nu=0.4, C=1.0), + svm.NuSVR(kernel="linear", nu=0.4, C=10.0), + svm.SVR(kernel="linear", C=10.0), + svm.LinearSVR(C=10.0), + svm.LinearSVR(C=10.0), ): clf.fit(diabetes.data, diabetes.target) assert clf.score(diabetes.data, diabetes.target) > 0.02 @@ -241,7 +244,7 @@ def test_linearsvr(): assert_almost_equal(score1, score2, 2) -def test_linearsvr_fit_sampleweight(): +def test_linearsvr_fit_sampleweight(global_random_seed): # check correct result when sample_weight is 1 # check that SVR(kernel='linear') and LinearSVC() give # comparable results @@ -265,8 +268,8 @@ def test_linearsvr_fit_sampleweight(): # check that fit(X) = fit([X1, X2, X3],sample_weight = [n1, n2, n3]) where # X = X1 repeated n1 times, X2 repeated n2 times and so forth - random_state = check_random_state(0) - random_weight = random_state.randint(0, 10, n_samples) + rng = np.random.RandomState(global_random_seed) + random_weight = rng.randint(0, 10, n_samples) lsvr_unflat = svm.LinearSVR(C=1e3, tol=1e-12, max_iter=10000).fit( diabetes.data, diabetes.target, sample_weight=random_weight ) @@ -307,20 +310,21 @@ def test_oneclass(): (lambda: clf.coef_)() -def test_oneclass_decision_function(): +def test_oneclass_decision_function(global_random_seed): # Test OneClassSVM decision function - clf = svm.OneClassSVM() - rnd = check_random_state(2) - + rng = np.random.RandomState(global_random_seed) + N = 1000 # Generate train data - X = 0.3 * rnd.randn(100, 2) + X = 0.3 * rng.randn(5*N, 2) + import seaborn as sns + sns.scatterplot(X) X_train = np.r_[X + 2, X - 2] # Generate some regular novel observations - X = 0.3 * rnd.randn(20, 2) + X = 0.3 * rng.randn(N, 2) X_test = np.r_[X + 2, X - 2] # Generate some abnormal novel observations - X_outliers = rnd.uniform(low=-4, high=4, size=(20, 2)) + X_outliers = rng.uniform(low=-4, high=4, size=(N, 2)) # fit the model clf = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.1) @@ -328,9 +332,9 @@ def test_oneclass_decision_function(): # predict things y_pred_test = clf.predict(X_test) - assert np.mean(y_pred_test == 1) > 0.9 + assert np.mean(y_pred_test == 1) > 0.85 y_pred_outliers = clf.predict(X_outliers) - assert np.mean(y_pred_outliers == -1) > 0.9 + assert np.mean(y_pred_outliers == -1) > 0.85 dec_func_test = clf.decision_function(X_test) assert_array_equal((dec_func_test > 0).ravel(), y_pred_test == 1) dec_func_outliers = clf.decision_function(X_outliers) @@ -361,13 +365,14 @@ def test_tweak_params(): assert_array_equal(clf.predict([[-0.1, -0.1]]), [2]) -def test_probability(): +def test_probability(global_random_seed): # Predict probabilities using SVC # This uses cross validation, so we use a slightly bigger testing set. + iris = get_iris_dataset(global_random_seed) for clf in ( - svm.SVC(probability=True, random_state=0, C=1.0), - svm.NuSVC(probability=True, random_state=0), + svm.SVC(probability=True, random_state=global_random_seed + 1, C=1.0), + svm.NuSVC(probability=True, random_state=global_random_seed + 2), ): clf.fit(iris.data, iris.target) @@ -380,7 +385,8 @@ def test_probability(): ) -def test_decision_function(): +def test_decision_function(global_random_seed): + iris = get_iris_dataset(global_random_seed) # Test decision_function # Sanity check, test that decision_function implemented in python # returns the same as the one in libsvm @@ -414,9 +420,10 @@ def test_decision_function(): @pytest.mark.parametrize("SVM", (svm.SVC, svm.NuSVC)) -def test_decision_function_shape(SVM): +def test_decision_function_shape(SVM, global_random_seed): # check that decision_function_shape='ovr' or 'ovo' gives # correct shape and is consistent with predict + iris = get_iris_dataset(global_random_seed) clf = SVM(kernel="linear", decision_function_shape="ovr").fit( iris.data, iris.target @@ -426,8 +433,8 @@ def test_decision_function_shape(SVM): assert_array_equal(clf.predict(iris.data), np.argmax(dec, axis=1)) # with five classes: - X, y = make_blobs(n_samples=80, centers=5, random_state=0) - X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0) + X, y = make_blobs(n_samples=80, centers=5, random_state=global_random_seed + 1) + X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=global_random_seed + 2) clf = SVM(kernel="linear", decision_function_shape="ovr").fit(X_train, y_train) dec = clf.decision_function(X_test) @@ -440,10 +447,11 @@ def test_decision_function_shape(SVM): assert dec.shape == (len(X_train), 10) -def test_svr_predict(): +def test_svr_predict(global_random_seed): # Test SVR's decision_function # Sanity check, test that predict implemented in python # returns the same as the one in libsvm + iris = get_iris_dataset(global_random_seed) X = iris.data y = iris.target @@ -462,7 +470,7 @@ def test_svr_predict(): assert_array_almost_equal(dec.ravel(), reg.predict(X).ravel()) -def test_weight(): +def test_weight(global_random_seed): # Test class weights clf = svm.SVC(class_weight={1: 0.1}) # we give a small weights to class 1 @@ -471,13 +479,13 @@ def test_weight(): assert_array_almost_equal(clf.predict(X), [2] * 6) X_, y_ = make_classification( - n_samples=200, n_features=10, weights=[0.833, 0.167], random_state=2 + n_samples=200, n_features=10, weights=[0.833, 0.167], random_state=global_random_seed ) for clf in ( - linear_model.LogisticRegression(), - svm.LinearSVC(random_state=0), - svm.SVC(), + linear_model.LogisticRegression(), + svm.LinearSVC(random_state=global_random_seed + 1), + svm.SVC(), ): clf.set_params(class_weight={0: 0.1, 1: 10}) clf.fit(X_[:100], y_[:100]) @@ -573,9 +581,9 @@ def test_negative_sample_weights_mask_all_samples(Estimator, err_msg, sample_wei "Classifier, err_msg", [ ( - svm.SVC, - "Invalid input - all samples with positive weights belong to the same" - " class", + svm.SVC, + "Invalid input - all samples with positive weights belong to the same" + " class", ), (svm.NuSVC, "specified nu is infeasible"), ], @@ -606,7 +614,7 @@ def test_negative_weights_svc_leave_just_one_label(Classifier, err_msg, sample_w ids=["partial-mask-label-1", "partial-mask-label-2"], ) def test_negative_weights_svc_leave_two_labels( - Classifier, model, sample_weight, mask_side + Classifier, model, sample_weight, mask_side ): clf = Classifier(kernel="linear") clf.fit(X, Y, sample_weight=sample_weight) @@ -630,8 +638,9 @@ def test_negative_weight_equal_coeffs(Estimator, sample_weight): @ignore_warnings(category=UndefinedMetricWarning) -def test_auto_weight(): +def test_auto_weight(global_random_seed): # Test class weights for imbalanced data + iris = get_iris_dataset(global_random_seed) from sklearn.linear_model import LogisticRegression # We take as dataset the two-dimensional projection of iris so @@ -650,9 +659,9 @@ def test_auto_weight(): assert np.argmax(class_weights) == 2 for clf in ( - svm.SVC(kernel="linear"), - svm.LinearSVC(random_state=0), - LogisticRegression(), + svm.SVC(kernel="linear"), + svm.LinearSVC(random_state=global_random_seed + 1), + LogisticRegression(), ): # check that score is better when class='balanced' is set. y_pred = clf.fit(X[unbalanced], y[unbalanced]).predict(X) @@ -666,14 +675,14 @@ def test_auto_weight(): ) -def test_bad_input(): +def test_bad_input(global_random_seed): # Test dimensions for labels Y2 = Y[:-1] # wrong dimensions for labels with pytest.raises(ValueError): svm.SVC().fit(X, Y2) # Test with arrays that are non-contiguous. - for clf in (svm.SVC(), svm.LinearSVC(random_state=0)): + for clf in (svm.SVC(), svm.LinearSVC(random_state=global_random_seed)): Xf = np.asfortranarray(X) assert not Xf.flags["C_CONTIGUOUS"] yf = np.ascontiguousarray(np.tile(Y, (2, 1)).T) @@ -718,8 +727,10 @@ def test_svc_nonfinite_params(global_random_seed): clf.fit(X, y) -def test_unicode_kernel(): +def test_unicode_kernel(global_random_seed): # Test that a unicode kernel name does not cause a TypeError + iris = get_iris_dataset(global_random_seed) + clf = svm.SVC(kernel="linear", probability=True) clf.fit(X, Y) clf.predict_proba(T) @@ -750,31 +761,31 @@ def test_sparse_fit_support_vectors_empty(): @pytest.mark.parametrize("loss", ["hinge", "squared_hinge"]) @pytest.mark.parametrize("penalty", ["l1", "l2"]) @pytest.mark.parametrize("dual", [True, False]) -def test_linearsvc_parameters(loss, penalty, dual): +def test_linearsvc_parameters(loss, penalty, dual, global_random_seed): # Test possible parameter combinations in LinearSVC # Generate list of possible parameter combinations - X, y = make_classification(n_samples=5, n_features=5, random_state=0) + X, y = make_classification(n_samples=5, n_features=5, random_state=global_random_seed) - clf = svm.LinearSVC(penalty=penalty, loss=loss, dual=dual, random_state=0) + clf = svm.LinearSVC(penalty=penalty, loss=loss, dual=dual, random_state=global_random_seed + 1) if ( - (loss, penalty) == ("hinge", "l1") - or (loss, penalty, dual) == ("hinge", "l2", False) - or (penalty, dual) == ("l1", True) + (loss, penalty) == ("hinge", "l1") + or (loss, penalty, dual) == ("hinge", "l2", False) + or (penalty, dual) == ("l1", True) ): with pytest.raises( - ValueError, - match="Unsupported set of arguments.*penalty='%s.*loss='%s.*dual=%s" - % (penalty, loss, dual), + ValueError, + match="Unsupported set of arguments.*penalty='%s.*loss='%s.*dual=%s" + % (penalty, loss, dual), ): clf.fit(X, y) else: clf.fit(X, y) -def test_linearsvc(): +def test_linearsvc(global_random_seed): # Test basic routines using LinearSVC - clf = svm.LinearSVC(random_state=0).fit(X, Y) + clf = svm.LinearSVC(random_state=global_random_seed).fit(X, Y) # by default should have intercept assert clf.fit_intercept @@ -784,16 +795,16 @@ def test_linearsvc(): # the same with l1 penalty clf = svm.LinearSVC( - penalty="l1", loss="squared_hinge", dual=False, random_state=0 + penalty="l1", loss="squared_hinge", dual=False, random_state=global_random_seed + 1 ).fit(X, Y) assert_array_equal(clf.predict(T), true_result) # l2 penalty with dual formulation - clf = svm.LinearSVC(penalty="l2", dual=True, random_state=0).fit(X, Y) + clf = svm.LinearSVC(penalty="l2", dual=True, random_state=global_random_seed + 2).fit(X, Y) assert_array_equal(clf.predict(T), true_result) # l2 penalty, l1 loss - clf = svm.LinearSVC(penalty="l2", loss="hinge", dual=True, random_state=0) + clf = svm.LinearSVC(penalty="l2", loss="hinge", dual=True, random_state=global_random_seed + 3) clf.fit(X, Y) assert_array_equal(clf.predict(T), true_result) @@ -803,10 +814,12 @@ def test_linearsvc(): assert_array_equal(res, true_result) -def test_linearsvc_crammer_singer(): +def test_linearsvc_crammer_singer(global_random_seed): # Test LinearSVC with crammer_singer multi-class svm - ovr_clf = svm.LinearSVC(random_state=0).fit(iris.data, iris.target) - cs_clf = svm.LinearSVC(multi_class="crammer_singer", random_state=0) + iris = get_iris_dataset(global_random_seed) + + ovr_clf = svm.LinearSVC(random_state=global_random_seed + 1).fit(iris.data, iris.target) + cs_clf = svm.LinearSVC(multi_class="crammer_singer", random_state=global_random_seed + 2) cs_clf.fit(iris.data, iris.target) # similar prediction for ovr and crammer-singer: @@ -824,12 +837,12 @@ def test_linearsvc_crammer_singer(): assert_array_almost_equal(dec_func, cs_clf.decision_function(iris.data)) -def test_linearsvc_fit_sampleweight(): +def test_linearsvc_fit_sampleweight(global_random_seed): # check correct result when sample_weight is 1 n_samples = len(X) unit_weight = np.ones(n_samples) - clf = svm.LinearSVC(random_state=0).fit(X, Y) - clf_unitweight = svm.LinearSVC(random_state=0, tol=1e-12, max_iter=1000).fit( + clf = svm.LinearSVC(random_state=global_random_seed).fit(X, Y) + clf_unitweight = svm.LinearSVC(random_state=global_random_seed + 1, tol=1e-12, max_iter=1000).fit( X, Y, sample_weight=unit_weight ) @@ -840,16 +853,16 @@ def test_linearsvc_fit_sampleweight(): # check that fit(X) = fit([X1, X2, X3],sample_weight = [n1, n2, n3]) where # X = X1 repeated n1 times, X2 repeated n2 times and so forth - random_state = check_random_state(0) - random_weight = random_state.randint(0, 10, n_samples) - lsvc_unflat = svm.LinearSVC(random_state=0, tol=1e-12, max_iter=1000).fit( + rng = np.random.RandomState(global_random_seed) + random_weight = rng.randint(0, 10, n_samples) + lsvc_unflat = svm.LinearSVC(random_state=global_random_seed + 2, tol=1e-12, max_iter=1000).fit( X, Y, sample_weight=random_weight ) pred1 = lsvc_unflat.predict(T) X_flat = np.repeat(X, random_weight, axis=0) y_flat = np.repeat(Y, random_weight, axis=0) - lsvc_flat = svm.LinearSVC(random_state=0, tol=1e-12, max_iter=1000).fit( + lsvc_flat = svm.LinearSVC(random_state=global_random_seed + 3, tol=1e-12, max_iter=1000).fit( X_flat, y_flat ) pred2 = lsvc_flat.predict(T) @@ -858,16 +871,16 @@ def test_linearsvc_fit_sampleweight(): assert_allclose(lsvc_unflat.coef_, lsvc_flat.coef_, 1, 0.0001) -def test_crammer_singer_binary(): +def test_crammer_singer_binary(global_random_seed): # Test Crammer-Singer formulation in the binary case - X, y = make_classification(n_classes=2, random_state=0) + X, y = make_classification(n_classes=2, random_state=global_random_seed) for fit_intercept in (True, False): acc = ( svm.LinearSVC( fit_intercept=fit_intercept, multi_class="crammer_singer", - random_state=0, + random_state=global_random_seed + 1, ) .fit(X, y) .score(X, y) @@ -875,11 +888,13 @@ def test_crammer_singer_binary(): assert acc > 0.9 -def test_linearsvc_iris(): +def test_linearsvc_iris(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # Test that LinearSVC gives plausible predictions on the iris dataset # Also, test symbolic class names (classes_). target = iris.target_names[iris.target] - clf = svm.LinearSVC(random_state=0).fit(iris.data, target) + clf = svm.LinearSVC(random_state=global_random_seed + 1).fit(iris.data, target) assert set(clf.classes_) == set(iris.target_names) assert np.mean(clf.predict(iris.data) == target) > 0.8 @@ -888,7 +903,7 @@ def test_linearsvc_iris(): assert_array_equal(pred, clf.predict(iris.data)) -def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC): +def test_dense_liblinear_intercept_handling(global_random_seed, classifier=svm.LinearSVC): # Test that dense liblinear honours intercept_scaling param X = [[2, 1], [3, 1], [1, 3], [2, 3]] y = [0, 0, 1, 1] @@ -899,7 +914,7 @@ def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC): dual=False, C=4, tol=1e-7, - random_state=0, + random_state=global_random_seed, ) assert clf.intercept_scaling == 1, clf.intercept_scaling assert clf.fit_intercept @@ -925,7 +940,9 @@ def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC): assert_array_almost_equal(intercept1, intercept2, decimal=2) -def test_liblinear_set_coef(): +def test_liblinear_set_coef(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # multi-class case clf = svm.LinearSVC().fit(iris.data, iris.target) values = clf.decision_function(iris.data) @@ -946,7 +963,9 @@ def test_liblinear_set_coef(): assert_array_equal(values, values2) -def test_immutable_coef_property(): +def test_immutable_coef_property(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # Check that primal coef modification are not silently ignored svms = [ svm.SVC(kernel="linear").fit(iris.data, iris.target), @@ -977,13 +996,15 @@ def test_linearsvc_verbose(): os.dup2(stdout, 1) # restore original stdout -def test_svc_clone_with_callable_kernel(): +def test_svc_clone_with_callable_kernel(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # create SVM with callable linear kernel, check that results are the same # as with built-in linear kernel svm_callable = svm.SVC( kernel=lambda x, y: np.dot(x, y.T), probability=True, - random_state=0, + random_state=global_random_seed + 1, decision_function_shape="ovr", ) # clone for checking clonability with lambda functions.. @@ -991,7 +1012,7 @@ def test_svc_clone_with_callable_kernel(): svm_cloned.fit(iris.data, iris.target) svm_builtin = svm.SVC( - kernel="linear", probability=True, random_state=0, decision_function_shape="ovr" + kernel="linear", probability=True, random_state=global_random_seed + 1, decision_function_shape="ovr" ) svm_builtin.fit(iris.data, iris.target) @@ -1016,9 +1037,9 @@ def test_svc_bad_kernel(): svc.fit(X, Y) -def test_libsvm_convergence_warnings(): +def test_libsvm_convergence_warnings(global_random_seed): a = svm.SVC( - kernel=lambda x, y: np.dot(x, y.T), probability=True, random_state=0, max_iter=2 + kernel=lambda x, y: np.dot(x, y.T), probability=True, random_state=global_random_seed, max_iter=2 ) warning_msg = ( r"Solver terminated early \(max_iter=2\). Consider pre-processing " @@ -1043,18 +1064,20 @@ def test_unfitted(): # ignore convergence warnings from max_iter=1 @ignore_warnings -def test_consistent_proba(): - a = svm.SVC(probability=True, max_iter=1, random_state=0) +def test_consistent_proba(global_random_seed): + a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed) proba_1 = a.fit(X, Y).predict_proba(X) - a = svm.SVC(probability=True, max_iter=1, random_state=0) + a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed + 1) proba_2 = a.fit(X, Y).predict_proba(X) assert_array_almost_equal(proba_1, proba_2) -def test_linear_svm_convergence_warnings(): +def test_linear_svm_convergence_warnings(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # Test that warnings are raised if model does not converge - lsvc = svm.LinearSVC(random_state=0, max_iter=2) + lsvc = svm.LinearSVC(random_state=global_random_seed + 1, max_iter=2) warning_msg = "Liblinear failed to converge, increase the number of iterations." with pytest.warns(ConvergenceWarning, match=warning_msg): lsvc.fit(X, Y) @@ -1063,7 +1086,7 @@ def test_linear_svm_convergence_warnings(): assert isinstance(lsvc.n_iter_, int) assert lsvc.n_iter_ == 2 - lsvr = svm.LinearSVR(random_state=0, max_iter=2) + lsvr = svm.LinearSVR(random_state=global_random_seed + 2, max_iter=2) with pytest.warns(ConvergenceWarning, match=warning_msg): lsvr.fit(iris.data, iris.target) assert isinstance(lsvr.n_iter_, int) @@ -1091,7 +1114,9 @@ def test_lsvc_intercept_scaling_zero(): assert lsvc.intercept_ == 0.0 -def test_hasattr_predict_proba(): +def test_hasattr_predict_proba(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # Method must be (un)available before or after fit, switched by # `probability` param @@ -1115,9 +1140,9 @@ def test_hasattr_predict_proba(): G.predict_proba(iris.data) -def test_decision_function_shape_two_class(): +def test_decision_function_shape_two_class(global_random_seed): for n_classes in [2, 3]: - X, y = make_blobs(centers=n_classes, random_state=0) + X, y = make_blobs(centers=n_classes, random_state=global_random_seed) for estimator in [svm.SVC, svm.NuSVC]: clf = OneVsRestClassifier(estimator(decision_function_shape="ovr")).fit( X, y @@ -1170,11 +1195,11 @@ def test_ovr_decision_function(): @pytest.mark.parametrize("SVCClass", [svm.SVC, svm.NuSVC]) -def test_svc_invalid_break_ties_param(SVCClass): - X, y = make_blobs(random_state=42) +def test_svc_invalid_break_ties_param(SVCClass, global_random_seed): + X, y = make_blobs(random_state=global_random_seed) svm = SVCClass( - kernel="linear", decision_function_shape="ovo", break_ties=True, random_state=42 + kernel="linear", decision_function_shape="ovo", break_ties=True, random_state=global_random_seed + 1 ).fit(X, y) with pytest.raises(ValueError, match="break_ties must be False"): @@ -1182,18 +1207,18 @@ def test_svc_invalid_break_ties_param(SVCClass): @pytest.mark.parametrize("SVCClass", [svm.SVC, svm.NuSVC]) -def test_svc_ovr_tie_breaking(SVCClass): +def test_svc_ovr_tie_breaking(SVCClass, global_random_seed): """Test if predict breaks ties in OVR mode. Related issue: https://github.com/scikit-learn/scikit-learn/issues/8277 """ - X, y = make_blobs(random_state=0, n_samples=20, n_features=2) + X, y = make_blobs(random_state=global_random_seed, n_samples=20, n_features=2) xs = np.linspace(X[:, 0].min(), X[:, 0].max(), 100) ys = np.linspace(X[:, 1].min(), X[:, 1].max(), 100) xx, yy = np.meshgrid(xs, ys) common_params = dict( - kernel="rbf", gamma=1e6, random_state=42, decision_function_shape="ovr" + kernel="rbf", gamma=1e6, random_state=global_random_seed + 1, decision_function_shape="ovr" ) svm = SVCClass( break_ties=False, @@ -1232,7 +1257,7 @@ def test_gamma_scale(): (LinearSVR, {"loss": "squared_epsilon_insensitive", "dual": True}), ], ) -def test_linearsvm_liblinear_sample_weight(SVM, params): +def test_linearsvm_liblinear_sample_weight(SVM, params, global_random_seed): X = np.array( [ [1, 3], @@ -1261,10 +1286,10 @@ def test_linearsvm_liblinear_sample_weight(SVM, params): X2 = np.vstack([X, X]) y2 = np.hstack([y, 3 - y]) sample_weight = np.ones(shape=len(y) * 2) - sample_weight[len(y) :] = 0 - X2, y2, sample_weight = shuffle(X2, y2, sample_weight, random_state=0) + sample_weight[len(y):] = 0 + X2, y2, sample_weight = shuffle(X2, y2, sample_weight, random_state=global_random_seed) - base_estimator = SVM(random_state=42) + base_estimator = SVM(random_state=global_random_seed + 1) base_estimator.set_params(**params) base_estimator.set_params(tol=1e-12, max_iter=1000) est_no_weight = base.clone(base_estimator).fit(X, y) @@ -1355,14 +1380,15 @@ def test_svc_raises_error_internal_representation(): ], ) @pytest.mark.parametrize( - "dataset", + "dataset_params", [ - make_classification(n_classes=2, n_informative=2, random_state=0), - make_classification(n_classes=3, n_informative=3, random_state=0), - make_classification(n_classes=4, n_informative=4, random_state=0), + {"n_classes": 2, "n_informative": 2}, + {"n_classes": 3, "n_informative": 3}, + {"n_classes": 4, "n_informative": 4}, ], ) -def test_n_iter_libsvm(estimator, expected_n_iter_type, dataset): +def test_n_iter_libsvm(estimator, expected_n_iter_type, dataset_params, global_random_seed): + dataset = make_classification(*dataset_params, random_state=global_random_seed) # Check that the type of n_iter_ is correct for the classes that inherit # from BaseSVC. # Note that for SVC, and NuSVC this is an ndarray; while for SVR, NuSVR, and From 49978b7e98ca6c99cd054ab8a765d2801561c388 Mon Sep 17 00:00:00 2001 From: Itay Date: Sat, 15 Apr 2023 17:14:38 +0300 Subject: [PATCH 009/230] multiple test fixes to accommodate the new global_random_seed with lower thresholds and other fixes. --- sklearn/svm/tests/test_svm.py | 68 +++++++++++++++++------------------ 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index 6cd8f0aa85cdb..9a7adbb19c670 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -425,25 +425,28 @@ def test_decision_function_shape(SVM, global_random_seed): # correct shape and is consistent with predict iris = get_iris_dataset(global_random_seed) - clf = SVM(kernel="linear", decision_function_shape="ovr").fit( + linear_ovr_svm = SVM(kernel="linear", decision_function_shape="ovr",random_state=global_random_seed+1, break_ties=True) + # we need to use break_ties here so that the prediction won't break ties randomly but use the argmax of dec. + linear_ovr_svm.fit( iris.data, iris.target ) - dec = clf.decision_function(iris.data) + dec = linear_ovr_svm.decision_function(iris.data) assert dec.shape == (len(iris.data), 3) - assert_array_equal(clf.predict(iris.data), np.argmax(dec, axis=1)) + assert_array_equal(linear_ovr_svm.predict(iris.data), np.argmax(dec, axis=1)) # with five classes: - X, y = make_blobs(n_samples=80, centers=5, random_state=global_random_seed + 1) - X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=global_random_seed + 2) + X, y = make_blobs(n_samples=80, centers=5, random_state=global_random_seed + 2) + X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=global_random_seed + 3) - clf = SVM(kernel="linear", decision_function_shape="ovr").fit(X_train, y_train) - dec = clf.decision_function(X_test) + linear_ovr_svm.fit(X_train, y_train) + dec = linear_ovr_svm.decision_function(X_test) assert dec.shape == (len(X_test), 5) - assert_array_equal(clf.predict(X_test), np.argmax(dec, axis=1)) + assert_array_equal(linear_ovr_svm.predict(X_test), np.argmax(dec, axis=1)) - # check shape of ovo_decition_function=True - clf = SVM(kernel="linear", decision_function_shape="ovo").fit(X_train, y_train) - dec = clf.decision_function(X_train) + # check shape of ovo_decision_function=True + linear_ovo_svm = SVM(kernel="linear", decision_function_shape="ovo",random_state=global_random_seed+4,break_ties=True) + linear_ovo_svm.fit(X_train, y_train) + dec = linear_ovo_svm.decision_function(X_train) assert dec.shape == (len(X_train), 10) @@ -479,7 +482,7 @@ def test_weight(global_random_seed): assert_array_almost_equal(clf.predict(X), [2] * 6) X_, y_ = make_classification( - n_samples=200, n_features=10, weights=[0.833, 0.167], random_state=global_random_seed + n_samples=2000, n_features=10, weights=[0.833, 0.167], random_state=global_random_seed ) for clf in ( @@ -488,9 +491,9 @@ def test_weight(global_random_seed): svm.SVC(), ): clf.set_params(class_weight={0: 0.1, 1: 10}) - clf.fit(X_[:100], y_[:100]) - y_pred = clf.predict(X_[100:]) - assert f1_score(y_[100:], y_pred) > 0.3 + clf.fit(X_[:1000], y_[:1000]) + y_pred = clf.predict(X_[1000:]) + assert f1_score(y_[1000:], y_pred) > 0.25 @pytest.mark.parametrize("estimator", [svm.SVC(C=1e-2), svm.NuSVC()]) @@ -644,7 +647,7 @@ def test_auto_weight(global_random_seed): from sklearn.linear_model import LogisticRegression # We take as dataset the two-dimensional projection of iris so - # that it is not separable and remove half of predictors from + # that it is not separable and remove 30 predictors from # class 1. # We add one to the targets as a non-regression test: # class_weight="balanced" @@ -652,16 +655,16 @@ def test_auto_weight(global_random_seed): from sklearn.utils import compute_class_weight X, y = iris.data[:, :2], iris.target + 1 - unbalanced = np.delete(np.arange(y.size), np.where(y > 2)[0][::2]) + unbalanced = np.delete(np.arange(y.size), np.where(y > 2)[0][:30]) classes = np.unique(y[unbalanced]) class_weights = compute_class_weight("balanced", classes=classes, y=y[unbalanced]) assert np.argmax(class_weights) == 2 for clf in ( - svm.SVC(kernel="linear"), - svm.LinearSVC(random_state=global_random_seed + 1), - LogisticRegression(), + svm.SVC(kernel="linear",random_state=global_random_seed + 1), + svm.LinearSVC(random_state=global_random_seed + 2), + LogisticRegression(random_state=global_random_seed+3), ): # check that score is better when class='balanced' is set. y_pred = clf.fit(X[unbalanced], y[unbalanced]).predict(X) @@ -873,7 +876,7 @@ def test_linearsvc_fit_sampleweight(global_random_seed): def test_crammer_singer_binary(global_random_seed): # Test Crammer-Singer formulation in the binary case - X, y = make_classification(n_classes=2, random_state=global_random_seed) + X, y = make_classification(n_classes=2, random_state=global_random_seed,n_samples=256) for fit_intercept in (True, False): acc = ( @@ -885,7 +888,7 @@ def test_crammer_singer_binary(global_random_seed): .fit(X, y) .score(X, y) ) - assert acc > 0.9 + assert acc > 0.85 def test_linearsvc_iris(global_random_seed): @@ -1067,7 +1070,7 @@ def test_unfitted(): def test_consistent_proba(global_random_seed): a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed) proba_1 = a.fit(X, Y).predict_proba(X) - a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed + 1) + a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed) proba_2 = a.fit(X, Y).predict_proba(X) assert_array_almost_equal(proba_1, proba_2) @@ -1299,9 +1302,9 @@ def test_linearsvm_liblinear_sample_weight(SVM, params, global_random_seed): for method in ("predict", "decision_function"): if hasattr(base_estimator, method): - X_est_no_weight = getattr(est_no_weight, method)(X) - X_est_with_weight = getattr(est_with_weight, method)(X) - assert_allclose(X_est_no_weight, X_est_with_weight) + result_without_weight = getattr(est_no_weight, method)(X) + result_with_weight = getattr(est_with_weight, method)(X) + assert_allclose(result_without_weight, result_with_weight,atol=1e-6) @pytest.mark.parametrize("Klass", (OneClassSVM, SVR, NuSVR)) @@ -1380,15 +1383,10 @@ def test_svc_raises_error_internal_representation(): ], ) @pytest.mark.parametrize( - "dataset_params", - [ - {"n_classes": 2, "n_informative": 2}, - {"n_classes": 3, "n_informative": 3}, - {"n_classes": 4, "n_informative": 4}, - ], -) -def test_n_iter_libsvm(estimator, expected_n_iter_type, dataset_params, global_random_seed): - dataset = make_classification(*dataset_params, random_state=global_random_seed) + "n_classes", + [2, 3, 4], ) +def test_n_iter_libsvm(estimator, expected_n_iter_type, n_classes, global_random_seed): + dataset = make_classification(n_classes=n_classes, n_informative=n_classes, random_state=global_random_seed) # Check that the type of n_iter_ is correct for the classes that inherit # from BaseSVC. # Note that for SVC, and NuSVC this is an ndarray; while for SVR, NuSVR, and From 5d6facecacf4725cf014f16d855f40fb02437edd Mon Sep 17 00:00:00 2001 From: Itay Date: Sat, 15 Apr 2023 17:16:47 +0300 Subject: [PATCH 010/230] using a single RandomState instead of 2 where possible --- sklearn/svm/tests/test_svm.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index 9a7adbb19c670..50f3917689a16 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -315,7 +315,7 @@ def test_oneclass_decision_function(global_random_seed): rng = np.random.RandomState(global_random_seed) N = 1000 # Generate train data - X = 0.3 * rng.randn(5*N, 2) + X = 0.3 * rng.randn(5 * N, 2) import seaborn as sns sns.scatterplot(X) X_train = np.r_[X + 2, X - 2] @@ -1099,8 +1099,9 @@ def test_linear_svm_convergence_warnings(global_random_seed): def test_svr_coef_sign(global_random_seed): # Test that SVR(kernel="linear") has coef_ with the right sign. # Non-regression test for #2933. - X = np.random.RandomState(global_random_seed).randn(10, 3) - y = np.random.RandomState(global_random_seed + 1).randn(10) + rng = np.random.RandomState(global_random_seed) + X = rng.randn(10, 3) + y = rng.randn(10) for svr in [svm.SVR(kernel="linear"), svm.NuSVR(kernel="linear"), svm.LinearSVR()]: svr.fit(X, y) From 1916186e68139618dd5e63d58b42da236f1f83fd Mon Sep 17 00:00:00 2001 From: Itay Date: Sat, 15 Apr 2023 22:37:41 +0300 Subject: [PATCH 011/230] fixed 2 issues after pipeline failed --- sklearn/svm/tests/test_svm.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index 50f3917689a16..babcb857ea132 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -315,9 +315,7 @@ def test_oneclass_decision_function(global_random_seed): rng = np.random.RandomState(global_random_seed) N = 1000 # Generate train data - X = 0.3 * rng.randn(5 * N, 2) - import seaborn as sns - sns.scatterplot(X) + X = 0.3 * rng.randn(5*N, 2) X_train = np.r_[X + 2, X - 2] # Generate some regular novel observations @@ -906,7 +904,7 @@ def test_linearsvc_iris(global_random_seed): assert_array_equal(pred, clf.predict(iris.data)) -def test_dense_liblinear_intercept_handling(global_random_seed, classifier=svm.LinearSVC): +def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC, global_random_seed=42): # Test that dense liblinear honours intercept_scaling param X = [[2, 1], [3, 1], [1, 3], [2, 3]] y = [0, 0, 1, 1] From 7139fda2ca7be17dc5ae3f03c341674c8b7e9678 Mon Sep 17 00:00:00 2001 From: Itay Date: Fri, 17 Mar 2023 17:27:52 +0200 Subject: [PATCH 012/230] global random seed, replaced two functions with static seeds --- sklearn/svm/tests/test_svm.py | 10 +++++----- sklearn/tests/test_naive_bayes.py | 22 ++++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index ca23360f9d462..1bf0eab91b0a5 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -706,9 +706,9 @@ def test_bad_input(): clf.predict(Xt) -def test_svc_nonfinite_params(): +def test_svc_nonfinite_params(global_random_seed): # Check SVC throws ValueError when dealing with non-finite parameter values - rng = np.random.RandomState(0) + rng = np.random.RandomState(global_random_seed) n_samples = 10 fmax = np.finfo(np.float64).max X = fmax * rng.uniform(size=(n_samples, 2)) @@ -1071,11 +1071,11 @@ def test_linear_svm_convergence_warnings(): assert lsvr.n_iter_ == 2 -def test_svr_coef_sign(): +def test_svr_coef_sign(global_random_seed): # Test that SVR(kernel="linear") has coef_ with the right sign. # Non-regression test for #2933. - X = np.random.RandomState(21).randn(10, 3) - y = np.random.RandomState(12).randn(10) + X = np.random.RandomState(global_random_seed).randn(10, 3) + y = np.random.RandomState(global_random_seed + 1).randn(10) for svr in [svm.SVR(kernel="linear"), svm.NuSVR(kernel="linear"), svm.LinearSVR()]: svr.fit(X, y) diff --git a/sklearn/tests/test_naive_bayes.py b/sklearn/tests/test_naive_bayes.py index 4516fabb8961d..c3ba2e653f4b0 100644 --- a/sklearn/tests/test_naive_bayes.py +++ b/sklearn/tests/test_naive_bayes.py @@ -49,6 +49,7 @@ def get_random_integer_x_three_classes_y(global_random_seed): return X2, y2 + def test_gnb(): # Gaussian Naive Bayes classification. # This checks that GaussianNB implements fit and predict and returns @@ -75,7 +76,7 @@ def test_gnb_prior(global_random_seed): # Test whether class priors are properly set. clf = GaussianNB().fit(X, y) assert_array_almost_equal(np.array([3, 3]) / 6.0, clf.class_prior_, 8) - X1, y1 = get_random_normal_x_binary_y(global_random_seed) + X1,y1 = get_random_normal_x_binary_y(global_random_seed) clf = GaussianNB().fit(X1, y1) # Check that the class priors sum to 1 assert_array_almost_equal(clf.class_prior_.sum(), 1) @@ -225,9 +226,9 @@ def test_gnb_naive_bayes_scale_invariance(): @pytest.mark.parametrize("DiscreteNaiveBayes", DISCRETE_NAIVE_BAYES_CLASSES) -def test_discretenb_prior(DiscreteNaiveBayes, global_random_seed): +def test_discretenb_prior(DiscreteNaiveBayes,global_random_seed): # Test whether class priors are properly set. - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) clf = DiscreteNaiveBayes().fit(X2, y2) assert_array_almost_equal( np.log(np.array([2, 2, 2]) / 6.0), clf.class_log_prior_, 8 @@ -285,9 +286,9 @@ def test_discretenb_partial_fit(DiscreteNaiveBayes): @pytest.mark.parametrize("NaiveBayes", ALL_NAIVE_BAYES_CLASSES) -def test_NB_partial_fit_no_first_classes(NaiveBayes, global_random_seed): +def test_NB_partial_fit_no_first_classes(NaiveBayes,global_random_seed): # classes is required for first call to partial fit - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) with pytest.raises( ValueError, match="classes must be passed on the first call to partial_fit." @@ -465,11 +466,11 @@ def test_discretenb_degenerate_one_class_case( @pytest.mark.parametrize("kind", ("dense", "sparse")) -def test_mnnb(kind, global_random_seed): +def test_mnnb(kind,global_random_seed): # Test Multinomial Naive Bayes classification. # This checks that MultinomialNB implements fit and predict and returns # correct values for a simple toy dataset. - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) if kind == "dense": X = X2 @@ -693,7 +694,7 @@ def test_cnb(): def test_categoricalnb(global_random_seed): # Check the ability to predict the training set. clf = CategoricalNB() - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) y_pred = clf.fit(X2, y2).predict(X2) assert_array_equal(y_pred, y2) @@ -800,6 +801,7 @@ def test_categoricalnb_with_min_categories( ], ) def test_categoricalnb_min_categories_errors(min_categories, error_msg): + X = np.array([[0, 0], [0, 1], [0, 0], [1, 1]]) y = np.array([1, 1, 2, 2]) @@ -981,8 +983,8 @@ def test_check_alpha(): @pytest.mark.parametrize("Estimator", ALL_NAIVE_BAYES_CLASSES) -def test_predict_joint_proba(Estimator, global_random_seed): - X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) +def test_predict_joint_proba(Estimator,global_random_seed): + X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) est = Estimator().fit(X2, y2) jll = est.predict_joint_log_proba(X2) log_prob_x = logsumexp(jll, axis=1) From d92a9f7c12b02e21fe7b8f4e0ff541fd258e3290 Mon Sep 17 00:00:00 2001 From: Itay Date: Fri, 17 Mar 2023 17:28:31 +0200 Subject: [PATCH 013/230] revert other changes --- sklearn/tests/test_naive_bayes.py | 48 ++++++++++--------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/sklearn/tests/test_naive_bayes.py b/sklearn/tests/test_naive_bayes.py index c3ba2e653f4b0..979ae4caed407 100644 --- a/sklearn/tests/test_naive_bayes.py +++ b/sklearn/tests/test_naive_bayes.py @@ -31,23 +31,15 @@ X = np.array([[-2, -1], [-1, -1], [-1, -2], [1, 1], [1, 2], [2, 1]]) y = np.array([1, 1, 1, 2, 2, 2]) +# A bit more random tests +rng = np.random.RandomState(0) +X1 = rng.normal(size=(10, 3)) +y1 = (rng.normal(size=(10)) > 0).astype(int) -def get_random_normal_x_binary_y(global_random_seed): - # A bit more random tests - rng = np.random.RandomState(global_random_seed) - X1 = rng.normal(size=(10, 3)) - y1 = (rng.normal(size=10) > 0).astype(int) - return X1, y1 - - -def get_random_integer_x_three_classes_y(global_random_seed): - # Data is 6 random integer points in a 100 dimensional space classified to - # three classes. - rng = np.random.RandomState(global_random_seed) - X2 = rng.randint(5, size=(6, 100)) - y2 = np.array([1, 1, 2, 2, 3, 3]) - return X2, y2 - +# Data is 6 random integer points in a 100 dimensional space classified to +# three classes. +X2 = rng.randint(5, size=(6, 100)) +y2 = np.array([1, 1, 2, 2, 3, 3]) def test_gnb(): @@ -72,17 +64,16 @@ def test_gnb(): GaussianNB().partial_fit(X, y, classes=[0, 1]) -def test_gnb_prior(global_random_seed): +def test_gnb_prior(): # Test whether class priors are properly set. clf = GaussianNB().fit(X, y) assert_array_almost_equal(np.array([3, 3]) / 6.0, clf.class_prior_, 8) - X1,y1 = get_random_normal_x_binary_y(global_random_seed) clf = GaussianNB().fit(X1, y1) # Check that the class priors sum to 1 assert_array_almost_equal(clf.class_prior_.sum(), 1) -def test_gnb_sample_weight(global_random_seed): +def test_gnb_sample_weight(): """Test whether sample weights are properly used in GNB.""" # Sample weights all being 1 should not change results sw = np.ones(6) @@ -94,8 +85,6 @@ def test_gnb_sample_weight(global_random_seed): # Fitting twice with half sample-weights should result # in same result as fitting once with full weights - rng = np.random.RandomState(global_random_seed) - sw = rng.rand(y.shape[0]) clf1 = GaussianNB().fit(X, y, sample_weight=sw) clf2 = GaussianNB().partial_fit(X, y, classes=[1, 2], sample_weight=sw / 2) @@ -226,9 +215,8 @@ def test_gnb_naive_bayes_scale_invariance(): @pytest.mark.parametrize("DiscreteNaiveBayes", DISCRETE_NAIVE_BAYES_CLASSES) -def test_discretenb_prior(DiscreteNaiveBayes,global_random_seed): +def test_discretenb_prior(DiscreteNaiveBayes): # Test whether class priors are properly set. - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) clf = DiscreteNaiveBayes().fit(X2, y2) assert_array_almost_equal( np.log(np.array([2, 2, 2]) / 6.0), clf.class_log_prior_, 8 @@ -286,10 +274,8 @@ def test_discretenb_partial_fit(DiscreteNaiveBayes): @pytest.mark.parametrize("NaiveBayes", ALL_NAIVE_BAYES_CLASSES) -def test_NB_partial_fit_no_first_classes(NaiveBayes,global_random_seed): +def test_NB_partial_fit_no_first_classes(NaiveBayes): # classes is required for first call to partial fit - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) - with pytest.raises( ValueError, match="classes must be passed on the first call to partial_fit." ): @@ -466,11 +452,10 @@ def test_discretenb_degenerate_one_class_case( @pytest.mark.parametrize("kind", ("dense", "sparse")) -def test_mnnb(kind,global_random_seed): +def test_mnnb(kind): # Test Multinomial Naive Bayes classification. # This checks that MultinomialNB implements fit and predict and returns # correct values for a simple toy dataset. - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) if kind == "dense": X = X2 @@ -691,11 +676,9 @@ def test_cnb(): assert_array_almost_equal(clf.feature_log_prob_, normed_weights) -def test_categoricalnb(global_random_seed): +def test_categoricalnb(): # Check the ability to predict the training set. clf = CategoricalNB() - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) - y_pred = clf.fit(X2, y2).predict(X2) assert_array_equal(y_pred, y2) @@ -983,8 +966,7 @@ def test_check_alpha(): @pytest.mark.parametrize("Estimator", ALL_NAIVE_BAYES_CLASSES) -def test_predict_joint_proba(Estimator,global_random_seed): - X2,y2 = get_random_integer_x_three_classes_y(global_random_seed) +def test_predict_joint_proba(Estimator): est = Estimator().fit(X2, y2) jll = est.predict_joint_log_proba(X2) log_prob_x = logsumexp(jll, axis=1) From f5c4771f0a8072c8329fb0047c69033c18f58093 Mon Sep 17 00:00:00 2001 From: Itay Date: Tue, 21 Mar 2023 22:10:28 +0200 Subject: [PATCH 014/230] adding global random seeds instead of static randoms --- sklearn/svm/tests/test_svm.py | 244 +++++++++++++++++++--------------- 1 file changed, 135 insertions(+), 109 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index 1bf0eab91b0a5..dbd013a0ecc32 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -36,12 +36,14 @@ T = [[-1, -1], [2, 2], [3, 2]] true_result = [1, 2, 2] -# also load the iris dataset -iris = datasets.load_iris() -rng = check_random_state(42) -perm = rng.permutation(iris.target.size) -iris.data = iris.data[perm] -iris.target = iris.target[perm] + +def get_iris_dataset(global_random_seed): + iris = datasets.load_iris() + rng = check_random_state(global_random_seed) + perm = rng.permutation(iris.target.size) + iris.data = iris.data[perm] + iris.target = iris.target[perm] + return iris def test_libsvm_parameters(): @@ -54,9 +56,9 @@ def test_libsvm_parameters(): assert_array_equal(clf.predict(X), Y) -def test_libsvm_iris(): +def test_libsvm_iris(global_random_seed): # Check consistency on dataset iris. - + iris = get_iris_dataset(global_random_seed) # shuffle the dataset so that labels are not ordered for k in ("linear", "rbf"): clf = svm.SVC(kernel=k).fit(iris.data, iris.target) @@ -134,7 +136,7 @@ def test_libsvm_iris(): assert_array_equal(pred, pred2) -def test_precomputed(): +def test_precomputed(global_random_seed): # SVC with a precomputed kernel. # We test it with a toy dataset and with iris. clf = svm.SVC(kernel="precomputed") @@ -183,6 +185,7 @@ def kfunc(x, y): # and check parameters against a linear SVC clf = svm.SVC(kernel="precomputed") clf2 = svm.SVC(kernel="linear") + iris = get_iris_dataset(global_random_seed) K = np.dot(iris.data, iris.data.T) clf.fit(K, iris.target) clf2.fit(iris.data, iris.target) @@ -212,11 +215,11 @@ def test_svr(): diabetes = datasets.load_diabetes() for clf in ( - svm.NuSVR(kernel="linear", nu=0.4, C=1.0), - svm.NuSVR(kernel="linear", nu=0.4, C=10.0), - svm.SVR(kernel="linear", C=10.0), - svm.LinearSVR(C=10.0), - svm.LinearSVR(C=10.0), + svm.NuSVR(kernel="linear", nu=0.4, C=1.0), + svm.NuSVR(kernel="linear", nu=0.4, C=10.0), + svm.SVR(kernel="linear", C=10.0), + svm.LinearSVR(C=10.0), + svm.LinearSVR(C=10.0), ): clf.fit(diabetes.data, diabetes.target) assert clf.score(diabetes.data, diabetes.target) > 0.02 @@ -241,7 +244,7 @@ def test_linearsvr(): assert_almost_equal(score1, score2, 2) -def test_linearsvr_fit_sampleweight(): +def test_linearsvr_fit_sampleweight(global_random_seed): # check correct result when sample_weight is 1 # check that SVR(kernel='linear') and LinearSVC() give # comparable results @@ -265,8 +268,8 @@ def test_linearsvr_fit_sampleweight(): # check that fit(X) = fit([X1, X2, X3],sample_weight = [n1, n2, n3]) where # X = X1 repeated n1 times, X2 repeated n2 times and so forth - random_state = check_random_state(0) - random_weight = random_state.randint(0, 10, n_samples) + rng = np.random.RandomState(global_random_seed) + random_weight = rng.randint(0, 10, n_samples) lsvr_unflat = svm.LinearSVR(C=1e3, tol=1e-12, max_iter=10000).fit( diabetes.data, diabetes.target, sample_weight=random_weight ) @@ -307,20 +310,21 @@ def test_oneclass(): (lambda: clf.coef_)() -def test_oneclass_decision_function(): +def test_oneclass_decision_function(global_random_seed): # Test OneClassSVM decision function - clf = svm.OneClassSVM() - rnd = check_random_state(2) - + rng = np.random.RandomState(global_random_seed) + N = 1000 # Generate train data - X = 0.3 * rnd.randn(100, 2) + X = 0.3 * rng.randn(5*N, 2) + import seaborn as sns + sns.scatterplot(X) X_train = np.r_[X + 2, X - 2] # Generate some regular novel observations - X = 0.3 * rnd.randn(20, 2) + X = 0.3 * rng.randn(N, 2) X_test = np.r_[X + 2, X - 2] # Generate some abnormal novel observations - X_outliers = rnd.uniform(low=-4, high=4, size=(20, 2)) + X_outliers = rng.uniform(low=-4, high=4, size=(N, 2)) # fit the model clf = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.1) @@ -328,9 +332,9 @@ def test_oneclass_decision_function(): # predict things y_pred_test = clf.predict(X_test) - assert np.mean(y_pred_test == 1) > 0.9 + assert np.mean(y_pred_test == 1) > 0.85 y_pred_outliers = clf.predict(X_outliers) - assert np.mean(y_pred_outliers == -1) > 0.9 + assert np.mean(y_pred_outliers == -1) > 0.85 dec_func_test = clf.decision_function(X_test) assert_array_equal((dec_func_test > 0).ravel(), y_pred_test == 1) dec_func_outliers = clf.decision_function(X_outliers) @@ -361,13 +365,14 @@ def test_tweak_params(): assert_array_equal(clf.predict([[-0.1, -0.1]]), [2]) -def test_probability(): +def test_probability(global_random_seed): # Predict probabilities using SVC # This uses cross validation, so we use a slightly bigger testing set. + iris = get_iris_dataset(global_random_seed) for clf in ( - svm.SVC(probability=True, random_state=0, C=1.0), - svm.NuSVC(probability=True, random_state=0), + svm.SVC(probability=True, random_state=global_random_seed + 1, C=1.0), + svm.NuSVC(probability=True, random_state=global_random_seed + 2), ): clf.fit(iris.data, iris.target) @@ -380,7 +385,8 @@ def test_probability(): ) -def test_decision_function(): +def test_decision_function(global_random_seed): + iris = get_iris_dataset(global_random_seed) # Test decision_function # Sanity check, test that decision_function implemented in python # returns the same as the one in libsvm @@ -414,9 +420,10 @@ def test_decision_function(): @pytest.mark.parametrize("SVM", (svm.SVC, svm.NuSVC)) -def test_decision_function_shape(SVM): +def test_decision_function_shape(SVM, global_random_seed): # check that decision_function_shape='ovr' or 'ovo' gives # correct shape and is consistent with predict + iris = get_iris_dataset(global_random_seed) clf = SVM(kernel="linear", decision_function_shape="ovr").fit( iris.data, iris.target @@ -426,8 +433,8 @@ def test_decision_function_shape(SVM): assert_array_equal(clf.predict(iris.data), np.argmax(dec, axis=1)) # with five classes: - X, y = make_blobs(n_samples=80, centers=5, random_state=0) - X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0) + X, y = make_blobs(n_samples=80, centers=5, random_state=global_random_seed + 1) + X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=global_random_seed + 2) clf = SVM(kernel="linear", decision_function_shape="ovr").fit(X_train, y_train) dec = clf.decision_function(X_test) @@ -440,10 +447,11 @@ def test_decision_function_shape(SVM): assert dec.shape == (len(X_train), 10) -def test_svr_predict(): +def test_svr_predict(global_random_seed): # Test SVR's decision_function # Sanity check, test that predict implemented in python # returns the same as the one in libsvm + iris = get_iris_dataset(global_random_seed) X = iris.data y = iris.target @@ -462,7 +470,7 @@ def test_svr_predict(): assert_array_almost_equal(dec.ravel(), reg.predict(X).ravel()) -def test_weight(): +def test_weight(global_random_seed): # Test class weights clf = svm.SVC(class_weight={1: 0.1}) # we give a small weights to class 1 @@ -471,13 +479,13 @@ def test_weight(): assert_array_almost_equal(clf.predict(X), [2] * 6) X_, y_ = make_classification( - n_samples=200, n_features=10, weights=[0.833, 0.167], random_state=2 + n_samples=200, n_features=10, weights=[0.833, 0.167], random_state=global_random_seed ) for clf in ( - linear_model.LogisticRegression(), - svm.LinearSVC(random_state=0), - svm.SVC(), + linear_model.LogisticRegression(), + svm.LinearSVC(random_state=global_random_seed + 1), + svm.SVC(), ): clf.set_params(class_weight={0: 0.1, 1: 10}) clf.fit(X_[:100], y_[:100]) @@ -608,7 +616,7 @@ def test_negative_weights_svc_leave_just_one_label(Classifier, err_msg, sample_w ids=["partial-mask-label-1", "partial-mask-label-2"], ) def test_negative_weights_svc_leave_two_labels( - Classifier, model, sample_weight, mask_side + Classifier, model, sample_weight, mask_side ): clf = Classifier(kernel="linear") clf.fit(X, Y, sample_weight=sample_weight) @@ -632,8 +640,9 @@ def test_negative_weight_equal_coeffs(Estimator, sample_weight): @ignore_warnings(category=UndefinedMetricWarning) -def test_auto_weight(): +def test_auto_weight(global_random_seed): # Test class weights for imbalanced data + iris = get_iris_dataset(global_random_seed) from sklearn.linear_model import LogisticRegression # We take as dataset the two-dimensional projection of iris so @@ -652,9 +661,9 @@ def test_auto_weight(): assert np.argmax(class_weights) == 2 for clf in ( - svm.SVC(kernel="linear"), - svm.LinearSVC(random_state=0), - LogisticRegression(), + svm.SVC(kernel="linear"), + svm.LinearSVC(random_state=global_random_seed + 1), + LogisticRegression(), ): # check that score is better when class='balanced' is set. y_pred = clf.fit(X[unbalanced], y[unbalanced]).predict(X) @@ -668,14 +677,14 @@ def test_auto_weight(): ) -def test_bad_input(): +def test_bad_input(global_random_seed): # Test dimensions for labels Y2 = Y[:-1] # wrong dimensions for labels with pytest.raises(ValueError): svm.SVC().fit(X, Y2) # Test with arrays that are non-contiguous. - for clf in (svm.SVC(), svm.LinearSVC(random_state=0)): + for clf in (svm.SVC(), svm.LinearSVC(random_state=global_random_seed)): Xf = np.asfortranarray(X) assert not Xf.flags["C_CONTIGUOUS"] yf = np.ascontiguousarray(np.tile(Y, (2, 1)).T) @@ -720,8 +729,10 @@ def test_svc_nonfinite_params(global_random_seed): clf.fit(X, y) -def test_unicode_kernel(): +def test_unicode_kernel(global_random_seed): # Test that a unicode kernel name does not cause a TypeError + iris = get_iris_dataset(global_random_seed) + clf = svm.SVC(kernel="linear", probability=True) clf.fit(X, Y) clf.predict_proba(T) @@ -752,30 +763,30 @@ def test_sparse_fit_support_vectors_empty(): @pytest.mark.parametrize("loss", ["hinge", "squared_hinge"]) @pytest.mark.parametrize("penalty", ["l1", "l2"]) @pytest.mark.parametrize("dual", [True, False]) -def test_linearsvc_parameters(loss, penalty, dual): +def test_linearsvc_parameters(loss, penalty, dual, global_random_seed): # Test possible parameter combinations in LinearSVC # Generate list of possible parameter combinations - X, y = make_classification(n_samples=5, n_features=5, random_state=0) + X, y = make_classification(n_samples=5, n_features=5, random_state=global_random_seed) - clf = svm.LinearSVC(penalty=penalty, loss=loss, dual=dual, random_state=0) + clf = svm.LinearSVC(penalty=penalty, loss=loss, dual=dual, random_state=global_random_seed + 1) if ( - (loss, penalty) == ("hinge", "l1") - or (loss, penalty, dual) == ("hinge", "l2", False) - or (penalty, dual) == ("l1", True) + (loss, penalty) == ("hinge", "l1") + or (loss, penalty, dual) == ("hinge", "l2", False) + or (penalty, dual) == ("l1", True) ): with pytest.raises( - ValueError, - match="Unsupported set of arguments.*penalty='%s.*loss='%s.*dual=%s" - % (penalty, loss, dual), + ValueError, + match="Unsupported set of arguments.*penalty='%s.*loss='%s.*dual=%s" + % (penalty, loss, dual), ): clf.fit(X, y) else: clf.fit(X, y) -def test_linearsvc(): +def test_linearsvc(global_random_seed): # Test basic routines using LinearSVC - clf = svm.LinearSVC(random_state=0).fit(X, Y) + clf = svm.LinearSVC(random_state=global_random_seed).fit(X, Y) # by default should have intercept assert clf.fit_intercept @@ -785,16 +796,16 @@ def test_linearsvc(): # the same with l1 penalty clf = svm.LinearSVC( - penalty="l1", loss="squared_hinge", dual=False, random_state=0 + penalty="l1", loss="squared_hinge", dual=False, random_state=global_random_seed + 1 ).fit(X, Y) assert_array_equal(clf.predict(T), true_result) # l2 penalty with dual formulation - clf = svm.LinearSVC(penalty="l2", dual=True, random_state=0).fit(X, Y) + clf = svm.LinearSVC(penalty="l2", dual=True, random_state=global_random_seed + 2).fit(X, Y) assert_array_equal(clf.predict(T), true_result) # l2 penalty, l1 loss - clf = svm.LinearSVC(penalty="l2", loss="hinge", dual=True, random_state=0) + clf = svm.LinearSVC(penalty="l2", loss="hinge", dual=True, random_state=global_random_seed + 3) clf.fit(X, Y) assert_array_equal(clf.predict(T), true_result) @@ -804,10 +815,12 @@ def test_linearsvc(): assert_array_equal(res, true_result) -def test_linearsvc_crammer_singer(): +def test_linearsvc_crammer_singer(global_random_seed): # Test LinearSVC with crammer_singer multi-class svm - ovr_clf = svm.LinearSVC(random_state=0).fit(iris.data, iris.target) - cs_clf = svm.LinearSVC(multi_class="crammer_singer", random_state=0) + iris = get_iris_dataset(global_random_seed) + + ovr_clf = svm.LinearSVC(random_state=global_random_seed + 1).fit(iris.data, iris.target) + cs_clf = svm.LinearSVC(multi_class="crammer_singer", random_state=global_random_seed + 2) cs_clf.fit(iris.data, iris.target) # similar prediction for ovr and crammer-singer: @@ -825,12 +838,12 @@ def test_linearsvc_crammer_singer(): assert_array_almost_equal(dec_func, cs_clf.decision_function(iris.data)) -def test_linearsvc_fit_sampleweight(): +def test_linearsvc_fit_sampleweight(global_random_seed): # check correct result when sample_weight is 1 n_samples = len(X) unit_weight = np.ones(n_samples) - clf = svm.LinearSVC(random_state=0).fit(X, Y) - clf_unitweight = svm.LinearSVC(random_state=0, tol=1e-12, max_iter=1000).fit( + clf = svm.LinearSVC(random_state=global_random_seed).fit(X, Y) + clf_unitweight = svm.LinearSVC(random_state=global_random_seed + 1, tol=1e-12, max_iter=1000).fit( X, Y, sample_weight=unit_weight ) @@ -841,16 +854,16 @@ def test_linearsvc_fit_sampleweight(): # check that fit(X) = fit([X1, X2, X3],sample_weight = [n1, n2, n3]) where # X = X1 repeated n1 times, X2 repeated n2 times and so forth - random_state = check_random_state(0) - random_weight = random_state.randint(0, 10, n_samples) - lsvc_unflat = svm.LinearSVC(random_state=0, tol=1e-12, max_iter=1000).fit( + rng = np.random.RandomState(global_random_seed) + random_weight = rng.randint(0, 10, n_samples) + lsvc_unflat = svm.LinearSVC(random_state=global_random_seed + 2, tol=1e-12, max_iter=1000).fit( X, Y, sample_weight=random_weight ) pred1 = lsvc_unflat.predict(T) X_flat = np.repeat(X, random_weight, axis=0) y_flat = np.repeat(Y, random_weight, axis=0) - lsvc_flat = svm.LinearSVC(random_state=0, tol=1e-12, max_iter=1000).fit( + lsvc_flat = svm.LinearSVC(random_state=global_random_seed + 3, tol=1e-12, max_iter=1000).fit( X_flat, y_flat ) pred2 = lsvc_flat.predict(T) @@ -859,16 +872,16 @@ def test_linearsvc_fit_sampleweight(): assert_allclose(lsvc_unflat.coef_, lsvc_flat.coef_, 1, 0.0001) -def test_crammer_singer_binary(): +def test_crammer_singer_binary(global_random_seed): # Test Crammer-Singer formulation in the binary case - X, y = make_classification(n_classes=2, random_state=0) + X, y = make_classification(n_classes=2, random_state=global_random_seed) for fit_intercept in (True, False): acc = ( svm.LinearSVC( fit_intercept=fit_intercept, multi_class="crammer_singer", - random_state=0, + random_state=global_random_seed + 1, ) .fit(X, y) .score(X, y) @@ -876,11 +889,13 @@ def test_crammer_singer_binary(): assert acc > 0.9 -def test_linearsvc_iris(): +def test_linearsvc_iris(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # Test that LinearSVC gives plausible predictions on the iris dataset # Also, test symbolic class names (classes_). target = iris.target_names[iris.target] - clf = svm.LinearSVC(random_state=0).fit(iris.data, target) + clf = svm.LinearSVC(random_state=global_random_seed + 1).fit(iris.data, target) assert set(clf.classes_) == set(iris.target_names) assert np.mean(clf.predict(iris.data) == target) > 0.8 @@ -889,7 +904,7 @@ def test_linearsvc_iris(): assert_array_equal(pred, clf.predict(iris.data)) -def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC): +def test_dense_liblinear_intercept_handling(global_random_seed, classifier=svm.LinearSVC): # Test that dense liblinear honours intercept_scaling param X = [[2, 1], [3, 1], [1, 3], [2, 3]] y = [0, 0, 1, 1] @@ -900,7 +915,7 @@ def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC): dual=False, C=4, tol=1e-7, - random_state=0, + random_state=global_random_seed, ) assert clf.intercept_scaling == 1, clf.intercept_scaling assert clf.fit_intercept @@ -926,7 +941,9 @@ def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC): assert_array_almost_equal(intercept1, intercept2, decimal=2) -def test_liblinear_set_coef(): +def test_liblinear_set_coef(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # multi-class case clf = svm.LinearSVC().fit(iris.data, iris.target) values = clf.decision_function(iris.data) @@ -947,7 +964,9 @@ def test_liblinear_set_coef(): assert_array_equal(values, values2) -def test_immutable_coef_property(): +def test_immutable_coef_property(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # Check that primal coef modification are not silently ignored svms = [ svm.SVC(kernel="linear").fit(iris.data, iris.target), @@ -978,13 +997,15 @@ def test_linearsvc_verbose(): os.dup2(stdout, 1) # restore original stdout -def test_svc_clone_with_callable_kernel(): +def test_svc_clone_with_callable_kernel(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # create SVM with callable linear kernel, check that results are the same # as with built-in linear kernel svm_callable = svm.SVC( kernel=lambda x, y: np.dot(x, y.T), probability=True, - random_state=0, + random_state=global_random_seed + 1, decision_function_shape="ovr", ) # clone for checking clonability with lambda functions.. @@ -992,7 +1013,7 @@ def test_svc_clone_with_callable_kernel(): svm_cloned.fit(iris.data, iris.target) svm_builtin = svm.SVC( - kernel="linear", probability=True, random_state=0, decision_function_shape="ovr" + kernel="linear", probability=True, random_state=global_random_seed + 1, decision_function_shape="ovr" ) svm_builtin.fit(iris.data, iris.target) @@ -1017,9 +1038,9 @@ def test_svc_bad_kernel(): svc.fit(X, Y) -def test_libsvm_convergence_warnings(): +def test_libsvm_convergence_warnings(global_random_seed): a = svm.SVC( - kernel=lambda x, y: np.dot(x, y.T), probability=True, random_state=0, max_iter=2 + kernel=lambda x, y: np.dot(x, y.T), probability=True, random_state=global_random_seed, max_iter=2 ) warning_msg = ( r"Solver terminated early \(max_iter=2\). Consider pre-processing " @@ -1044,18 +1065,20 @@ def test_unfitted(): # ignore convergence warnings from max_iter=1 @ignore_warnings -def test_consistent_proba(): - a = svm.SVC(probability=True, max_iter=1, random_state=0) +def test_consistent_proba(global_random_seed): + a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed) proba_1 = a.fit(X, Y).predict_proba(X) - a = svm.SVC(probability=True, max_iter=1, random_state=0) + a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed + 1) proba_2 = a.fit(X, Y).predict_proba(X) assert_array_almost_equal(proba_1, proba_2) -def test_linear_svm_convergence_warnings(): +def test_linear_svm_convergence_warnings(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # Test that warnings are raised if model does not converge - lsvc = svm.LinearSVC(random_state=0, max_iter=2) + lsvc = svm.LinearSVC(random_state=global_random_seed + 1, max_iter=2) warning_msg = "Liblinear failed to converge, increase the number of iterations." with pytest.warns(ConvergenceWarning, match=warning_msg): lsvc.fit(X, Y) @@ -1064,7 +1087,7 @@ def test_linear_svm_convergence_warnings(): assert isinstance(lsvc.n_iter_, int) assert lsvc.n_iter_ == 2 - lsvr = svm.LinearSVR(random_state=0, max_iter=2) + lsvr = svm.LinearSVR(random_state=global_random_seed + 2, max_iter=2) with pytest.warns(ConvergenceWarning, match=warning_msg): lsvr.fit(iris.data, iris.target) assert isinstance(lsvr.n_iter_, int) @@ -1092,7 +1115,9 @@ def test_lsvc_intercept_scaling_zero(): assert lsvc.intercept_ == 0.0 -def test_hasattr_predict_proba(): +def test_hasattr_predict_proba(global_random_seed): + iris = get_iris_dataset(global_random_seed) + # Method must be (un)available before or after fit, switched by # `probability` param @@ -1116,9 +1141,9 @@ def test_hasattr_predict_proba(): G.predict_proba(iris.data) -def test_decision_function_shape_two_class(): +def test_decision_function_shape_two_class(global_random_seed): for n_classes in [2, 3]: - X, y = make_blobs(centers=n_classes, random_state=0) + X, y = make_blobs(centers=n_classes, random_state=global_random_seed) for estimator in [svm.SVC, svm.NuSVC]: clf = OneVsRestClassifier(estimator(decision_function_shape="ovr")).fit( X, y @@ -1171,11 +1196,11 @@ def test_ovr_decision_function(): @pytest.mark.parametrize("SVCClass", [svm.SVC, svm.NuSVC]) -def test_svc_invalid_break_ties_param(SVCClass): - X, y = make_blobs(random_state=42) +def test_svc_invalid_break_ties_param(SVCClass, global_random_seed): + X, y = make_blobs(random_state=global_random_seed) svm = SVCClass( - kernel="linear", decision_function_shape="ovo", break_ties=True, random_state=42 + kernel="linear", decision_function_shape="ovo", break_ties=True, random_state=global_random_seed + 1 ).fit(X, y) with pytest.raises(ValueError, match="break_ties must be False"): @@ -1183,18 +1208,18 @@ def test_svc_invalid_break_ties_param(SVCClass): @pytest.mark.parametrize("SVCClass", [svm.SVC, svm.NuSVC]) -def test_svc_ovr_tie_breaking(SVCClass): +def test_svc_ovr_tie_breaking(SVCClass, global_random_seed): """Test if predict breaks ties in OVR mode. Related issue: https://github.com/scikit-learn/scikit-learn/issues/8277 """ - X, y = make_blobs(random_state=0, n_samples=20, n_features=2) + X, y = make_blobs(random_state=global_random_seed, n_samples=20, n_features=2) xs = np.linspace(X[:, 0].min(), X[:, 0].max(), 100) ys = np.linspace(X[:, 1].min(), X[:, 1].max(), 100) xx, yy = np.meshgrid(xs, ys) common_params = dict( - kernel="rbf", gamma=1e6, random_state=42, decision_function_shape="ovr" + kernel="rbf", gamma=1e6, random_state=global_random_seed + 1, decision_function_shape="ovr" ) svm = SVCClass( break_ties=False, @@ -1233,7 +1258,7 @@ def test_gamma_scale(): (LinearSVR, {"loss": "squared_epsilon_insensitive", "dual": True}), ], ) -def test_linearsvm_liblinear_sample_weight(SVM, params): +def test_linearsvm_liblinear_sample_weight(SVM, params, global_random_seed): X = np.array( [ [1, 3], @@ -1262,10 +1287,10 @@ def test_linearsvm_liblinear_sample_weight(SVM, params): X2 = np.vstack([X, X]) y2 = np.hstack([y, 3 - y]) sample_weight = np.ones(shape=len(y) * 2) - sample_weight[len(y) :] = 0 - X2, y2, sample_weight = shuffle(X2, y2, sample_weight, random_state=0) + sample_weight[len(y):] = 0 + X2, y2, sample_weight = shuffle(X2, y2, sample_weight, random_state=global_random_seed) - base_estimator = SVM(random_state=42) + base_estimator = SVM(random_state=global_random_seed + 1) base_estimator.set_params(**params) base_estimator.set_params(tol=1e-12, max_iter=1000) est_no_weight = base.clone(base_estimator).fit(X, y) @@ -1356,14 +1381,15 @@ def test_svc_raises_error_internal_representation(): ], ) @pytest.mark.parametrize( - "dataset", + "dataset_params", [ - make_classification(n_classes=2, n_informative=2, random_state=0), - make_classification(n_classes=3, n_informative=3, random_state=0), - make_classification(n_classes=4, n_informative=4, random_state=0), + {"n_classes": 2, "n_informative": 2}, + {"n_classes": 3, "n_informative": 3}, + {"n_classes": 4, "n_informative": 4}, ], ) -def test_n_iter_libsvm(estimator, expected_n_iter_type, dataset): +def test_n_iter_libsvm(estimator, expected_n_iter_type, dataset_params, global_random_seed): + dataset = make_classification(*dataset_params, random_state=global_random_seed) # Check that the type of n_iter_ is correct for the classes that inherit # from BaseSVC. # Note that for SVC, and NuSVC this is an ndarray; while for SVR, NuSVR, and From 563cde5745416d4f7e4b430c6d7b35acc33f974a Mon Sep 17 00:00:00 2001 From: Itay Date: Sat, 15 Apr 2023 17:14:38 +0300 Subject: [PATCH 015/230] multiple test fixes to accommodate the new global_random_seed with lower thresholds and other fixes. --- sklearn/svm/tests/test_svm.py | 68 +++++++++++++++++------------------ 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index dbd013a0ecc32..e2ecc51cfe91f 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -425,25 +425,28 @@ def test_decision_function_shape(SVM, global_random_seed): # correct shape and is consistent with predict iris = get_iris_dataset(global_random_seed) - clf = SVM(kernel="linear", decision_function_shape="ovr").fit( + linear_ovr_svm = SVM(kernel="linear", decision_function_shape="ovr",random_state=global_random_seed+1, break_ties=True) + # we need to use break_ties here so that the prediction won't break ties randomly but use the argmax of dec. + linear_ovr_svm.fit( iris.data, iris.target ) - dec = clf.decision_function(iris.data) + dec = linear_ovr_svm.decision_function(iris.data) assert dec.shape == (len(iris.data), 3) - assert_array_equal(clf.predict(iris.data), np.argmax(dec, axis=1)) + assert_array_equal(linear_ovr_svm.predict(iris.data), np.argmax(dec, axis=1)) # with five classes: - X, y = make_blobs(n_samples=80, centers=5, random_state=global_random_seed + 1) - X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=global_random_seed + 2) + X, y = make_blobs(n_samples=80, centers=5, random_state=global_random_seed + 2) + X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=global_random_seed + 3) - clf = SVM(kernel="linear", decision_function_shape="ovr").fit(X_train, y_train) - dec = clf.decision_function(X_test) + linear_ovr_svm.fit(X_train, y_train) + dec = linear_ovr_svm.decision_function(X_test) assert dec.shape == (len(X_test), 5) - assert_array_equal(clf.predict(X_test), np.argmax(dec, axis=1)) + assert_array_equal(linear_ovr_svm.predict(X_test), np.argmax(dec, axis=1)) - # check shape of ovo_decition_function=True - clf = SVM(kernel="linear", decision_function_shape="ovo").fit(X_train, y_train) - dec = clf.decision_function(X_train) + # check shape of ovo_decision_function=True + linear_ovo_svm = SVM(kernel="linear", decision_function_shape="ovo",random_state=global_random_seed+4,break_ties=True) + linear_ovo_svm.fit(X_train, y_train) + dec = linear_ovo_svm.decision_function(X_train) assert dec.shape == (len(X_train), 10) @@ -479,7 +482,7 @@ def test_weight(global_random_seed): assert_array_almost_equal(clf.predict(X), [2] * 6) X_, y_ = make_classification( - n_samples=200, n_features=10, weights=[0.833, 0.167], random_state=global_random_seed + n_samples=2000, n_features=10, weights=[0.833, 0.167], random_state=global_random_seed ) for clf in ( @@ -488,9 +491,9 @@ def test_weight(global_random_seed): svm.SVC(), ): clf.set_params(class_weight={0: 0.1, 1: 10}) - clf.fit(X_[:100], y_[:100]) - y_pred = clf.predict(X_[100:]) - assert f1_score(y_[100:], y_pred) > 0.3 + clf.fit(X_[:1000], y_[:1000]) + y_pred = clf.predict(X_[1000:]) + assert f1_score(y_[1000:], y_pred) > 0.25 @pytest.mark.parametrize("estimator", [svm.SVC(C=1e-2), svm.NuSVC()]) @@ -646,7 +649,7 @@ def test_auto_weight(global_random_seed): from sklearn.linear_model import LogisticRegression # We take as dataset the two-dimensional projection of iris so - # that it is not separable and remove half of predictors from + # that it is not separable and remove 30 predictors from # class 1. # We add one to the targets as a non-regression test: # class_weight="balanced" @@ -654,16 +657,16 @@ def test_auto_weight(global_random_seed): from sklearn.utils import compute_class_weight X, y = iris.data[:, :2], iris.target + 1 - unbalanced = np.delete(np.arange(y.size), np.where(y > 2)[0][::2]) + unbalanced = np.delete(np.arange(y.size), np.where(y > 2)[0][:30]) classes = np.unique(y[unbalanced]) class_weights = compute_class_weight("balanced", classes=classes, y=y[unbalanced]) assert np.argmax(class_weights) == 2 for clf in ( - svm.SVC(kernel="linear"), - svm.LinearSVC(random_state=global_random_seed + 1), - LogisticRegression(), + svm.SVC(kernel="linear",random_state=global_random_seed + 1), + svm.LinearSVC(random_state=global_random_seed + 2), + LogisticRegression(random_state=global_random_seed+3), ): # check that score is better when class='balanced' is set. y_pred = clf.fit(X[unbalanced], y[unbalanced]).predict(X) @@ -874,7 +877,7 @@ def test_linearsvc_fit_sampleweight(global_random_seed): def test_crammer_singer_binary(global_random_seed): # Test Crammer-Singer formulation in the binary case - X, y = make_classification(n_classes=2, random_state=global_random_seed) + X, y = make_classification(n_classes=2, random_state=global_random_seed,n_samples=256) for fit_intercept in (True, False): acc = ( @@ -886,7 +889,7 @@ def test_crammer_singer_binary(global_random_seed): .fit(X, y) .score(X, y) ) - assert acc > 0.9 + assert acc > 0.85 def test_linearsvc_iris(global_random_seed): @@ -1068,7 +1071,7 @@ def test_unfitted(): def test_consistent_proba(global_random_seed): a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed) proba_1 = a.fit(X, Y).predict_proba(X) - a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed + 1) + a = svm.SVC(probability=True, max_iter=1, random_state=global_random_seed) proba_2 = a.fit(X, Y).predict_proba(X) assert_array_almost_equal(proba_1, proba_2) @@ -1300,9 +1303,9 @@ def test_linearsvm_liblinear_sample_weight(SVM, params, global_random_seed): for method in ("predict", "decision_function"): if hasattr(base_estimator, method): - X_est_no_weight = getattr(est_no_weight, method)(X) - X_est_with_weight = getattr(est_with_weight, method)(X) - assert_allclose(X_est_no_weight, X_est_with_weight) + result_without_weight = getattr(est_no_weight, method)(X) + result_with_weight = getattr(est_with_weight, method)(X) + assert_allclose(result_without_weight, result_with_weight,atol=1e-6) @pytest.mark.parametrize("Klass", (OneClassSVM, SVR, NuSVR)) @@ -1381,15 +1384,10 @@ def test_svc_raises_error_internal_representation(): ], ) @pytest.mark.parametrize( - "dataset_params", - [ - {"n_classes": 2, "n_informative": 2}, - {"n_classes": 3, "n_informative": 3}, - {"n_classes": 4, "n_informative": 4}, - ], -) -def test_n_iter_libsvm(estimator, expected_n_iter_type, dataset_params, global_random_seed): - dataset = make_classification(*dataset_params, random_state=global_random_seed) + "n_classes", + [2, 3, 4], ) +def test_n_iter_libsvm(estimator, expected_n_iter_type, n_classes, global_random_seed): + dataset = make_classification(n_classes=n_classes, n_informative=n_classes, random_state=global_random_seed) # Check that the type of n_iter_ is correct for the classes that inherit # from BaseSVC. # Note that for SVC, and NuSVC this is an ndarray; while for SVR, NuSVR, and From e906f25a235abce586529155894bbf3cbaae6569 Mon Sep 17 00:00:00 2001 From: Itay Date: Sat, 15 Apr 2023 17:16:47 +0300 Subject: [PATCH 016/230] using a single RandomState instead of 2 where possible --- sklearn/svm/tests/test_svm.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index e2ecc51cfe91f..8fcb18e9b6843 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -315,7 +315,7 @@ def test_oneclass_decision_function(global_random_seed): rng = np.random.RandomState(global_random_seed) N = 1000 # Generate train data - X = 0.3 * rng.randn(5*N, 2) + X = 0.3 * rng.randn(5 * N, 2) import seaborn as sns sns.scatterplot(X) X_train = np.r_[X + 2, X - 2] @@ -1100,8 +1100,9 @@ def test_linear_svm_convergence_warnings(global_random_seed): def test_svr_coef_sign(global_random_seed): # Test that SVR(kernel="linear") has coef_ with the right sign. # Non-regression test for #2933. - X = np.random.RandomState(global_random_seed).randn(10, 3) - y = np.random.RandomState(global_random_seed + 1).randn(10) + rng = np.random.RandomState(global_random_seed) + X = rng.randn(10, 3) + y = rng.randn(10) for svr in [svm.SVR(kernel="linear"), svm.NuSVR(kernel="linear"), svm.LinearSVR()]: svr.fit(X, y) From d993d27050e35ace3947f510061e1fa157dae0b7 Mon Sep 17 00:00:00 2001 From: Itay Date: Sat, 15 Apr 2023 22:37:41 +0300 Subject: [PATCH 017/230] fixed 2 issues after pipeline failed --- sklearn/svm/tests/test_svm.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index 8fcb18e9b6843..f9d73ca85a628 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -315,9 +315,7 @@ def test_oneclass_decision_function(global_random_seed): rng = np.random.RandomState(global_random_seed) N = 1000 # Generate train data - X = 0.3 * rng.randn(5 * N, 2) - import seaborn as sns - sns.scatterplot(X) + X = 0.3 * rng.randn(5*N, 2) X_train = np.r_[X + 2, X - 2] # Generate some regular novel observations @@ -907,7 +905,7 @@ def test_linearsvc_iris(global_random_seed): assert_array_equal(pred, clf.predict(iris.data)) -def test_dense_liblinear_intercept_handling(global_random_seed, classifier=svm.LinearSVC): +def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC, global_random_seed=42): # Test that dense liblinear honours intercept_scaling param X = [[2, 1], [3, 1], [1, 3], [2, 3]] y = [0, 0, 1, 1] From 9e36903f7008e9ca3314c3396bf8715d2be48539 Mon Sep 17 00:00:00 2001 From: Itay Date: Sat, 15 Apr 2023 22:53:54 +0300 Subject: [PATCH 018/230] black plugin --- sklearn/svm/tests/test_svm.py | 165 ++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 57 deletions(-) diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py index 11f316a51775c..fe0a76c79c471 100644 --- a/sklearn/svm/tests/test_svm.py +++ b/sklearn/svm/tests/test_svm.py @@ -215,11 +215,11 @@ def test_svr(): diabetes = datasets.load_diabetes() for clf in ( - svm.NuSVR(kernel="linear", nu=0.4, C=1.0), - svm.NuSVR(kernel="linear", nu=0.4, C=10.0), - svm.SVR(kernel="linear", C=10.0), - svm.LinearSVR(C=10.0), - svm.LinearSVR(C=10.0), + svm.NuSVR(kernel="linear", nu=0.4, C=1.0), + svm.NuSVR(kernel="linear", nu=0.4, C=10.0), + svm.SVR(kernel="linear", C=10.0), + svm.LinearSVR(C=10.0), + svm.LinearSVR(C=10.0), ): clf.fit(diabetes.data, diabetes.target) assert clf.score(diabetes.data, diabetes.target) > 0.02 @@ -315,7 +315,7 @@ def test_oneclass_decision_function(global_random_seed): rng = np.random.RandomState(global_random_seed) N = 1000 # Generate train data - X = 0.3 * rng.randn(5*N, 2) + X = 0.3 * rng.randn(5 * N, 2) X_train = np.r_[X + 2, X - 2] # Generate some regular novel observations @@ -369,8 +369,8 @@ def test_probability(global_random_seed): iris = get_iris_dataset(global_random_seed) for clf in ( - svm.SVC(probability=True, random_state=global_random_seed + 1, C=1.0), - svm.NuSVC(probability=True, random_state=global_random_seed + 2), + svm.SVC(probability=True, random_state=global_random_seed + 1, C=1.0), + svm.NuSVC(probability=True, random_state=global_random_seed + 2), ): clf.fit(iris.data, iris.target) @@ -423,18 +423,23 @@ def test_decision_function_shape(SVM, global_random_seed): # correct shape and is consistent with predict iris = get_iris_dataset(global_random_seed) - linear_ovr_svm = SVM(kernel="linear", decision_function_shape="ovr",random_state=global_random_seed+1, break_ties=True) - # we need to use break_ties here so that the prediction won't break ties randomly but use the argmax of dec. - linear_ovr_svm.fit( - iris.data, iris.target + linear_ovr_svm = SVM( + kernel="linear", + decision_function_shape="ovr", + random_state=global_random_seed + 1, + break_ties=True, ) + # we need to use break_ties here so that the prediction won't break ties randomly but use the argmax of dec. + linear_ovr_svm.fit(iris.data, iris.target) dec = linear_ovr_svm.decision_function(iris.data) assert dec.shape == (len(iris.data), 3) assert_array_equal(linear_ovr_svm.predict(iris.data), np.argmax(dec, axis=1)) # with five classes: X, y = make_blobs(n_samples=80, centers=5, random_state=global_random_seed + 2) - X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=global_random_seed + 3) + X_train, X_test, y_train, y_test = train_test_split( + X, y, random_state=global_random_seed + 3 + ) linear_ovr_svm.fit(X_train, y_train) dec = linear_ovr_svm.decision_function(X_test) @@ -442,7 +447,12 @@ def test_decision_function_shape(SVM, global_random_seed): assert_array_equal(linear_ovr_svm.predict(X_test), np.argmax(dec, axis=1)) # check shape of ovo_decision_function=True - linear_ovo_svm = SVM(kernel="linear", decision_function_shape="ovo",random_state=global_random_seed+4,break_ties=True) + linear_ovo_svm = SVM( + kernel="linear", + decision_function_shape="ovo", + random_state=global_random_seed + 4, + break_ties=True, + ) linear_ovo_svm.fit(X_train, y_train) dec = linear_ovo_svm.decision_function(X_train) assert dec.shape == (len(X_train), 10) @@ -480,13 +490,16 @@ def test_weight(global_random_seed): assert_array_almost_equal(clf.predict(X), [2] * 6) X_, y_ = make_classification( - n_samples=2000, n_features=10, weights=[0.833, 0.167], random_state=global_random_seed + n_samples=2000, + n_features=10, + weights=[0.833, 0.167], + random_state=global_random_seed, ) for clf in ( - linear_model.LogisticRegression(), - svm.LinearSVC(random_state=global_random_seed + 1), - svm.SVC(), + linear_model.LogisticRegression(), + svm.LinearSVC(random_state=global_random_seed + 1), + svm.SVC(), ): clf.set_params(class_weight={0: 0.1, 1: 10}) clf.fit(X_[:1000], y_[:1000]) @@ -582,9 +595,11 @@ def test_negative_sample_weights_mask_all_samples(Estimator, err_msg, sample_wei "Classifier, err_msg", [ ( - svm.SVC, + svm.SVC, + ( "Invalid input - all samples with positive weights belong to the same" - " class", + " class" + ), ), (svm.NuSVC, "specified nu is infeasible"), ], @@ -615,7 +630,7 @@ def test_negative_weights_svc_leave_just_one_label(Classifier, err_msg, sample_w ids=["partial-mask-label-1", "partial-mask-label-2"], ) def test_negative_weights_svc_leave_two_labels( - Classifier, model, sample_weight, mask_side + Classifier, model, sample_weight, mask_side ): clf = Classifier(kernel="linear") clf.fit(X, Y, sample_weight=sample_weight) @@ -660,9 +675,9 @@ def test_auto_weight(global_random_seed): assert np.argmax(class_weights) == 2 for clf in ( - svm.SVC(kernel="linear",random_state=global_random_seed + 1), - svm.LinearSVC(random_state=global_random_seed + 2), - LogisticRegression(random_state=global_random_seed+3), + svm.SVC(kernel="linear", random_state=global_random_seed + 1), + svm.LinearSVC(random_state=global_random_seed + 2), + LogisticRegression(random_state=global_random_seed + 3), ): # check that score is better when class='balanced' is set. y_pred = clf.fit(X[unbalanced], y[unbalanced]).predict(X) @@ -765,18 +780,22 @@ def test_sparse_fit_support_vectors_empty(): def test_linearsvc_parameters(loss, penalty, dual, global_random_seed): # Test possible parameter combinations in LinearSVC # Generate list of possible parameter combinations - X, y = make_classification(n_samples=5, n_features=5, random_state=global_random_seed) + X, y = make_classification( + n_samples=5, n_features=5, random_state=global_random_seed + ) - clf = svm.LinearSVC(penalty=penalty, loss=loss, dual=dual, random_state=global_random_seed + 1) + clf = svm.LinearSVC( + penalty=penalty, loss=loss, dual=dual, random_state=global_random_seed + 1 + ) if ( - (loss, penalty) == ("hinge", "l1") - or (loss, penalty, dual) == ("hinge", "l2", False) - or (penalty, dual) == ("l1", True) + (loss, penalty) == ("hinge", "l1") + or (loss, penalty, dual) == ("hinge", "l2", False) + or (penalty, dual) == ("l1", True) ): with pytest.raises( - ValueError, - match="Unsupported set of arguments.*penalty='%s.*loss='%s.*dual=%s" - % (penalty, loss, dual), + ValueError, + match="Unsupported set of arguments.*penalty='%s.*loss='%s.*dual=%s" + % (penalty, loss, dual), ): clf.fit(X, y) else: @@ -795,16 +814,23 @@ def test_linearsvc(global_random_seed): # the same with l1 penalty clf = svm.LinearSVC( - penalty="l1", loss="squared_hinge", dual=False, random_state=global_random_seed + 1 + penalty="l1", + loss="squared_hinge", + dual=False, + random_state=global_random_seed + 1, ).fit(X, Y) assert_array_equal(clf.predict(T), true_result) # l2 penalty with dual formulation - clf = svm.LinearSVC(penalty="l2", dual=True, random_state=global_random_seed + 2).fit(X, Y) + clf = svm.LinearSVC( + penalty="l2", dual=True, random_state=global_random_seed + 2 + ).fit(X, Y) assert_array_equal(clf.predict(T), true_result) # l2 penalty, l1 loss - clf = svm.LinearSVC(penalty="l2", loss="hinge", dual=True, random_state=global_random_seed + 3) + clf = svm.LinearSVC( + penalty="l2", loss="hinge", dual=True, random_state=global_random_seed + 3 + ) clf.fit(X, Y) assert_array_equal(clf.predict(T), true_result) @@ -818,8 +844,12 @@ def test_linearsvc_crammer_singer(global_random_seed): # Test LinearSVC with crammer_singer multi-class svm iris = get_iris_dataset(global_random_seed) - ovr_clf = svm.LinearSVC(random_state=global_random_seed + 1).fit(iris.data, iris.target) - cs_clf = svm.LinearSVC(multi_class="crammer_singer", random_state=global_random_seed + 2) + ovr_clf = svm.LinearSVC(random_state=global_random_seed + 1).fit( + iris.data, iris.target + ) + cs_clf = svm.LinearSVC( + multi_class="crammer_singer", random_state=global_random_seed + 2 + ) cs_clf.fit(iris.data, iris.target) # similar prediction for ovr and crammer-singer: @@ -842,9 +872,9 @@ def test_linearsvc_fit_sampleweight(global_random_seed): n_samples = len(X) unit_weight = np.ones(n_samples) clf = svm.LinearSVC(random_state=global_random_seed).fit(X, Y) - clf_unitweight = svm.LinearSVC(random_state=global_random_seed + 1, tol=1e-12, max_iter=1000).fit( - X, Y, sample_weight=unit_weight - ) + clf_unitweight = svm.LinearSVC( + random_state=global_random_seed + 1, tol=1e-12, max_iter=1000 + ).fit(X, Y, sample_weight=unit_weight) # check if same as sample_weight=None assert_array_equal(clf_unitweight.predict(T), clf.predict(T)) @@ -855,16 +885,16 @@ def test_linearsvc_fit_sampleweight(global_random_seed): rng = np.random.RandomState(global_random_seed) random_weight = rng.randint(0, 10, n_samples) - lsvc_unflat = svm.LinearSVC(random_state=global_random_seed + 2, tol=1e-12, max_iter=1000).fit( - X, Y, sample_weight=random_weight - ) + lsvc_unflat = svm.LinearSVC( + random_state=global_random_seed + 2, tol=1e-12, max_iter=1000 + ).fit(X, Y, sample_weight=random_weight) pred1 = lsvc_unflat.predict(T) X_flat = np.repeat(X, random_weight, axis=0) y_flat = np.repeat(Y, random_weight, axis=0) - lsvc_flat = svm.LinearSVC(random_state=global_random_seed + 3, tol=1e-12, max_iter=1000).fit( - X_flat, y_flat - ) + lsvc_flat = svm.LinearSVC( + random_state=global_random_seed + 3, tol=1e-12, max_iter=1000 + ).fit(X_flat, y_flat) pred2 = lsvc_flat.predict(T) assert_array_equal(pred1, pred2) @@ -873,7 +903,9 @@ def test_linearsvc_fit_sampleweight(global_random_seed): def test_crammer_singer_binary(global_random_seed): # Test Crammer-Singer formulation in the binary case - X, y = make_classification(n_classes=2, random_state=global_random_seed,n_samples=256) + X, y = make_classification( + n_classes=2, random_state=global_random_seed, n_samples=256 + ) for fit_intercept in (True, False): acc = ( @@ -903,7 +935,9 @@ def test_linearsvc_iris(global_random_seed): assert_array_equal(pred, clf.predict(iris.data)) -def test_dense_liblinear_intercept_handling(classifier=svm.LinearSVC, global_random_seed=42): +def test_dense_liblinear_intercept_handling( + classifier=svm.LinearSVC, global_random_seed=42 +): # Test that dense liblinear honours intercept_scaling param X = [[2, 1], [3, 1], [1, 3], [2, 3]] y = [0, 0, 1, 1] @@ -1012,7 +1046,10 @@ def test_svc_clone_with_callable_kernel(global_random_seed): svm_cloned.fit(iris.data, iris.target) svm_builtin = svm.SVC( - kernel="linear", probability=True, random_state=global_random_seed + 1, decision_function_shape="ovr" + kernel="linear", + probability=True, + random_state=global_random_seed + 1, + decision_function_shape="ovr", ) svm_builtin.fit(iris.data, iris.target) @@ -1039,7 +1076,10 @@ def test_svc_bad_kernel(): def test_libsvm_convergence_warnings(global_random_seed): a = svm.SVC( - kernel=lambda x, y: np.dot(x, y.T), probability=True, random_state=global_random_seed, max_iter=2 + kernel=lambda x, y: np.dot(x, y.T), + probability=True, + random_state=global_random_seed, + max_iter=2, ) warning_msg = ( r"Solver terminated early \(max_iter=2\). Consider pre-processing " @@ -1200,7 +1240,10 @@ def test_svc_invalid_break_ties_param(SVCClass, global_random_seed): X, y = make_blobs(random_state=global_random_seed) svm = SVCClass( - kernel="linear", decision_function_shape="ovo", break_ties=True, random_state=global_random_seed + 1 + kernel="linear", + decision_function_shape="ovo", + break_ties=True, + random_state=global_random_seed + 1, ).fit(X, y) with pytest.raises(ValueError, match="break_ties must be False"): @@ -1219,7 +1262,10 @@ def test_svc_ovr_tie_breaking(SVCClass, global_random_seed): xx, yy = np.meshgrid(xs, ys) common_params = dict( - kernel="rbf", gamma=1e6, random_state=global_random_seed + 1, decision_function_shape="ovr" + kernel="rbf", + gamma=1e6, + random_state=global_random_seed + 1, + decision_function_shape="ovr", ) svm = SVCClass( break_ties=False, @@ -1287,8 +1333,10 @@ def test_linearsvm_liblinear_sample_weight(SVM, params, global_random_seed): X2 = np.vstack([X, X]) y2 = np.hstack([y, 3 - y]) sample_weight = np.ones(shape=len(y) * 2) - sample_weight[len(y):] = 0 - X2, y2, sample_weight = shuffle(X2, y2, sample_weight, random_state=global_random_seed) + sample_weight[len(y) :] = 0 + X2, y2, sample_weight = shuffle( + X2, y2, sample_weight, random_state=global_random_seed + ) base_estimator = SVM(random_state=global_random_seed + 1) base_estimator.set_params(**params) @@ -1302,7 +1350,7 @@ def test_linearsvm_liblinear_sample_weight(SVM, params, global_random_seed): if hasattr(base_estimator, method): result_without_weight = getattr(est_no_weight, method)(X) result_with_weight = getattr(est_with_weight, method)(X) - assert_allclose(result_without_weight, result_with_weight,atol=1e-6) + assert_allclose(result_without_weight, result_with_weight, atol=1e-6) @pytest.mark.parametrize("Klass", (OneClassSVM, SVR, NuSVR)) @@ -1382,9 +1430,12 @@ def test_svc_raises_error_internal_representation(): ) @pytest.mark.parametrize( "n_classes", - [2, 3, 4], ) + [2, 3, 4], +) def test_n_iter_libsvm(estimator, expected_n_iter_type, n_classes, global_random_seed): - dataset = make_classification(n_classes=n_classes, n_informative=n_classes, random_state=global_random_seed) + dataset = make_classification( + n_classes=n_classes, n_informative=n_classes, random_state=global_random_seed + ) # Check that the type of n_iter_ is correct for the classes that inherit # from BaseSVC. # Note that for SVC, and NuSVC this is an ndarray; while for SVR, NuSVR, and From 7d975380087a04264c74d84b4399711ee2d18361 Mon Sep 17 00:00:00 2001 From: Itay Date: Sat, 15 Apr 2023 22:57:36 +0300 Subject: [PATCH 019/230] revert NB --- sklearn/tests/test_naive_bayes.py | 48 ++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/sklearn/tests/test_naive_bayes.py b/sklearn/tests/test_naive_bayes.py index 979ae4caed407..4516fabb8961d 100644 --- a/sklearn/tests/test_naive_bayes.py +++ b/sklearn/tests/test_naive_bayes.py @@ -31,15 +31,22 @@ X = np.array([[-2, -1], [-1, -1], [-1, -2], [1, 1], [1, 2], [2, 1]]) y = np.array([1, 1, 1, 2, 2, 2]) -# A bit more random tests -rng = np.random.RandomState(0) -X1 = rng.normal(size=(10, 3)) -y1 = (rng.normal(size=(10)) > 0).astype(int) -# Data is 6 random integer points in a 100 dimensional space classified to -# three classes. -X2 = rng.randint(5, size=(6, 100)) -y2 = np.array([1, 1, 2, 2, 3, 3]) +def get_random_normal_x_binary_y(global_random_seed): + # A bit more random tests + rng = np.random.RandomState(global_random_seed) + X1 = rng.normal(size=(10, 3)) + y1 = (rng.normal(size=10) > 0).astype(int) + return X1, y1 + + +def get_random_integer_x_three_classes_y(global_random_seed): + # Data is 6 random integer points in a 100 dimensional space classified to + # three classes. + rng = np.random.RandomState(global_random_seed) + X2 = rng.randint(5, size=(6, 100)) + y2 = np.array([1, 1, 2, 2, 3, 3]) + return X2, y2 def test_gnb(): @@ -64,16 +71,17 @@ def test_gnb(): GaussianNB().partial_fit(X, y, classes=[0, 1]) -def test_gnb_prior(): +def test_gnb_prior(global_random_seed): # Test whether class priors are properly set. clf = GaussianNB().fit(X, y) assert_array_almost_equal(np.array([3, 3]) / 6.0, clf.class_prior_, 8) + X1, y1 = get_random_normal_x_binary_y(global_random_seed) clf = GaussianNB().fit(X1, y1) # Check that the class priors sum to 1 assert_array_almost_equal(clf.class_prior_.sum(), 1) -def test_gnb_sample_weight(): +def test_gnb_sample_weight(global_random_seed): """Test whether sample weights are properly used in GNB.""" # Sample weights all being 1 should not change results sw = np.ones(6) @@ -85,6 +93,8 @@ def test_gnb_sample_weight(): # Fitting twice with half sample-weights should result # in same result as fitting once with full weights + rng = np.random.RandomState(global_random_seed) + sw = rng.rand(y.shape[0]) clf1 = GaussianNB().fit(X, y, sample_weight=sw) clf2 = GaussianNB().partial_fit(X, y, classes=[1, 2], sample_weight=sw / 2) @@ -215,8 +225,9 @@ def test_gnb_naive_bayes_scale_invariance(): @pytest.mark.parametrize("DiscreteNaiveBayes", DISCRETE_NAIVE_BAYES_CLASSES) -def test_discretenb_prior(DiscreteNaiveBayes): +def test_discretenb_prior(DiscreteNaiveBayes, global_random_seed): # Test whether class priors are properly set. + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) clf = DiscreteNaiveBayes().fit(X2, y2) assert_array_almost_equal( np.log(np.array([2, 2, 2]) / 6.0), clf.class_log_prior_, 8 @@ -274,8 +285,10 @@ def test_discretenb_partial_fit(DiscreteNaiveBayes): @pytest.mark.parametrize("NaiveBayes", ALL_NAIVE_BAYES_CLASSES) -def test_NB_partial_fit_no_first_classes(NaiveBayes): +def test_NB_partial_fit_no_first_classes(NaiveBayes, global_random_seed): # classes is required for first call to partial fit + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + with pytest.raises( ValueError, match="classes must be passed on the first call to partial_fit." ): @@ -452,10 +465,11 @@ def test_discretenb_degenerate_one_class_case( @pytest.mark.parametrize("kind", ("dense", "sparse")) -def test_mnnb(kind): +def test_mnnb(kind, global_random_seed): # Test Multinomial Naive Bayes classification. # This checks that MultinomialNB implements fit and predict and returns # correct values for a simple toy dataset. + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) if kind == "dense": X = X2 @@ -676,9 +690,11 @@ def test_cnb(): assert_array_almost_equal(clf.feature_log_prob_, normed_weights) -def test_categoricalnb(): +def test_categoricalnb(global_random_seed): # Check the ability to predict the training set. clf = CategoricalNB() + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + y_pred = clf.fit(X2, y2).predict(X2) assert_array_equal(y_pred, y2) @@ -784,7 +800,6 @@ def test_categoricalnb_with_min_categories( ], ) def test_categoricalnb_min_categories_errors(min_categories, error_msg): - X = np.array([[0, 0], [0, 1], [0, 0], [1, 1]]) y = np.array([1, 1, 2, 2]) @@ -966,7 +981,8 @@ def test_check_alpha(): @pytest.mark.parametrize("Estimator", ALL_NAIVE_BAYES_CLASSES) -def test_predict_joint_proba(Estimator): +def test_predict_joint_proba(Estimator, global_random_seed): + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) est = Estimator().fit(X2, y2) jll = est.predict_joint_log_proba(X2) log_prob_x = logsumexp(jll, axis=1) From 2bd2d1cbf0cbaa053d2e433b2268d7943205a865 Mon Sep 17 00:00:00 2001 From: "Thomas J. Fan" Date: Mon, 13 Mar 2023 05:06:01 -0400 Subject: [PATCH 020/230] DOC Allows section links to be visible when linked (#25783) --- doc/themes/scikit-learn-modern/static/css/theme.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/themes/scikit-learn-modern/static/css/theme.css b/doc/themes/scikit-learn-modern/static/css/theme.css index 50644e59a25bf..90cfeb9300490 100644 --- a/doc/themes/scikit-learn-modern/static/css/theme.css +++ b/doc/themes/scikit-learn-modern/static/css/theme.css @@ -395,6 +395,15 @@ a.sk-footer-funding-link:hover { width: 100%; } +/* Enables section links to be visible when anchor-linked */ +section[id]::before { + display: block; + height: 52px; + margin-top: -52px; + visibility: hidden; + content: ""; +} + div.sk-page-content { background-color: white; position: relative; From 1253b8eaa0cec9a6877ceafc5ebf8479f514b3f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= Date: Mon, 13 Mar 2023 11:26:37 +0100 Subject: [PATCH 021/230] MNT Fix Pyodide build errors due to incompatible function pointer types (#25831) --- sklearn/svm/_liblinear.pxi | 8 ++++---- sklearn/svm/_libsvm.pxi | 2 +- sklearn/svm/_libsvm_sparse.pyx | 2 +- sklearn/svm/src/liblinear/_cython_blas_helpers.h | 8 ++++---- sklearn/svm/src/libsvm/_svm_cython_blas_helpers.h | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sklearn/svm/_liblinear.pxi b/sklearn/svm/_liblinear.pxi index 569fe5b8a88b5..1a874ba4cbf9c 100644 --- a/sklearn/svm/_liblinear.pxi +++ b/sklearn/svm/_liblinear.pxi @@ -1,8 +1,8 @@ cdef extern from "_cython_blas_helpers.h": - ctypedef double (*dot_func)(int, double*, int, double*, int) - ctypedef void (*axpy_func)(int, double, double*, int, double*, int) - ctypedef void (*scal_func)(int, double, double*, int) - ctypedef double (*nrm2_func)(int, double*, int) + ctypedef double (*dot_func)(int, const double*, int, const double*, int) + ctypedef void (*axpy_func)(int, double, const double*, int, double*, int) + ctypedef void (*scal_func)(int, double, const double*, int) + ctypedef double (*nrm2_func)(int, const double*, int) cdef struct BlasFunctions: dot_func dot axpy_func axpy diff --git a/sklearn/svm/_libsvm.pxi b/sklearn/svm/_libsvm.pxi index f97a21ad50da5..8f1250d884687 100644 --- a/sklearn/svm/_libsvm.pxi +++ b/sklearn/svm/_libsvm.pxi @@ -1,7 +1,7 @@ ################################################################################ # Includes cdef extern from "_svm_cython_blas_helpers.h": - ctypedef double (*dot_func)(int, double*, int, double*, int) + ctypedef double (*dot_func)(int, const double*, int, const double*, int) cdef struct BlasFunctions: dot_func dot diff --git a/sklearn/svm/_libsvm_sparse.pyx b/sklearn/svm/_libsvm_sparse.pyx index ffef617a70e6e..37619f399988c 100644 --- a/sklearn/svm/_libsvm_sparse.pyx +++ b/sklearn/svm/_libsvm_sparse.pyx @@ -11,7 +11,7 @@ cdef extern from *: # Includes cdef extern from "_svm_cython_blas_helpers.h": - ctypedef double (*dot_func)(int, double*, int, double*, int) + ctypedef double (*dot_func)(int, const double*, int, const double*, int) cdef struct BlasFunctions: dot_func dot diff --git a/sklearn/svm/src/liblinear/_cython_blas_helpers.h b/sklearn/svm/src/liblinear/_cython_blas_helpers.h index 6b2475e9d56cf..bdec1a2f99eb9 100644 --- a/sklearn/svm/src/liblinear/_cython_blas_helpers.h +++ b/sklearn/svm/src/liblinear/_cython_blas_helpers.h @@ -1,10 +1,10 @@ #ifndef _CYTHON_BLAS_HELPERS_H #define _CYTHON_BLAS_HELPERS_H -typedef double (*dot_func)(int, double*, int, double*, int); -typedef void (*axpy_func)(int, double, double*, int, double*, int); -typedef void (*scal_func)(int, double, double*, int); -typedef double (*nrm2_func)(int, double*, int); +typedef double (*dot_func)(int, const double*, int, const double*, int); +typedef void (*axpy_func)(int, double, const double*, int, double*, int); +typedef void (*scal_func)(int, double, const double*, int); +typedef double (*nrm2_func)(int, const double*, int); typedef struct BlasFunctions{ dot_func dot; diff --git a/sklearn/svm/src/libsvm/_svm_cython_blas_helpers.h b/sklearn/svm/src/libsvm/_svm_cython_blas_helpers.h index 057e08195e9a5..2548c7844d267 100644 --- a/sklearn/svm/src/libsvm/_svm_cython_blas_helpers.h +++ b/sklearn/svm/src/libsvm/_svm_cython_blas_helpers.h @@ -1,7 +1,7 @@ #ifndef _SVM_CYTHON_BLAS_HELPERS_H #define _SVM_CYTHON_BLAS_HELPERS_H -typedef double (*dot_func)(int, double*, int, double*, int); +typedef double (*dot_func)(int, const double*, int, const double*, int); typedef struct BlasFunctions{ dot_func dot; } BlasFunctions; From dfed65428b341ba112936581ef697b243acfc8ce Mon Sep 17 00:00:00 2001 From: genvalen Date: Mon, 13 Mar 2023 06:36:04 -0400 Subject: [PATCH 022/230] MAINT parameter validation for sklearn.datasets.load_svmlight_files (#25811) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/datasets/_svmlight_format_io.py | 18 ++++++++++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 19 insertions(+) diff --git a/sklearn/datasets/_svmlight_format_io.py b/sklearn/datasets/_svmlight_format_io.py index b217f33810476..e8d018431541b 100644 --- a/sklearn/datasets/_svmlight_format_io.py +++ b/sklearn/datasets/_svmlight_format_io.py @@ -245,6 +245,24 @@ def _open_and_load(f, dtype, multilabel, zero_based, query_id, offset=0, length= return data, indices, indptr, labels, query +@validate_params( + { + "files": [ + "array-like", + str, + os.PathLike, + HasMethods("read"), + Interval(Integral, 0, None, closed="left"), + ], + "n_features": [Interval(Integral, 1, None, closed="left"), None], + "dtype": "no_validation", # delegate validation to numpy + "multilabel": ["boolean"], + "zero_based": ["boolean", StrOptions({"auto"})], + "query_id": ["boolean"], + "offset": [Interval(Integral, 0, None, closed="left")], + "length": [Integral], + } +) def load_svmlight_files( files, *, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 7c04e5ce44319..8f9994f3a96aa 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -109,6 +109,7 @@ def _check_function_param_validation( "sklearn.datasets.fetch_covtype", "sklearn.datasets.fetch_kddcup99", "sklearn.datasets.load_svmlight_file", + "sklearn.datasets.load_svmlight_files", "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", "sklearn.datasets.make_sparse_coded_signal", From f751a6e8184540528416ab113a6ef14a14c0673b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= Date: Mon, 13 Mar 2023 12:38:30 +0100 Subject: [PATCH 023/230] CI Disable sphinx parallelism in CircleCI doc build (#25832) --- .circleci/config.yml | 2 ++ doc/Makefile | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6d9ae3c84226c..e2f54c0665c78 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -61,6 +61,8 @@ jobs: - OPENBLAS_NUM_THREADS: 2 - CONDA_ENV_NAME: testenv - LOCK_FILE: build_tools/circle/doc_linux-64_conda.lock + # Disable sphinx parallelism to avoid EOFError or job stalling in CircleCI + - SPHINX_NUMJOBS: 1 steps: - checkout - run: ./build_tools/circle/checkout_merge_commit.sh diff --git a/doc/Makefile b/doc/Makefile index 5b3ebc70d25fb..02656feba0710 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -8,12 +8,10 @@ PAPER = BUILDDIR = _build # Disable multiple jobs on OSX -# FIXME: disable completely the parallel build to investigate the EOFError and -# OSError observe in CircleCI ifeq ($(shell uname), Darwin) SPHINX_NUMJOBS ?= 1 else - SPHINX_NUMJOBS ?= 1 + SPHINX_NUMJOBS ?= auto endif ifneq ($(EXAMPLES_PATTERN),) From 2fba9c341e621187426b07b830befe68f601cfee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Mon, 13 Mar 2023 14:40:03 +0100 Subject: [PATCH 024/230] MAINT Parameters validation for metrics.recall_score (#25816) --- sklearn/metrics/_classification.py | 17 +++++++++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 18 insertions(+) diff --git a/sklearn/metrics/_classification.py b/sklearn/metrics/_classification.py index 68659d251cef7..88b8af7944ecc 100644 --- a/sklearn/metrics/_classification.py +++ b/sklearn/metrics/_classification.py @@ -2070,6 +2070,23 @@ def precision_score( return p +@validate_params( + { + "y_true": ["array-like", "sparse matrix"], + "y_pred": ["array-like", "sparse matrix"], + "labels": ["array-like", None], + "pos_label": [Real, str, "boolean", None], + "average": [ + StrOptions({"micro", "macro", "samples", "weighted", "binary"}), + None, + ], + "sample_weight": ["array-like", None], + "zero_division": [ + Options(Real, {0, 1}), + StrOptions({"warn"}), + ], + } +) def recall_score( y_true, y_pred, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 8f9994f3a96aa..b5934782bb42c 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -158,6 +158,7 @@ def _check_function_param_validation( "sklearn.metrics.precision_recall_fscore_support", "sklearn.metrics.precision_score", "sklearn.metrics.r2_score", + "sklearn.metrics.recall_score", "sklearn.metrics.roc_curve", "sklearn.metrics.zero_one_loss", "sklearn.model_selection.train_test_split", From 7403d31f41be2151019ff0ca1611b325c8fa8e04 Mon Sep 17 00:00:00 2001 From: tspeng Date: Mon, 13 Mar 2023 09:41:01 -0400 Subject: [PATCH 025/230] MAINT Parameters validation for sklearn.datasets.fetch_olivetti_faces (#25823) --- sklearn/datasets/_olivetti_faces.py | 10 ++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 11 insertions(+) diff --git a/sklearn/datasets/_olivetti_faces.py b/sklearn/datasets/_olivetti_faces.py index 296a3868081d9..bb26d01b45674 100644 --- a/sklearn/datasets/_olivetti_faces.py +++ b/sklearn/datasets/_olivetti_faces.py @@ -26,6 +26,7 @@ from ._base import _pkl_filepath from ._base import load_descr from ..utils import check_random_state, Bunch +from ..utils._param_validation import validate_params # The original data can be found at: # https://cs.nyu.edu/~roweis/data/olivettifaces.mat @@ -36,6 +37,15 @@ ) +@validate_params( + { + "data_home": [str, None], + "shuffle": ["boolean"], + "random_state": ["random_state"], + "download_if_missing": ["boolean"], + "return_X_y": ["boolean"], + } +) def fetch_olivetti_faces( *, data_home=None, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index b5934782bb42c..6b0e41ce543f2 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -108,6 +108,7 @@ def _check_function_param_validation( "sklearn.datasets.fetch_california_housing", "sklearn.datasets.fetch_covtype", "sklearn.datasets.fetch_kddcup99", + "sklearn.datasets.fetch_olivetti_faces", "sklearn.datasets.load_svmlight_file", "sklearn.datasets.load_svmlight_files", "sklearn.datasets.make_classification", From 8ac700dc536516d00bd125f190336a0749236563 Mon Sep 17 00:00:00 2001 From: Sortofamudkip Date: Mon, 13 Mar 2023 15:46:28 +0100 Subject: [PATCH 026/230] MAINT Parameters validation for metrics.top_k_accuracy_score (#25828) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: wishyut.pitawanik Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/metrics/_ranking.py | 10 ++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 11 insertions(+) diff --git a/sklearn/metrics/_ranking.py b/sklearn/metrics/_ranking.py index fe9a520096991..d5e2d3442259f 100644 --- a/sklearn/metrics/_ranking.py +++ b/sklearn/metrics/_ranking.py @@ -1733,6 +1733,16 @@ def ndcg_score(y_true, y_score, *, k=None, sample_weight=None, ignore_ties=False return np.average(gain, weights=sample_weight) +@validate_params( + { + "y_true": ["array-like"], + "y_score": ["array-like"], + "k": [Interval(Integral, 1, None, closed="left")], + "normalize": ["boolean"], + "sample_weight": ["array-like", None], + "labels": ["array-like", None], + } +) def top_k_accuracy_score( y_true, y_score, *, k=2, normalize=True, sample_weight=None, labels=None ): diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 6b0e41ce543f2..31aeb37c5e536 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -161,6 +161,7 @@ def _check_function_param_validation( "sklearn.metrics.r2_score", "sklearn.metrics.recall_score", "sklearn.metrics.roc_curve", + "sklearn.metrics.top_k_accuracy_score", "sklearn.metrics.zero_one_loss", "sklearn.model_selection.train_test_split", "sklearn.random_projection.johnson_lindenstrauss_min_dim", From 6a0958944b4d153afabc73f281e0fb5206e280a5 Mon Sep 17 00:00:00 2001 From: 2357juan <29247195+2357juan@users.noreply.github.com> Date: Mon, 13 Mar 2023 08:53:17 -0700 Subject: [PATCH 027/230] MAINT Use memoryviews in _random.pyx (#25780) Co-authored-by: Juan Gomez <{789543}+{2357juan}@users.noreply.github.com> --- sklearn/utils/_random.pyx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sklearn/utils/_random.pyx b/sklearn/utils/_random.pyx index 3a8609a4f8925..3589ffd2fdc4c 100644 --- a/sklearn/utils/_random.pyx +++ b/sklearn/utils/_random.pyx @@ -78,7 +78,7 @@ cpdef _sample_without_replacement_with_tracking_selection( cdef cnp.int_t i cdef cnp.int_t j - cdef cnp.ndarray[cnp.int_t, ndim=1] out = np.empty((n_samples, ), dtype=int) + cdef cnp.int_t[:] out = np.empty((n_samples, ), dtype=int) rng = check_random_state(random_state) rng_randint = rng.randint @@ -94,7 +94,7 @@ cpdef _sample_without_replacement_with_tracking_selection( selected.add(j) out[i] = j - return out + return np.asarray(out) cpdef _sample_without_replacement_with_pool(cnp.int_t n_population, @@ -133,9 +133,9 @@ cpdef _sample_without_replacement_with_pool(cnp.int_t n_population, cdef cnp.int_t i cdef cnp.int_t j - cdef cnp.ndarray[cnp.int_t, ndim=1] out = np.empty((n_samples, ), dtype=int) + cdef cnp.int_t[:] out = np.empty((n_samples, ), dtype=int) - cdef cnp.ndarray[cnp.int_t, ndim=1] pool = np.empty((n_population, ), + cdef cnp.int_t[:] pool = np.empty((n_population, ), dtype=int) rng = check_random_state(random_state) @@ -153,7 +153,7 @@ cpdef _sample_without_replacement_with_pool(cnp.int_t n_population, pool[j] = pool[n_population - i - 1] # move non-selected item into # vacancy - return out + return np.asarray(out) cpdef _sample_without_replacement_with_reservoir_sampling( @@ -195,7 +195,7 @@ cpdef _sample_without_replacement_with_reservoir_sampling( cdef cnp.int_t i cdef cnp.int_t j - cdef cnp.ndarray[cnp.int_t, ndim=1] out = np.empty((n_samples, ), dtype=int) + cdef cnp.int_t[:] out = np.empty((n_samples, ), dtype=int) rng = check_random_state(random_state) rng_randint = rng.randint @@ -212,7 +212,7 @@ cpdef _sample_without_replacement_with_reservoir_sampling( if j < n_samples: out[j] = i - return out + return np.asarray(out) cpdef sample_without_replacement(cnp.int_t n_population, From 0fab6b965a9a16b336ce8324824640031b16ede1 Mon Sep 17 00:00:00 2001 From: Adrin Jalali Date: Mon, 13 Mar 2023 17:11:15 +0100 Subject: [PATCH 028/230] MNT make plot_partial_dependence faster (#25806) --- examples/inspection/plot_partial_dependence.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/inspection/plot_partial_dependence.py b/examples/inspection/plot_partial_dependence.py index 4e771a7e28b26..f2f6c2949bb84 100644 --- a/examples/inspection/plot_partial_dependence.py +++ b/examples/inspection/plot_partial_dependence.py @@ -46,6 +46,10 @@ # Make an explicit copy to avoid "SettingWithCopyWarning" from pandas X, y = bikes.data.copy(), bikes.target +# We use only a subset of the data to speed up the example. +X = X.iloc[::5, :] +y = y[::5] + # %% # The feature `"weather"` has a particularity: the category `"heavy_rain"` is a rare # category. @@ -286,7 +290,9 @@ hgbdt_model = make_pipeline( hgbdt_preprocessor, HistGradientBoostingRegressor( - categorical_features=categorical_features, random_state=0 + categorical_features=categorical_features, + random_state=0, + max_iter=50, ), ) hgbdt_model.fit(X_train, y_train) From 7968dabc524be4e0574197fcf3bd620fb4a34edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:57:33 +0100 Subject: [PATCH 029/230] MAINT Clean deprecated losses in (hist) gradient boosting for 1.3 (#25834) --- sklearn/ensemble/_gb.py | 50 +------------- sklearn/ensemble/_gb_losses.py | 2 - .../gradient_boosting.py | 69 +++---------------- .../tests/test_gradient_boosting.py | 53 -------------- .../ensemble/tests/test_gradient_boosting.py | 27 -------- 5 files changed, 11 insertions(+), 190 deletions(-) diff --git a/sklearn/ensemble/_gb.py b/sklearn/ensemble/_gb.py index d80366141bdf9..fff35ab6c33b4 100644 --- a/sklearn/ensemble/_gb.py +++ b/sklearn/ensemble/_gb.py @@ -28,7 +28,6 @@ from ._base import BaseEnsemble from ..base import ClassifierMixin, RegressorMixin from ..base import is_classifier -from ..utils import deprecated from ._gradient_boosting import predict_stages from ._gradient_boosting import predict_stage @@ -275,20 +274,7 @@ def _fit_stage( return raw_predictions def _check_params(self): - # TODO(1.3): Remove - if self.loss == "deviance": - warnings.warn( - "The loss parameter name 'deviance' was deprecated in v1.1 and will be " - "removed in version 1.3. Use the new parameter name 'log_loss' which " - "is equivalent.", - FutureWarning, - ) - loss_class = ( - _gb_losses.MultinomialDeviance - if len(self.classes_) > 2 - else _gb_losses.BinomialDeviance - ) - elif self.loss == "log_loss": + if self.loss == "log_loss": loss_class = ( _gb_losses.MultinomialDeviance if len(self.classes_) > 2 @@ -853,15 +839,6 @@ def apply(self, X): return leaves - # TODO(1.3): Remove - # mypy error: Decorated property not supported - @deprecated( # type: ignore - "Attribute `loss_` was deprecated in version 1.1 and will be removed in 1.3." - ) - @property - def loss_(self): - return self._loss - class GradientBoostingClassifier(ClassifierMixin, BaseGradientBoosting): """Gradient Boosting for classification. @@ -880,16 +857,12 @@ class GradientBoostingClassifier(ClassifierMixin, BaseGradientBoosting): Parameters ---------- - loss : {'log_loss', 'deviance', 'exponential'}, default='log_loss' + loss : {'log_loss', 'exponential'}, default='log_loss' The loss function to be optimized. 'log_loss' refers to binomial and multinomial deviance, the same as used in logistic regression. It is a good choice for classification with probabilistic outputs. For loss 'exponential', gradient boosting recovers the AdaBoost algorithm. - .. deprecated:: 1.1 - The loss 'deviance' was deprecated in v1.1 and will be removed in - version 1.3. Use `loss='log_loss'` which is equivalent. - learning_rate : float, default=0.1 Learning rate shrinks the contribution of each tree by `learning_rate`. There is a trade-off between learning_rate and n_estimators. @@ -1107,13 +1080,6 @@ class GradientBoostingClassifier(ClassifierMixin, BaseGradientBoosting): model at iteration ``i`` on the in-bag sample. If ``subsample == 1`` this is the deviance on the training data. - loss_ : LossFunction - The concrete ``LossFunction`` object. - - .. deprecated:: 1.1 - Attribute `loss_` was deprecated in version 1.1 and will be - removed in 1.3. - init_ : estimator The estimator that provides the initial predictions. Set via the ``init`` argument or ``loss.init_estimator``. @@ -1194,12 +1160,9 @@ class GradientBoostingClassifier(ClassifierMixin, BaseGradientBoosting): 0.913... """ - # TODO(1.3): remove "deviance" _parameter_constraints: dict = { **BaseGradientBoosting._parameter_constraints, - "loss": [ - StrOptions({"log_loss", "deviance", "exponential"}, deprecated={"deviance"}) - ], + "loss": [StrOptions({"log_loss", "exponential"})], "init": [StrOptions({"zero"}), None, HasMethods(["fit", "predict_proba"])], } @@ -1681,13 +1644,6 @@ class GradientBoostingRegressor(RegressorMixin, BaseGradientBoosting): model at iteration ``i`` on the in-bag sample. If ``subsample == 1`` this is the deviance on the training data. - loss_ : LossFunction - The concrete ``LossFunction`` object. - - .. deprecated:: 1.1 - Attribute `loss_` was deprecated in version 1.1 and will be - removed in 1.3. - init_ : estimator The estimator that provides the initial predictions. Set via the ``init`` argument or ``loss.init_estimator``. diff --git a/sklearn/ensemble/_gb_losses.py b/sklearn/ensemble/_gb_losses.py index 228250910b94f..db2116d9aa2e1 100644 --- a/sklearn/ensemble/_gb_losses.py +++ b/sklearn/ensemble/_gb_losses.py @@ -992,8 +992,6 @@ def get_init_raw_predictions(self, X, estimator): "absolute_error": LeastAbsoluteError, "huber": HuberLossFunction, "quantile": QuantileLossFunction, - # TODO(1.3): Remove deviance - "deviance": None, # for both, multinomial and binomial "log_loss": None, # for both, multinomial and binomial "exponential": ExponentialLoss, } diff --git a/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py b/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py index 31069fe14ee41..6014fc845b8a6 100644 --- a/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py +++ b/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py @@ -5,7 +5,6 @@ from functools import partial import itertools from numbers import Real, Integral -import warnings import numpy as np from timeit import default_timer as time @@ -40,14 +39,11 @@ _LOSSES = _LOSSES.copy() -# TODO(1.3): Remove "binary_crossentropy" and "categorical_crossentropy" _LOSSES.update( { "poisson": HalfPoissonLoss, "gamma": HalfGammaLoss, "quantile": PinballLoss, - "binary_crossentropy": HalfBinomialLoss, - "categorical_crossentropy": HalfMultinomialLoss, } ) @@ -1573,8 +1569,7 @@ class HistGradientBoostingClassifier(ClassifierMixin, BaseHistGradientBoosting): Parameters ---------- - loss : {'log_loss', 'auto', 'binary_crossentropy', 'categorical_crossentropy'}, \ - default='log_loss' + loss : {'log_loss'}, default='log_loss' The loss function to use in the boosting process. For binary classification problems, 'log_loss' is also known as logistic loss, @@ -1587,11 +1582,6 @@ class HistGradientBoostingClassifier(ClassifierMixin, BaseHistGradientBoosting): boosting iteration and per class and uses the softmax function as inverse link function to compute the predicted probabilities of the classes. - .. deprecated:: 1.1 - The loss arguments 'auto', 'binary_crossentropy' and - 'categorical_crossentropy' were deprecated in v1.1 and will be removed in - version 1.3. Use `loss='log_loss'` which is equivalent. - learning_rate : float, default=0.1 The learning rate, also known as *shrinkage*. This is used as a multiplicative factor for the leaves values. Use ``1`` for no @@ -1797,25 +1787,9 @@ class HistGradientBoostingClassifier(ClassifierMixin, BaseHistGradientBoosting): 1.0 """ - # TODO(1.3): Remove "binary_crossentropy", "categorical_crossentropy", "auto" _parameter_constraints: dict = { **BaseHistGradientBoosting._parameter_constraints, - "loss": [ - StrOptions( - { - "log_loss", - "binary_crossentropy", - "categorical_crossentropy", - "auto", - }, - deprecated={ - "auto", - "binary_crossentropy", - "categorical_crossentropy", - }, - ), - BaseLoss, - ], + "loss": [StrOptions({"log_loss"}), BaseLoss], "class_weight": [dict, StrOptions({"balanced"}), None], } @@ -2014,37 +1988,10 @@ def _encode_y(self, y): return encoded_y def _get_loss(self, sample_weight): - # TODO(1.3): Remove "auto", "binary_crossentropy", "categorical_crossentropy" - if self.loss in ("auto", "binary_crossentropy", "categorical_crossentropy"): - warnings.warn( - f"The loss '{self.loss}' was deprecated in v1.1 and will be removed in " - "version 1.3. Use 'log_loss' which is equivalent.", - FutureWarning, + # At this point self.loss == "log_loss" + if self.n_trees_per_iteration_ == 1: + return HalfBinomialLoss(sample_weight=sample_weight) + else: + return HalfMultinomialLoss( + sample_weight=sample_weight, n_classes=self.n_trees_per_iteration_ ) - - if self.loss in ("log_loss", "auto"): - if self.n_trees_per_iteration_ == 1: - return HalfBinomialLoss(sample_weight=sample_weight) - else: - return HalfMultinomialLoss( - sample_weight=sample_weight, n_classes=self.n_trees_per_iteration_ - ) - if self.loss == "categorical_crossentropy": - if self.n_trees_per_iteration_ == 1: - raise ValueError( - f"loss='{self.loss}' is not suitable for a binary classification " - "problem. Please use loss='log_loss' instead." - ) - else: - return HalfMultinomialLoss( - sample_weight=sample_weight, n_classes=self.n_trees_per_iteration_ - ) - if self.loss == "binary_crossentropy": - if self.n_trees_per_iteration_ > 1: - raise ValueError( - f"loss='{self.loss}' is not defined for multiclass " - f"classification with n_classes={self.n_trees_per_iteration_}, " - "use loss='log_loss' instead." - ) - else: - return HalfBinomialLoss(sample_weight=sample_weight) diff --git a/sklearn/ensemble/_hist_gradient_boosting/tests/test_gradient_boosting.py b/sklearn/ensemble/_hist_gradient_boosting/tests/test_gradient_boosting.py index 7e774d9f09f45..e5972eaf351f6 100644 --- a/sklearn/ensemble/_hist_gradient_boosting/tests/test_gradient_boosting.py +++ b/sklearn/ensemble/_hist_gradient_boosting/tests/test_gradient_boosting.py @@ -85,19 +85,6 @@ def test_init_parameters_validation(GradientBoosting, X, y, params, err_msg): GradientBoosting(**params).fit(X, y) -# TODO(1.3): remove -@pytest.mark.filterwarnings("ignore::FutureWarning") -def test_invalid_classification_loss(): - binary_clf = HistGradientBoostingClassifier(loss="binary_crossentropy") - err_msg = ( - "loss='binary_crossentropy' is not defined for multiclass " - "classification with n_classes=3, use " - "loss='log_loss' instead" - ) - with pytest.raises(ValueError, match=err_msg): - binary_clf.fit(np.zeros(shape=(3, 2)), np.arange(3)) - - @pytest.mark.parametrize( "scoring, validation_fraction, early_stopping, n_iter_no_change, tol", [ @@ -672,20 +659,6 @@ def test_infinite_values_missing_values(): assert stump_clf.fit(X, y_isnan).score(X, y_isnan) == 1 -# TODO(1.3): remove -@pytest.mark.filterwarnings("ignore::FutureWarning") -def test_crossentropy_binary_problem(): - # categorical_crossentropy should only be used if there are more than two - # classes present. PR #14869 - X = [[1], [0]] - y = [0, 1] - gbrt = HistGradientBoostingClassifier(loss="categorical_crossentropy") - with pytest.raises( - ValueError, match="loss='categorical_crossentropy' is not suitable for" - ): - gbrt.fit(X, y) - - @pytest.mark.parametrize("scoring", [None, "loss"]) def test_string_target_early_stopping(scoring): # Regression tests for #14709 where the targets need to be encoded before @@ -1321,32 +1294,6 @@ def test_interaction_cst_numerically(): ) -# TODO(1.3): Remove -@pytest.mark.parametrize( - "old_loss, new_loss, Estimator", - [ - ("auto", "log_loss", HistGradientBoostingClassifier), - ("binary_crossentropy", "log_loss", HistGradientBoostingClassifier), - ("categorical_crossentropy", "log_loss", HistGradientBoostingClassifier), - ], -) -def test_loss_deprecated(old_loss, new_loss, Estimator): - if old_loss == "categorical_crossentropy": - X, y = X_multi_classification[:10], y_multi_classification[:10] - assert len(np.unique(y)) > 2 - else: - X, y = X_classification[:10], y_classification[:10] - - est1 = Estimator(loss=old_loss, random_state=0) - - with pytest.warns(FutureWarning, match=f"The loss '{old_loss}' was deprecated"): - est1.fit(X, y) - - est2 = Estimator(loss=new_loss, random_state=0) - est2.fit(X, y) - assert_allclose(est1.predict(X), est2.predict(X)) - - def test_no_user_warning_with_scoring(): """Check that no UserWarning is raised when scoring is set. diff --git a/sklearn/ensemble/tests/test_gradient_boosting.py b/sklearn/ensemble/tests/test_gradient_boosting.py index be60be7461e7a..3f2a1aae31bcb 100644 --- a/sklearn/ensemble/tests/test_gradient_boosting.py +++ b/sklearn/ensemble/tests/test_gradient_boosting.py @@ -1423,30 +1423,3 @@ def test_gbr_degenerate_feature_importances(): y = np.ones((10,)) gbr = GradientBoostingRegressor().fit(X, y) assert_array_equal(gbr.feature_importances_, np.zeros(10, dtype=np.float64)) - - -# TODO(1.3): Remove -def test_loss_deprecated(): - est1 = GradientBoostingClassifier(loss="deviance", random_state=0) - - with pytest.warns(FutureWarning, match=r"The loss.* 'deviance' was deprecated"): - est1.fit(X, y) - - est2 = GradientBoostingClassifier(loss="log_loss", random_state=0) - est2.fit(X, y) - assert_allclose(est1.predict(X), est2.predict(X)) - - -# TODO(1.3): remove -@pytest.mark.parametrize( - "Estimator", [GradientBoostingClassifier, GradientBoostingRegressor] -) -def test_loss_attribute_deprecation(Estimator): - # Check that we raise the proper deprecation warning if accessing - # `loss_`. - X = np.array([[1, 2], [3, 4]]) - y = np.array([1, 0]) - est = Estimator().fit(X, y) - - with pytest.warns(FutureWarning, match="`loss_` was deprecated"): - est.loss_ From 63e79e39306652df76dd8acf6a24d282c02844d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:58:31 +0100 Subject: [PATCH 030/230] MAINT Clean deprecation of normalize in calibration_curve for 1.3 (#25833) --- sklearn/calibration.py | 25 ------------------------- sklearn/tests/test_calibration.py | 20 -------------------- 2 files changed, 45 deletions(-) diff --git a/sklearn/calibration.py b/sklearn/calibration.py index 7db64a89468d5..d54aa158f5328 100644 --- a/sklearn/calibration.py +++ b/sklearn/calibration.py @@ -908,7 +908,6 @@ def calibration_curve( y_prob, *, pos_label=None, - normalize="deprecated", n_bins=5, strategy="uniform", ): @@ -934,17 +933,6 @@ def calibration_curve( .. versionadded:: 1.1 - normalize : bool, default="deprecated" - Whether y_prob needs to be normalized into the [0, 1] interval, i.e. - is not a proper probability. If True, the smallest value in y_prob - is linearly mapped onto 0 and the largest one onto 1. - - .. deprecated:: 1.1 - The normalize argument is deprecated in v1.1 and will be removed in v1.3. - Explicitly normalizing `y_prob` will reproduce this behavior, but it is - recommended that a proper probability is used (i.e. a classifier's - `predict_proba` positive class). - n_bins : int, default=5 Number of bins to discretize the [0, 1] interval. A bigger number requires more data. Bins with no samples (i.e. without @@ -992,19 +980,6 @@ def calibration_curve( check_consistent_length(y_true, y_prob) pos_label = _check_pos_label_consistency(pos_label, y_true) - # TODO(1.3): Remove normalize conditional block. - if normalize != "deprecated": - warnings.warn( - "The normalize argument is deprecated in v1.1 and will be removed in v1.3." - " Explicitly normalizing y_prob will reproduce this behavior, but it is" - " recommended that a proper probability is used (i.e. a classifier's" - " `predict_proba` positive class or `decision_function` output calibrated" - " with `CalibratedClassifierCV`).", - FutureWarning, - ) - if normalize: # Normalize predicted values into interval [0, 1] - y_prob = (y_prob - y_prob.min()) / (y_prob.max() - y_prob.min()) - if y_prob.min() < 0 or y_prob.max() > 1: raise ValueError("y_prob has values outside [0, 1].") diff --git a/sklearn/tests/test_calibration.py b/sklearn/tests/test_calibration.py index 72662ae221afa..01bdbd6566042 100644 --- a/sklearn/tests/test_calibration.py +++ b/sklearn/tests/test_calibration.py @@ -401,26 +401,6 @@ def test_calibration_curve(): calibration_curve(y_true2, y_pred2, strategy="percentile") -# TODO(1.3): Remove this test. -def test_calibration_curve_with_unnormalized_proba(): - """Tests the `normalize` parameter of `calibration_curve`""" - y_true = np.array([0, 0, 0, 1, 1, 1]) - y_pred = np.array([0.0, 0.1, 0.2, 0.8, 0.9, 1.0]) - - # Ensure `normalize` == False raises a FutureWarning. - with pytest.warns(FutureWarning): - calibration_curve(y_true, y_pred, n_bins=2, normalize=False) - - # Ensure `normalize` == True raises a FutureWarning and behaves as expected. - with pytest.warns(FutureWarning): - prob_true_unnormalized, prob_pred_unnormalized = calibration_curve( - y_true, y_pred * 2, n_bins=2, normalize=True - ) - prob_true, prob_pred = calibration_curve(y_true, y_pred, n_bins=2) - assert_almost_equal(prob_true, prob_true_unnormalized) - assert_almost_equal(prob_pred, prob_pred_unnormalized) - - @pytest.mark.parametrize("ensemble", [True, False]) def test_calibration_nan_imputer(ensemble): """Test that calibration can accept nan""" From a4e94ffc459e6a029c4a5e3d008fb38e84ad312e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Tue, 14 Mar 2023 11:43:12 +0100 Subject: [PATCH 031/230] BLD Clean command removes generated from cython templates (#25839) --- setup.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 55c5cc2923527..e40c1453f7e33 100755 --- a/setup.py +++ b/setup.py @@ -79,17 +79,20 @@ def run(self): shutil.rmtree("build") for dirpath, dirnames, filenames in os.walk("sklearn"): for filename in filenames: - if any( - filename.endswith(suffix) - for suffix in (".so", ".pyd", ".dll", ".pyc") - ): + root, extension = os.path.splitext(filename) + + if extension in [".so", ".pyd", ".dll", ".pyc"]: os.unlink(os.path.join(dirpath, filename)) - continue - extension = os.path.splitext(filename)[1] + if remove_c_files and extension in [".c", ".cpp"]: pyx_file = str.replace(filename, extension, ".pyx") if os.path.exists(os.path.join(dirpath, pyx_file)): os.unlink(os.path.join(dirpath, filename)) + + if remove_c_files and extension == ".tp": + if os.path.exists(os.path.join(dirpath, root)): + os.unlink(os.path.join(dirpath, root)) + for dirname in dirnames: if dirname == "__pycache__": shutil.rmtree(os.path.join(dirpath, dirname)) From 204fd87c42f46f495eac30b9b95fae70f744eeda Mon Sep 17 00:00:00 2001 From: Meekail Zain <34613774+Micky774@users.noreply.github.com> Date: Tue, 14 Mar 2023 07:04:34 -0400 Subject: [PATCH 032/230] PERF Implement `PairwiseDistancesReduction` backend for `KNeighbors.predict_proba` (#24076) Signed-off-by: Julien Jerphanion Co-authored-by: Julien Jerphanion Co-authored-by: Olivier Grisel --- .gitignore | 1 + doc/whats_new/v1.3.rst | 5 + setup.cfg | 1 + setup.py | 6 + .../_pairwise_distances_reduction/__init__.py | 2 + .../_argkmin.pyx.tp | 1 - .../_argkmin_classmode.pyx.tp | 208 ++++++++++++++++++ .../_dispatcher.py | 192 +++++++++++++++- .../test_pairwise_distances_reduction.py | 153 ++++++++++++- sklearn/neighbors/_base.py | 5 +- sklearn/neighbors/_classification.py | 67 +++++- sklearn/neighbors/tests/test_neighbors.py | 21 +- 12 files changed, 648 insertions(+), 14 deletions(-) create mode 100644 sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp diff --git a/.gitignore b/.gitignore index f6250b4d5f580..89600846100a8 100644 --- a/.gitignore +++ b/.gitignore @@ -90,6 +90,7 @@ sklearn/metrics/_dist_metrics.pyx sklearn/metrics/_dist_metrics.pxd sklearn/metrics/_pairwise_distances_reduction/_argkmin.pxd sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx +sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx sklearn/metrics/_pairwise_distances_reduction/_base.pxd sklearn/metrics/_pairwise_distances_reduction/_base.pyx sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pxd diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 1fe4289982993..439b348ce2610 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -292,6 +292,11 @@ Changelog dissimilarity is not a metric and cannot be supported by the BallTree. :pr:`25417` by :user:`Guillaume Lemaitre `. +- |Enhancement| The performance of :meth:`neighbors.KNeighborsClassifier.predict` + and of :meth:`neighbors.KNeighborsClassifier.predict_proba` has been improved + when `n_neighbors` is large and `algorithm="brute"` with non Euclidean metrics. + :pr:`24076` by :user:`Meekail Zain `, :user:`Julien Jerphanion `. + :mod:`sklearn.neural_network` ............................. diff --git a/setup.cfg b/setup.cfg index 081e78c92d480..3ed576cedf92f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -90,6 +90,7 @@ ignore = sklearn/metrics/_dist_metrics.pxd sklearn/metrics/_pairwise_distances_reduction/_argkmin.pxd sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx + sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx sklearn/metrics/_pairwise_distances_reduction/_base.pxd sklearn/metrics/_pairwise_distances_reduction/_base.pyx sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pxd diff --git a/setup.py b/setup.py index e40c1453f7e33..72172408110de 100755 --- a/setup.py +++ b/setup.py @@ -280,6 +280,12 @@ def check_package_status(package, min_version): "include_np": True, "extra_compile_args": ["-std=c++11"], }, + { + "sources": ["_argkmin_classmode.pyx.tp"], + "language": "c++", + "include_np": True, + "extra_compile_args": ["-std=c++11"], + }, { "sources": ["_radius_neighbors.pyx.tp", "_radius_neighbors.pxd.tp"], "language": "c++", diff --git a/sklearn/metrics/_pairwise_distances_reduction/__init__.py b/sklearn/metrics/_pairwise_distances_reduction/__init__.py index 133c854682f0c..baa1c9de03952 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/__init__.py +++ b/sklearn/metrics/_pairwise_distances_reduction/__init__.py @@ -90,6 +90,7 @@ BaseDistancesReductionDispatcher, ArgKmin, RadiusNeighbors, + ArgKminClassMode, sqeuclidean_row_norms, ) @@ -97,5 +98,6 @@ "BaseDistancesReductionDispatcher", "ArgKmin", "RadiusNeighbors", + "ArgKminClassMode", "sqeuclidean_row_norms", ] diff --git a/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx.tp index 3b2bce128dcb6..7caf5e0680dea 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx.tp @@ -178,7 +178,6 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): self.heaps_r_distances_chunks[thread_num] = &self.argkmin_distances[X_start, 0] self.heaps_indices_chunks[thread_num] = &self.argkmin_indices[X_start, 0] - @final cdef void _parallel_on_X_prange_iter_finalize( self, ITYPE_t thread_num, diff --git a/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp new file mode 100644 index 0000000000000..95577e5754e64 --- /dev/null +++ b/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp @@ -0,0 +1,208 @@ +{{py: + +implementation_specific_values = [ + # Values are the following ones: + # + # name_suffix, INPUT_DTYPE_t, INPUT_DTYPE + # + # We also use the float64 dtype and C-type names as defined in + # `sklearn.utils._typedefs` to maintain consistency. + # + ('64', 'DTYPE_t', 'DTYPE'), + ('32', 'cnp.float32_t', 'np.float32') +] + +}} + +from cython cimport floating, integral +from cython.parallel cimport parallel, prange +from libcpp.map cimport map as cpp_map, pair as cpp_pair +from libc.stdlib cimport free + +cimport numpy as cnp + +cnp.import_array() + +from ...utils._typedefs cimport ITYPE_t, DTYPE_t +from ...utils._typedefs import ITYPE, DTYPE +import numpy as np +from scipy.sparse import issparse +from sklearn.utils.fixes import threadpool_limits + +cpdef enum WeightingStrategy: + uniform = 0 + # TODO: Implement the following options, most likely in + # `weighted_histogram_mode` + distance = 1 + callable = 2 + +{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}} +from ._argkmin cimport ArgKmin{{name_suffix}} +from ._datasets_pair cimport DatasetsPair{{name_suffix}} + +cdef class ArgKminClassMode{{name_suffix}}(ArgKmin{{name_suffix}}): + """ + {{name_suffix}}bit implementation of ArgKminClassMode. + """ + cdef: + const ITYPE_t[:] class_membership, + const ITYPE_t[:] unique_labels + DTYPE_t[:, :] class_scores + cpp_map[ITYPE_t, ITYPE_t] labels_to_index + WeightingStrategy weight_type + + @classmethod + def compute( + cls, + X, + Y, + ITYPE_t k, + weights, + class_membership, + unique_labels, + str metric="euclidean", + chunk_size=None, + dict metric_kwargs=None, + str strategy=None, + ): + """Compute the argkmin reduction with class_membership. + + This classmethod is responsible for introspecting the arguments + values to dispatch to the most appropriate implementation of + :class:`ArgKminClassMode{{name_suffix}}`. + + This allows decoupling the API entirely from the implementation details + whilst maintaining RAII: all temporarily allocated datastructures necessary + for the concrete implementation are therefore freed when this classmethod + returns. + + No instance _must_ directly be created outside of this class method. + """ + # Use a generic implementation that handles most scipy + # metrics by computing the distances between 2 vectors at a time. + pda = ArgKminClassMode{{name_suffix}}( + datasets_pair=DatasetsPair{{name_suffix}}.get_for(X, Y, metric, metric_kwargs), + k=k, + chunk_size=chunk_size, + strategy=strategy, + weights=weights, + class_membership=class_membership, + unique_labels=unique_labels, + ) + + # Limit the number of threads in second level of nested parallelism for BLAS + # to avoid threads over-subscription (in GEMM for instance). + with threadpool_limits(limits=1, user_api="blas"): + if pda.execute_in_parallel_on_Y: + pda._parallel_on_Y() + else: + pda._parallel_on_X() + + return pda._finalize_results() + + def __init__( + self, + DatasetsPair{{name_suffix}} datasets_pair, + const ITYPE_t[:] class_membership, + const ITYPE_t[:] unique_labels, + chunk_size=None, + strategy=None, + ITYPE_t k=1, + weights=None, + ): + super().__init__( + datasets_pair=datasets_pair, + chunk_size=chunk_size, + strategy=strategy, + k=k, + ) + + if weights == "uniform": + self.weight_type = WeightingStrategy.uniform + elif weights == "distance": + self.weight_type = WeightingStrategy.distance + else: + self.weight_type = WeightingStrategy.callable + self.class_membership = class_membership + + self.unique_labels = unique_labels + + cdef ITYPE_t idx, neighbor_class_idx + # Map from set of unique labels to their indices in `class_scores` + # Buffer used in building a histogram for one-pass weighted mode + self.class_scores = np.zeros( + (self.n_samples_X, unique_labels.shape[0]), dtype=DTYPE, + ) + + def _finalize_results(self): + probabilities = np.asarray(self.class_scores) + probabilities /= probabilities.sum(axis=1, keepdims=True) + return probabilities + + cdef inline void weighted_histogram_mode( + self, + ITYPE_t sample_index, + ITYPE_t* indices, + DTYPE_t* distances, + ) noexcept nogil: + cdef: + ITYPE_t neighbor_idx, neighbor_class_idx, label_index, multi_output_index + DTYPE_t score_incr = 1 + # TODO: Implement other WeightingStrategy values + bint use_distance_weighting = ( + self.weight_type == WeightingStrategy.distance + ) + + # Iterate through the sample k-nearest neighbours + for neighbor_rank in range(self.k): + # Absolute indice of the neighbor_rank-th Nearest Neighbors + # in range [0, n_samples_Y) + # TODO: inspect if it worth permuting this condition + # and the for-loop above for improved branching. + if use_distance_weighting: + score_incr = 1 / distances[neighbor_rank] + neighbor_idx = indices[neighbor_rank] + neighbor_class_idx = self.class_membership[neighbor_idx] + self.class_scores[sample_index][neighbor_class_idx] += score_incr + return + + cdef void _parallel_on_X_prange_iter_finalize( + self, + ITYPE_t thread_num, + ITYPE_t X_start, + ITYPE_t X_end, + ) noexcept nogil: + cdef: + ITYPE_t idx, sample_index + for idx in range(X_end - X_start): + # One-pass top-one weighted mode + # Compute the absolute index in [0, n_samples_X) + sample_index = X_start + idx + self.weighted_histogram_mode( + sample_index, + &self.heaps_indices_chunks[thread_num][idx * self.k], + &self.heaps_r_distances_chunks[thread_num][idx * self.k], + ) + return + + cdef void _parallel_on_Y_finalize( + self, + ) noexcept nogil: + cdef: + ITYPE_t sample_index, thread_num + + with nogil, parallel(num_threads=self.chunks_n_threads): + # Deallocating temporary datastructures + for thread_num in prange(self.chunks_n_threads, schedule='static'): + free(self.heaps_r_distances_chunks[thread_num]) + free(self.heaps_indices_chunks[thread_num]) + + for sample_index in prange(self.n_samples_X, schedule='static'): + self.weighted_histogram_mode( + sample_index, + &self.argkmin_indices[sample_index][0], + &self.argkmin_distances[sample_index][0], + ) + return + +{{endfor}} diff --git a/sklearn/metrics/_pairwise_distances_reduction/_dispatcher.py b/sklearn/metrics/_pairwise_distances_reduction/_dispatcher.py index 576cc64ff5295..73d98f2ebe6b2 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_dispatcher.py +++ b/sklearn/metrics/_pairwise_distances_reduction/_dispatcher.py @@ -4,7 +4,7 @@ from typing import List -from scipy.sparse import isspmatrix_csr +from scipy.sparse import isspmatrix_csr, issparse from .._dist_metrics import BOOL_METRICS, METRIC_MAPPING @@ -13,6 +13,12 @@ ArgKmin64, ArgKmin32, ) + +from ._argkmin_classmode import ( + ArgKminClassMode64, + ArgKminClassMode32, +) + from ._radius_neighbors import ( RadiusNeighbors64, RadiusNeighbors32, @@ -428,3 +434,187 @@ def compute( "Only float64 or float32 datasets pairs are supported at this time, " f"got: X.dtype={X.dtype} and Y.dtype={Y.dtype}." ) + + +class ArgKminClassMode(BaseDistancesReductionDispatcher): + """Compute the argkmin of row vectors of X on the ones of Y with labels. + + For each row vector of X, computes the indices of k first the rows + vectors of Y with the smallest distances. Computes weighted mode of labels. + + ArgKminClassMode is typically used to perform bruteforce k-nearest neighbors + queries when the weighted mode of the labels for the k-nearest neighbors + are required, such as in `predict` methods. + + This class is not meant to be instanciated, one should only use + its :meth:`compute` classmethod which handles allocation and + deallocation consistently. + """ + + @classmethod + def is_usable_for(cls, X, Y, metric) -> bool: + """Return True if the dispatcher can be used for the given parameters. + + Parameters + ---------- + X : ndarray of shape (n_samples_X, n_features) + The input array to be labelled. + + Y : ndarray of shape (n_samples_Y, n_features) + The input array whose labels are provided through the `labels` + parameter. + + metric : str, default='euclidean' + The distance metric to use. For a list of available metrics, see + the documentation of :class:`~sklearn.metrics.DistanceMetric`. + Currently does not support `'precomputed'`. + + Returns + ------- + True if the PairwiseDistancesReduction can be used, else False. + """ + return ( + ArgKmin.is_usable_for(X, Y, metric) + # TODO: Support CSR matrices. + and not issparse(X) + and not issparse(Y) + # TODO: implement Euclidean specialization with GEMM. + and metric not in ("euclidean", "sqeuclidean") + ) + + @classmethod + def compute( + cls, + X, + Y, + k, + weights, + labels, + unique_labels, + metric="euclidean", + chunk_size=None, + metric_kwargs=None, + strategy=None, + ): + """Compute the argkmin reduction. + + Parameters + ---------- + X : ndarray of shape (n_samples_X, n_features) + The input array to be labelled. + + Y : ndarray of shape (n_samples_Y, n_features) + The input array whose labels are provided through the `labels` + parameter. + + k : int + The number of nearest neighbors to consider. + + weights : ndarray + The weights applied over the `labels` of `Y` when computing the + weighted mode of the labels. + + class_membership : ndarray + An array containing the index of the class membership of the + associated samples in `Y`. This is used in labeling `X`. + + unique_classes : ndarray + An array containing all unique indices contained in the + corresponding `class_membership` array. + + metric : str, default='euclidean' + The distance metric to use. For a list of available metrics, see + the documentation of :class:`~sklearn.metrics.DistanceMetric`. + Currently does not support `'precomputed'`. + + chunk_size : int, default=None, + The number of vectors per chunk. If None (default) looks-up in + scikit-learn configuration for `pairwise_dist_chunk_size`, + and use 256 if it is not set. + + metric_kwargs : dict, default=None + Keyword arguments to pass to specified metric function. + + strategy : str, {'auto', 'parallel_on_X', 'parallel_on_Y'}, default=None + The chunking strategy defining which dataset parallelization are made on. + + For both strategies the computations happens with two nested loops, + respectively on chunks of X and chunks of Y. + Strategies differs on which loop (outer or inner) is made to run + in parallel with the Cython `prange` construct: + + - 'parallel_on_X' dispatches chunks of X uniformly on threads. + Each thread then iterates on all the chunks of Y. This strategy is + embarrassingly parallel and comes with no datastructures + synchronisation. + + - 'parallel_on_Y' dispatches chunks of Y uniformly on threads. + Each thread processes all the chunks of X in turn. This strategy is + a sequence of embarrassingly parallel subtasks (the inner loop on Y + chunks) with intermediate datastructures synchronisation at each + iteration of the sequential outer loop on X chunks. + + - 'auto' relies on a simple heuristic to choose between + 'parallel_on_X' and 'parallel_on_Y': when `X.shape[0]` is large enough, + 'parallel_on_X' is usually the most efficient strategy. + When `X.shape[0]` is small but `Y.shape[0]` is large, 'parallel_on_Y' + brings more opportunity for parallelism and is therefore more efficient + despite the synchronization step at each iteration of the outer loop + on chunks of `X`. + + - None (default) looks-up in scikit-learn configuration for + `pairwise_dist_parallel_strategy`, and use 'auto' if it is not set. + + Returns + ------- + probabilities : ndarray of shape (n_samples_X, n_classes) + An array containing the class probabilities for each sample. + + Notes + ----- + This classmethod is responsible for introspecting the arguments + values to dispatch to the most appropriate implementation of + :class:`PairwiseDistancesArgKmin`. + + This allows decoupling the API entirely from the implementation details + whilst maintaining RAII: all temporarily allocated datastructures necessary + for the concrete implementation are therefore freed when this classmethod + returns. + """ + if weights not in {"uniform", "distance"}: + raise ValueError( + "Only the 'uniform' or 'distance' weights options are supported" + f" at this time. Got: {weights=}." + ) + if X.dtype == Y.dtype == np.float64: + return ArgKminClassMode64.compute( + X=X, + Y=Y, + k=k, + weights=weights, + class_membership=np.array(labels, dtype=np.intp), + unique_labels=np.array(unique_labels, dtype=np.intp), + metric=metric, + chunk_size=chunk_size, + metric_kwargs=metric_kwargs, + strategy=strategy, + ) + + if X.dtype == Y.dtype == np.float32: + return ArgKminClassMode32.compute( + X=X, + Y=Y, + k=k, + weights=weights, + class_membership=np.array(labels, dtype=np.intp), + unique_labels=np.array(unique_labels, dtype=np.intp), + metric=metric, + chunk_size=chunk_size, + metric_kwargs=metric_kwargs, + strategy=strategy, + ) + + raise ValueError( + "Only float64 or float32 datasets pairs are supported at this time, " + f"got: X.dtype={X.dtype} and Y.dtype={Y.dtype}." + ) diff --git a/sklearn/metrics/tests/test_pairwise_distances_reduction.py b/sklearn/metrics/tests/test_pairwise_distances_reduction.py index ad0ddbc60e9bd..7355dfd6ba912 100644 --- a/sklearn/metrics/tests/test_pairwise_distances_reduction.py +++ b/sklearn/metrics/tests/test_pairwise_distances_reduction.py @@ -13,10 +13,10 @@ from sklearn.metrics._pairwise_distances_reduction import ( BaseDistancesReductionDispatcher, ArgKmin, + ArgKminClassMode, RadiusNeighbors, sqeuclidean_row_norms, ) - from sklearn.metrics import euclidean_distances from sklearn.utils.fixes import sp_version, parse_version from sklearn.utils._testing import ( @@ -656,6 +656,124 @@ def test_argkmin_factory_method_wrong_usages(): ArgKmin.compute(X=X, Y=Y, k=k, metric=metric, metric_kwargs=metric_kwargs) +def test_argkmin_classmode_factory_method_wrong_usages(): + rng = np.random.RandomState(1) + X = rng.rand(100, 10) + Y = rng.rand(100, 10) + k = 5 + metric = "manhattan" + + weights = "uniform" + labels = rng.randint(low=0, high=10, size=100) + unique_labels = np.unique(labels) + + msg = ( + "Only float64 or float32 datasets pairs are supported at this time, " + "got: X.dtype=float32 and Y.dtype=float64" + ) + with pytest.raises(ValueError, match=msg): + ArgKminClassMode.compute( + X=X.astype(np.float32), + Y=Y, + k=k, + metric=metric, + weights=weights, + labels=labels, + unique_labels=unique_labels, + ) + + msg = ( + "Only float64 or float32 datasets pairs are supported at this time, " + "got: X.dtype=float64 and Y.dtype=int32" + ) + with pytest.raises(ValueError, match=msg): + ArgKminClassMode.compute( + X=X, + Y=Y.astype(np.int32), + k=k, + metric=metric, + weights=weights, + labels=labels, + unique_labels=unique_labels, + ) + + with pytest.raises(ValueError, match="k == -1, must be >= 1."): + ArgKminClassMode.compute( + X=X, + Y=Y, + k=-1, + metric=metric, + weights=weights, + labels=labels, + unique_labels=unique_labels, + ) + + with pytest.raises(ValueError, match="k == 0, must be >= 1."): + ArgKminClassMode.compute( + X=X, + Y=Y, + k=0, + metric=metric, + weights=weights, + labels=labels, + unique_labels=unique_labels, + ) + + with pytest.raises(ValueError, match="Unrecognized metric"): + ArgKminClassMode.compute( + X=X, + Y=Y, + k=k, + metric="wrong metric", + weights=weights, + labels=labels, + unique_labels=unique_labels, + ) + + with pytest.raises( + ValueError, match=r"Buffer has wrong number of dimensions \(expected 2, got 1\)" + ): + ArgKminClassMode.compute( + X=np.array([1.0, 2.0]), + Y=Y, + k=k, + metric=metric, + weights=weights, + labels=labels, + unique_labels=unique_labels, + ) + + with pytest.raises(ValueError, match="ndarray is not C-contiguous"): + ArgKminClassMode.compute( + X=np.asfortranarray(X), + Y=Y, + k=k, + metric=metric, + weights=weights, + labels=labels, + unique_labels=unique_labels, + ) + + non_existent_weights_strategy = "non_existent_weights_strategy" + message = ( + "Only the 'uniform' or 'distance' weights options are supported at this time. " + f"Got: weights='{non_existent_weights_strategy}'." + ) + with pytest.raises(ValueError, match=message): + ArgKminClassMode.compute( + X=X, + Y=Y, + k=k, + metric=metric, + weights=non_existent_weights_strategy, + labels=labels, + unique_labels=unique_labels, + ) + + # TODO: introduce assertions on UserWarnings once the Euclidean specialisation + # of ArgKminClassMode is supported. + + def test_radius_neighbors_factory_method_wrong_usages(): rng = np.random.RandomState(1) X = rng.rand(100, 10) @@ -1222,3 +1340,36 @@ def test_sqeuclidean_row_norms( with pytest.raises(ValueError): X = np.asfortranarray(X) sqeuclidean_row_norms(X, num_threads=num_threads) + + +def test_argkmin_classmode_strategy_consistent(): + rng = np.random.RandomState(1) + X = rng.rand(100, 10) + Y = rng.rand(100, 10) + k = 5 + metric = "manhattan" + + weights = "uniform" + labels = rng.randint(low=0, high=10, size=100) + unique_labels = np.unique(labels) + results_X = ArgKminClassMode.compute( + X=X, + Y=Y, + k=k, + metric=metric, + weights=weights, + labels=labels, + unique_labels=unique_labels, + strategy="parallel_on_X", + ) + results_Y = ArgKminClassMode.compute( + X=X, + Y=Y, + k=k, + metric=metric, + weights=weights, + labels=labels, + unique_labels=unique_labels, + strategy="parallel_on_Y", + ) + assert_array_equal(results_X, results_Y) diff --git a/sklearn/neighbors/_base.py b/sklearn/neighbors/_base.py index 88febbd9a3aea..9e3dfa248f00e 100644 --- a/sklearn/neighbors/_base.py +++ b/sklearn/neighbors/_base.py @@ -475,7 +475,10 @@ def _fit(self, X, y=None): check_classification_targets(y) self.classes_ = [] - self._y = np.empty(y.shape, dtype=int) + # Using `dtype=np.intp` is necessary since `np.bincount` + # (called in _classification.py) fails when dealing + # with a float64 array on 32bit systems. + self._y = np.empty(y.shape, dtype=np.intp) for k in range(self._y.shape[1]): classes, self._y[:, k] = np.unique(y[:, k], return_inverse=True) self.classes_.append(classes) diff --git a/sklearn/neighbors/_classification.py b/sklearn/neighbors/_classification.py index b849d28e131a5..dbc070987d5d0 100644 --- a/sklearn/neighbors/_classification.py +++ b/sklearn/neighbors/_classification.py @@ -12,13 +12,24 @@ import numpy as np from ..utils.fixes import _mode from ..utils.extmath import weighted_mode -from ..utils.validation import _is_arraylike, _num_samples +from ..utils.validation import _is_arraylike, _num_samples, check_is_fitted import warnings from ._base import _get_weights from ._base import NeighborsBase, KNeighborsMixin, RadiusNeighborsMixin from ..base import ClassifierMixin +from ..metrics._pairwise_distances_reduction import ArgKminClassMode from ..utils._param_validation import StrOptions +from sklearn.neighbors._base import _check_precomputed + + +def _adjusted_metric(metric, metric_kwargs, p=None): + metric_kwargs = metric_kwargs or {} + if metric == "minkowski": + metric_kwargs["p"] = p + if p == 2: + metric = "euclidean" + return metric, metric_kwargs class KNeighborsClassifier(KNeighborsMixin, ClassifierMixin, NeighborsBase): @@ -228,7 +239,21 @@ def predict(self, X): y : ndarray of shape (n_queries,) or (n_queries, n_outputs) Class labels for each data sample. """ + check_is_fitted(self, "_fit_method") if self.weights == "uniform": + if self._fit_method == "brute" and ArgKminClassMode.is_usable_for( + X, self._fit_X, self.metric + ): + probabilities = self.predict_proba(X) + if self.outputs_2d_: + return np.stack( + [ + self.classes_[idx][np.argmax(probas, axis=1)] + for idx, probas in enumerate(probabilities) + ], + axis=1, + ) + return self.classes_[np.argmax(probabilities, axis=1)] # In that case, we do not need the distances to perform # the weighting so we do not compute them. neigh_ind = self.kneighbors(X, return_distance=False) @@ -277,7 +302,47 @@ def predict_proba(self, X): The class probabilities of the input samples. Classes are ordered by lexicographic order. """ + check_is_fitted(self, "_fit_method") if self.weights == "uniform": + # TODO: systematize this mapping of metric for + # PairwiseDistancesReductions. + metric, metric_kwargs = _adjusted_metric( + metric=self.metric, metric_kwargs=self.metric_params, p=self.p + ) + if ( + self._fit_method == "brute" + and ArgKminClassMode.is_usable_for(X, self._fit_X, metric) + # TODO: Implement efficient multi-output solution + and not self.outputs_2d_ + ): + if self.metric == "precomputed": + X = _check_precomputed(X) + else: + X = self._validate_data( + X, accept_sparse="csr", reset=False, order="C" + ) + + probabilities = ArgKminClassMode.compute( + X, + self._fit_X, + k=self.n_neighbors, + weights=self.weights, + labels=self._y, + unique_labels=self.classes_, + metric=metric, + metric_kwargs=metric_kwargs, + # `strategy="parallel_on_X"` has in practice be shown + # to be more efficient than `strategy="parallel_on_Y`` + # on many combination of datasets. + # Hence, we choose to enforce it here. + # For more information, see: + # https://github.com/scikit-learn/scikit-learn/pull/24076#issuecomment-1445258342 # noqa + # TODO: adapt the heuristic for `strategy="auto"` for + # `ArgKminClassMode` and use `strategy="auto"`. + strategy="parallel_on_X", + ) + return probabilities + # In that case, we do not need the distances to perform # the weighting so we do not compute them. neigh_ind = self.kneighbors(X, return_distance=False) diff --git a/sklearn/neighbors/tests/test_neighbors.py b/sklearn/neighbors/tests/test_neighbors.py index b82d369f2c12c..4ef2831990f0a 100644 --- a/sklearn/neighbors/tests/test_neighbors.py +++ b/sklearn/neighbors/tests/test_neighbors.py @@ -675,15 +675,18 @@ def test_kneighbors_classifier_predict_proba(global_dtype): cls = neighbors.KNeighborsClassifier(n_neighbors=3, p=1) # cityblock dist cls.fit(X, y) y_prob = cls.predict_proba(X) - real_prob = np.array( - [ - [0, 2.0 / 3, 1.0 / 3], - [1.0 / 3, 2.0 / 3, 0], - [1.0 / 3, 0, 2.0 / 3], - [0, 1.0 / 3, 2.0 / 3], - [2.0 / 3, 1.0 / 3, 0], - [2.0 / 3, 1.0 / 3, 0], - ] + real_prob = ( + np.array( + [ + [0, 2, 1], + [1, 2, 0], + [1, 0, 2], + [0, 1, 2], + [2, 1, 0], + [2, 1, 0], + ] + ) + / 3.0 ) assert_array_equal(real_prob, y_prob) # Check that it also works with non integer labels From 2a5662e4b13f82a0dcdefbf8a3294c98e715e7e4 Mon Sep 17 00:00:00 2001 From: zeeshan lone <56621467+still-learning-ev@users.noreply.github.com> Date: Tue, 14 Mar 2023 18:31:40 +0530 Subject: [PATCH 033/230] MAINT Added Parameter Validation for datasets.make_circles (#25848) Co-authored-by: jeremiedbb --- sklearn/datasets/_samples_generator.py | 26 ++++++++++--------- .../datasets/tests/test_samples_generator.py | 13 +--------- sklearn/tests/test_public_functions.py | 1 + 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 9a972ba031bd3..a3495b358354f 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -672,6 +672,15 @@ def make_regression( return X, y +@validate_params( + { + "n_samples": [Interval(Integral, 0, None, closed="left"), tuple], + "shuffle": ["boolean"], + "noise": [Interval(Real, 0, None, closed="left"), None], + "random_state": ["random_state"], + "factor": [Interval(Real, 0, 1, closed="left")], + } +) def make_circles( n_samples=100, *, shuffle=True, noise=None, random_state=None, factor=0.8 ): @@ -706,7 +715,7 @@ def make_circles( See :term:`Glossary `. factor : float, default=.8 - Scale factor between inner and outer circle in the range `(0, 1)`. + Scale factor between inner and outer circle in the range `[0, 1)`. Returns ------- @@ -716,20 +725,13 @@ def make_circles( y : ndarray of shape (n_samples,) The integer labels (0 or 1) for class membership of each sample. """ - - if factor >= 1 or factor < 0: - raise ValueError("'factor' has to be between 0 and 1.") - if isinstance(n_samples, numbers.Integral): n_samples_out = n_samples // 2 n_samples_in = n_samples - n_samples_out - else: - try: - n_samples_out, n_samples_in = n_samples - except ValueError as e: - raise ValueError( - "`n_samples` can be either an int or a two-element tuple." - ) from e + else: # n_samples is a tuple + if len(n_samples) != 2: + raise ValueError("When a tuple, n_samples must have exactly two elements.") + n_samples_out, n_samples_in = n_samples generator = check_random_state(random_state) # so as not to have the first point = last point, we set endpoint=False diff --git a/sklearn/datasets/tests/test_samples_generator.py b/sklearn/datasets/tests/test_samples_generator.py index 09c245667c0a3..13df2bc796a55 100644 --- a/sklearn/datasets/tests/test_samples_generator.py +++ b/sklearn/datasets/tests/test_samples_generator.py @@ -688,11 +688,6 @@ def test_make_circles(): 2, ), "Samples not correctly distributed across circles." - with pytest.raises(ValueError): - make_circles(factor=-0.01) - with pytest.raises(ValueError): - make_circles(factor=1.0) - def test_make_circles_unbalanced(): X, y = make_circles(n_samples=(2, 8)) @@ -704,12 +699,6 @@ def test_make_circles_unbalanced(): with pytest.raises( ValueError, - match=r"`n_samples` can be either an int " r"or a two-element tuple.", - ): - make_circles(n_samples=[1, 2, 3]) - - with pytest.raises( - ValueError, - match=r"`n_samples` can be either an int " r"or a two-element tuple.", + match="When a tuple, n_samples must have exactly two elements.", ): make_circles(n_samples=(10,)) diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 31aeb37c5e536..c89ce2481bd61 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -111,6 +111,7 @@ def _check_function_param_validation( "sklearn.datasets.fetch_olivetti_faces", "sklearn.datasets.load_svmlight_file", "sklearn.datasets.load_svmlight_files", + "sklearn.datasets.make_circles", "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", "sklearn.datasets.make_sparse_coded_signal", From afdfbea99b497054cf5a46be50e3f900f8d98dc9 Mon Sep 17 00:00:00 2001 From: Adrin Jalali Date: Tue, 14 Mar 2023 15:40:43 +0100 Subject: [PATCH 034/230] MNT use a single job by default with sphinx build (#25836) --- build_tools/circle/build_doc.sh | 5 ----- doc/Makefile | 8 ++------ 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/build_tools/circle/build_doc.sh b/build_tools/circle/build_doc.sh index bc7fb67b33f40..9f6733373ca20 100755 --- a/build_tools/circle/build_doc.sh +++ b/build_tools/circle/build_doc.sh @@ -189,11 +189,6 @@ ccache -s export OMP_NUM_THREADS=1 -# Avoid CI job getting killed because it uses too much memory -if [[ -z $SPHINX_NUMJOBS ]]; then - export SPHINX_NUMJOBS=2 -fi - if [[ "$CIRCLE_BRANCH" =~ ^main$ && -z "$CI_PULL_REQUEST" ]] then # List available documentation versions if on main diff --git a/doc/Makefile b/doc/Makefile index 02656feba0710..b56a1289cd581 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -7,12 +7,8 @@ SPHINXBUILD ?= sphinx-build PAPER = BUILDDIR = _build -# Disable multiple jobs on OSX -ifeq ($(shell uname), Darwin) - SPHINX_NUMJOBS ?= 1 -else - SPHINX_NUMJOBS ?= auto -endif +# Run sequential by default, unless SPHINX_NUMJOBS is set. +SPHINX_NUMJOBS ?= 1 ifneq ($(EXAMPLES_PATTERN),) EXAMPLES_PATTERN_OPTS := -D sphinx_gallery_conf.filename_pattern="$(EXAMPLES_PATTERN)" From 951772bacef0f1e23db7f3b69f6ae2e993d65fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:51:24 +0100 Subject: [PATCH 035/230] BLD Generate warning automatically for templated cython files (#25842) --- sklearn/_build_utils/__init__.py | 7 +++++++ sklearn/_loss/_loss.pyx.tp | 5 ----- sklearn/linear_model/_sag_fast.pyx.tp | 14 +------------- sklearn/linear_model/_sgd_fast.pyx.tp | 8 +------- sklearn/utils/_seq_dataset.pxd.tp | 12 ++++-------- sklearn/utils/_seq_dataset.pyx.tp | 13 +++++-------- sklearn/utils/_weight_vector.pxd.tp | 2 -- sklearn/utils/_weight_vector.pyx.tp | 2 -- 8 files changed, 18 insertions(+), 45 deletions(-) diff --git a/sklearn/_build_utils/__init__.py b/sklearn/_build_utils/__init__.py index d539c0c06ecc1..b31b4c4f67078 100644 --- a/sklearn/_build_utils/__init__.py +++ b/sklearn/_build_utils/__init__.py @@ -103,5 +103,12 @@ def gen_from_templates(templates): tmpl_ = Tempita.sub(tmpl) + warn_msg = ( + "# WARNING: Do not edit this file directly.\n" + f"# It is automatically generated from {template!r}.\n" + "# Changes must be made there.\n\n" + ) + with open(outfile, "w") as f: + f.write(warn_msg) f.write(tmpl_) diff --git a/sklearn/_loss/_loss.pyx.tp b/sklearn/_loss/_loss.pyx.tp index efb40d678e3f6..ae4fee45540db 100644 --- a/sklearn/_loss/_loss.pyx.tp +++ b/sklearn/_loss/_loss.pyx.tp @@ -181,11 +181,6 @@ class_list = [ "cgradient_half_binomial", "cgrad_hess_half_binomial"), ] }} -""" -WARNING: Do not edit `sklearn/_loss/_loss.pyx` file directly, as it is generated from -`sklearn/_loss/_loss.pyx.tp`. Changes must be made there. -""" -#------------------------------------------------------------------------------ # Design: # See https://github.com/scikit-learn/scikit-learn/issues/15123 for reasons. diff --git a/sklearn/linear_model/_sag_fast.pyx.tp b/sklearn/linear_model/_sag_fast.pyx.tp index 5449d5bf4ad02..97bf3020d6602 100644 --- a/sklearn/linear_model/_sag_fast.pyx.tp +++ b/sklearn/linear_model/_sag_fast.pyx.tp @@ -24,19 +24,7 @@ dtypes = [('64', 'double', 'np.float64'), ('32', 'float', 'np.float32')] }} - -#------------------------------------------------------------------------------ - -# Authors: Danny Sullivan -# Tom Dupre la Tour -# Arthur Mensch Date: Tue, 14 Mar 2023 20:53:28 +0530 Subject: [PATCH 036/230] MAINT parameter validation for sklearn.datasets.fetch_lfw_people (#25820) Co-authored-by: jeremiedbb --- sklearn/datasets/_lfw.py | 15 ++++++++++++++- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sklearn/datasets/_lfw.py b/sklearn/datasets/_lfw.py index 7252c050bef3c..c6f1a5f9a90c8 100644 --- a/sklearn/datasets/_lfw.py +++ b/sklearn/datasets/_lfw.py @@ -10,7 +10,8 @@ from os import listdir, makedirs, remove from os.path import join, exists, isdir - +from ..utils._param_validation import validate_params, Interval, Hidden +from numbers import Integral, Real import logging import numpy as np @@ -231,6 +232,18 @@ def _fetch_lfw_people( return faces, target, target_names +@validate_params( + { + "data_home": [str, None], + "funneled": ["boolean"], + "resize": [Interval(Real, 0, None, closed="neither"), None], + "min_faces_per_person": [Interval(Integral, 0, None, closed="left"), None], + "color": ["boolean"], + "slice_": [tuple, Hidden(None)], + "download_if_missing": ["boolean"], + "return_X_y": ["boolean"], + } +) def fetch_lfw_people( *, data_home=None, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index c89ce2481bd61..ece939d5cc922 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -108,6 +108,7 @@ def _check_function_param_validation( "sklearn.datasets.fetch_california_housing", "sklearn.datasets.fetch_covtype", "sklearn.datasets.fetch_kddcup99", + "sklearn.datasets.fetch_lfw_people", "sklearn.datasets.fetch_olivetti_faces", "sklearn.datasets.load_svmlight_file", "sklearn.datasets.load_svmlight_files", From f31a1130512f766a79a71884f514568617d9b314 Mon Sep 17 00:00:00 2001 From: AymericBasset <45051041+AymericBasset@users.noreply.github.com> Date: Tue, 14 Mar 2023 17:11:08 +0100 Subject: [PATCH 037/230] MAINT Parameters validation for metrics.fbeta_score (#25841) --- sklearn/metrics/_classification.py | 18 ++++++++++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 19 insertions(+) diff --git a/sklearn/metrics/_classification.py b/sklearn/metrics/_classification.py index 88b8af7944ecc..9aba3f57a54e6 100644 --- a/sklearn/metrics/_classification.py +++ b/sklearn/metrics/_classification.py @@ -1227,6 +1227,24 @@ def f1_score( ) +@validate_params( + { + "y_true": ["array-like", "sparse matrix"], + "y_pred": ["array-like", "sparse matrix"], + "beta": [Interval(Real, 0.0, None, closed="both")], + "labels": ["array-like", None], + "pos_label": [Real, str, "boolean", None], + "average": [ + StrOptions({"micro", "macro", "samples", "weighted", "binary"}), + None, + ], + "sample_weight": ["array-like", None], + "zero_division": [ + Options(Real, {0, 1}), + StrOptions({"warn"}), + ], + } +) def fbeta_score( y_true, y_pred, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index ece939d5cc922..3aaeaf0abff27 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -139,6 +139,7 @@ def _check_function_param_validation( "sklearn.metrics.dcg_score", "sklearn.metrics.det_curve", "sklearn.metrics.f1_score", + "sklearn.metrics.fbeta_score", "sklearn.metrics.get_scorer", "sklearn.metrics.hamming_loss", "sklearn.metrics.jaccard_score", From 548bf03bf338741b3f9bf2e4a9577e48e0ceed7a Mon Sep 17 00:00:00 2001 From: Maren Westermann Date: Tue, 14 Mar 2023 18:26:35 +0100 Subject: [PATCH 038/230] TST add global_random_seed fixture to sklearn/covariance/tests/test_robust_covariance.py (#25821) --- .../tests/test_robust_covariance.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sklearn/covariance/tests/test_robust_covariance.py b/sklearn/covariance/tests/test_robust_covariance.py index 9bb93328b17a2..97a6cfb1d738d 100644 --- a/sklearn/covariance/tests/test_robust_covariance.py +++ b/sklearn/covariance/tests/test_robust_covariance.py @@ -20,24 +20,24 @@ n_samples, n_features = X.shape -def test_mcd(): +def test_mcd(global_random_seed): # Tests the FastMCD algorithm implementation # Small data set # test without outliers (random independent normal data) - launch_mcd_on_dataset(100, 5, 0, 0.01, 0.1, 80) + launch_mcd_on_dataset(100, 5, 0, 0.02, 0.1, 75, global_random_seed) # test with a contaminated data set (medium contamination) - launch_mcd_on_dataset(100, 5, 20, 0.01, 0.01, 70) + launch_mcd_on_dataset(100, 5, 20, 0.3, 0.3, 65, global_random_seed) # test with a contaminated data set (strong contamination) - launch_mcd_on_dataset(100, 5, 40, 0.1, 0.1, 50) + launch_mcd_on_dataset(100, 5, 40, 0.1, 0.1, 50, global_random_seed) # Medium data set - launch_mcd_on_dataset(1000, 5, 450, 0.1, 0.1, 540) + launch_mcd_on_dataset(1000, 5, 450, 0.1, 0.1, 540, global_random_seed) # Large data set - launch_mcd_on_dataset(1700, 5, 800, 0.1, 0.1, 870) + launch_mcd_on_dataset(1700, 5, 800, 0.1, 0.1, 870, global_random_seed) # 1D data set - launch_mcd_on_dataset(500, 1, 100, 0.001, 0.001, 350) + launch_mcd_on_dataset(500, 1, 100, 0.02, 0.02, 350, global_random_seed) def test_fast_mcd_on_invalid_input(): @@ -56,10 +56,10 @@ def test_mcd_class_on_invalid_input(): def launch_mcd_on_dataset( - n_samples, n_features, n_outliers, tol_loc, tol_cov, tol_support + n_samples, n_features, n_outliers, tol_loc, tol_cov, tol_support, seed ): - rand_gen = np.random.RandomState(0) + rand_gen = np.random.RandomState(seed) data = rand_gen.randn(n_samples, n_features) # add some outliers outliers_index = rand_gen.permutation(n_samples)[:n_outliers] @@ -70,7 +70,7 @@ def launch_mcd_on_dataset( pure_data = data[inliers_mask] # compute MCD by fitting an object - mcd_fit = MinCovDet(random_state=rand_gen).fit(data) + mcd_fit = MinCovDet(random_state=seed).fit(data) T = mcd_fit.location_ S = mcd_fit.covariance_ H = mcd_fit.support_ @@ -92,10 +92,10 @@ def test_mcd_issue1127(): mcd.fit(X) -def test_mcd_issue3367(): +def test_mcd_issue3367(global_random_seed): # Check that MCD completes when the covariance matrix is singular # i.e. one of the rows and columns are all zeros - rand_gen = np.random.RandomState(0) + rand_gen = np.random.RandomState(global_random_seed) # Think of these as the values for X and Y -> 10 values between -5 and 5 data_values = np.linspace(-5, 5, 10).tolist() @@ -140,7 +140,7 @@ def test_mcd_support_covariance_is_zero(): MinCovDet().fit(X) -def test_mcd_increasing_det_warning(): +def test_mcd_increasing_det_warning(global_random_seed): # Check that a warning is raised if we observe increasing determinants # during the c_step. In theory the sequence of determinants should be # decreasing. Increasing determinants are likely due to ill-conditioned @@ -168,7 +168,7 @@ def test_mcd_increasing_det_warning(): [5.2, 3.5, 1.5, 0.2], ] - mcd = MinCovDet(random_state=1) + mcd = MinCovDet(support_fraction=0.5, random_state=global_random_seed) warn_msg = "Determinant has increased" with pytest.warns(RuntimeWarning, match=warn_msg): mcd.fit(X) From 349e0ecd362ebf7911f0bd9825fb8adbd53b041a Mon Sep 17 00:00:00 2001 From: Nishu Choudhary <51842539+choudharynishu@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:08:32 -0400 Subject: [PATCH 039/230] MAINT Parameter validation for linear_model.orthogonal_mp (#25817) --- sklearn/linear_model/_omp.py | 19 ++++++++++++++----- sklearn/linear_model/tests/test_omp.py | 2 +- sklearn/tests/test_public_functions.py | 1 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/sklearn/linear_model/_omp.py b/sklearn/linear_model/_omp.py index f0bd04568c473..b1dc1e352fd62 100644 --- a/sklearn/linear_model/_omp.py +++ b/sklearn/linear_model/_omp.py @@ -18,6 +18,7 @@ from ..utils import as_float_array, check_array from ..utils.parallel import delayed, Parallel from ..utils._param_validation import Hidden, Interval, StrOptions +from ..utils._param_validation import validate_params from ..model_selection import check_cv premature = ( @@ -281,6 +282,18 @@ def _gram_omp( return gamma, indices[:n_active], n_active +@validate_params( + { + "X": ["array-like"], + "y": [np.ndarray], + "n_nonzero_coefs": [Interval(Integral, 1, None, closed="left"), None], + "tol": [Interval(Real, 0, None, closed="left"), None], + "precompute": ["boolean", StrOptions({"auto"})], + "copy_X": ["boolean"], + "return_path": ["boolean"], + "return_n_iter": ["boolean"], + } +) def orthogonal_mp( X, y, @@ -308,7 +321,7 @@ def orthogonal_mp( Parameters ---------- - X : ndarray of shape (n_samples, n_features) + X : array-like of shape (n_samples, n_features) Input data. Columns are assumed to have unit norm. y : ndarray of shape (n_samples,) or (n_samples, n_targets) @@ -380,10 +393,6 @@ def orthogonal_mp( # default for n_nonzero_coefs is 0.1 * n_features # but at least one. n_nonzero_coefs = max(int(0.1 * X.shape[1]), 1) - if tol is not None and tol < 0: - raise ValueError("Epsilon cannot be negative") - if tol is None and n_nonzero_coefs <= 0: - raise ValueError("The number of atoms must be positive") if tol is None and n_nonzero_coefs > X.shape[1]: raise ValueError( "The number of atoms cannot be more than the number of features" diff --git a/sklearn/linear_model/tests/test_omp.py b/sklearn/linear_model/tests/test_omp.py index 6aecd9abc6505..599e2940f9403 100644 --- a/sklearn/linear_model/tests/test_omp.py +++ b/sklearn/linear_model/tests/test_omp.py @@ -120,7 +120,7 @@ def test_unreachable_accuracy(): @pytest.mark.parametrize("positional_params", [(X, y), (G, Xy)]) @pytest.mark.parametrize( "keyword_params", - [{"tol": -1}, {"n_nonzero_coefs": -1}, {"n_nonzero_coefs": n_features + 1}], + [{"n_nonzero_coefs": n_features + 1}], ) def test_bad_input(positional_params, keyword_params): with pytest.raises(ValueError): diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 3aaeaf0abff27..a9fff191b06a7 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -126,6 +126,7 @@ def _check_function_param_validation( "sklearn.feature_selection.f_regression", "sklearn.feature_selection.mutual_info_classif", "sklearn.feature_selection.r_regression", + "sklearn.linear_model.orthogonal_mp", "sklearn.metrics.accuracy_score", "sklearn.metrics.auc", "sklearn.metrics.average_precision_score", From 467d7b537293d8dca756bdacbb45b75ec665d67e Mon Sep 17 00:00:00 2001 From: Guillaume Lemaitre Date: Tue, 14 Mar 2023 20:37:35 +0100 Subject: [PATCH 040/230] TST activate common tests for TSNE (#25374) --- sklearn/manifold/_t_sne.py | 9 +++++-- sklearn/utils/estimator_checks.py | 45 ++++++++++++++++++------------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/sklearn/manifold/_t_sne.py b/sklearn/manifold/_t_sne.py index 99ec6ea0876f2..61d43606dedb9 100644 --- a/sklearn/manifold/_t_sne.py +++ b/sklearn/manifold/_t_sne.py @@ -17,7 +17,7 @@ from scipy.sparse import csr_matrix, issparse from numbers import Integral, Real from ..neighbors import NearestNeighbors -from ..base import BaseEstimator +from ..base import BaseEstimator, ClassNamePrefixFeaturesOutMixin, TransformerMixin from ..utils import check_random_state from ..utils._openmp_helpers import _openmp_effective_n_threads from ..utils.validation import check_non_negative @@ -537,7 +537,7 @@ def trustworthiness(X, X_embedded, *, n_neighbors=5, metric="euclidean"): return t -class TSNE(BaseEstimator): +class TSNE(ClassNamePrefixFeaturesOutMixin, TransformerMixin, BaseEstimator): """T-distributed Stochastic Neighbor Embedding. t-SNE [1] is a tool to visualize high-dimensional data. It converts @@ -1145,5 +1145,10 @@ def fit(self, X, y=None): self.fit_transform(X) return self + @property + def _n_features_out(self): + """Number of transformed output features.""" + return self.embedding_.shape[1] + def _more_tags(self): return {"pairwise": self.metric == "precomputed"} diff --git a/sklearn/utils/estimator_checks.py b/sklearn/utils/estimator_checks.py index 9eb666c68984d..14aaf8b40e8e0 100644 --- a/sklearn/utils/estimator_checks.py +++ b/sklearn/utils/estimator_checks.py @@ -4234,9 +4234,14 @@ def fit_then_transform(est): def fit_transform(est): return est.fit_transform(X, y) - transform_methods = [fit_then_transform, fit_transform] - for transform_method in transform_methods: + transform_methods = { + "transform": fit_then_transform, + "fit_transform": fit_transform, + } + for name, transform_method in transform_methods.items(): transformer = clone(transformer) + if not hasattr(transformer, name): + continue X_trans_no_setting = transform_method(transformer) # Auto wrapping only wraps the first array @@ -4269,29 +4274,31 @@ def _output_from_fit_transform(transformer, name, X, df, y): ("fit.transform/array/df", X, df), ("fit.transform/array/array", X, X), ] - for ( - case, - data_fit, - data_transform, - ) in cases: - transformer.fit(data_fit, y) - if name in CROSS_DECOMPOSITION: - X_trans, _ = transformer.transform(data_transform, y) - else: - X_trans = transformer.transform(data_transform) - outputs[case] = (X_trans, transformer.get_feature_names_out()) + if all(hasattr(transformer, meth) for meth in ["fit", "transform"]): + for ( + case, + data_fit, + data_transform, + ) in cases: + transformer.fit(data_fit, y) + if name in CROSS_DECOMPOSITION: + X_trans, _ = transformer.transform(data_transform, y) + else: + X_trans = transformer.transform(data_transform) + outputs[case] = (X_trans, transformer.get_feature_names_out()) # fit_transform case: cases = [ ("fit_transform/df", df), ("fit_transform/array", X), ] - for case, data in cases: - if name in CROSS_DECOMPOSITION: - X_trans, _ = transformer.fit_transform(data, y) - else: - X_trans = transformer.fit_transform(data, y) - outputs[case] = (X_trans, transformer.get_feature_names_out()) + if hasattr(transformer, "fit_transform"): + for case, data in cases: + if name in CROSS_DECOMPOSITION: + X_trans, _ = transformer.fit_transform(data, y) + else: + X_trans = transformer.fit_transform(data, y) + outputs[case] = (X_trans, transformer.get_feature_names_out()) return outputs From 3be19ea11a25c50a1006c4d5fe0f4953f7184be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= Date: Wed, 15 Mar 2023 11:36:20 +0100 Subject: [PATCH 041/230] CI Update lock files (#25849) --- build_tools/azure/debian_atlas_32bit_lock.txt | 2 +- ...onda_defaults_openblas_linux-64_conda.lock | 44 +++---- .../py38_conda_forge_mkl_win-64_conda.lock | 74 +++++------ ...e_openblas_ubuntu_2204_linux-64_conda.lock | 110 ++++++++++------- ...latest_conda_forge_mkl_linux-64_conda.lock | 111 +++++++++-------- ..._forge_mkl_no_coverage_linux-64_conda.lock | 109 +++++++++------- ...pylatest_conda_forge_mkl_osx-64_conda.lock | 73 ++++++----- ...test_conda_mkl_no_openmp_osx-64_conda.lock | 51 ++++---- ...st_pip_openblas_pandas_linux-64_conda.lock | 54 ++++---- ...pylatest_pip_scipy_dev_linux-64_conda.lock | 34 ++--- build_tools/azure/pypy3_linux-64_conda.lock | 60 +++++---- build_tools/azure/ubuntu_atlas_lock.txt | 6 +- build_tools/circle/doc_environment.yml | 3 +- build_tools/circle/doc_linux-64_conda.lock | 116 +++++++++--------- .../doc_min_dependencies_linux-64_conda.lock | 54 ++++---- .../py39_conda_forge_linux-aarch64_conda.lock | 54 ++++---- .../update_environments_and_lock_files.py | 3 +- .../calibration/plot_calibration_curve.py | 2 +- .../calibration/plot_compare_calibration.py | 2 +- examples/svm/plot_svm_margin.py | 7 +- sklearn/_min_dependencies.py | 2 +- .../tests/test_confusion_matrix_display.py | 5 +- 22 files changed, 525 insertions(+), 451 deletions(-) diff --git a/build_tools/azure/debian_atlas_32bit_lock.txt b/build_tools/azure/debian_atlas_32bit_lock.txt index cb69c8b876f86..dbcc32cd1ff78 100644 --- a/build_tools/azure/debian_atlas_32bit_lock.txt +++ b/build_tools/azure/debian_atlas_32bit_lock.txt @@ -10,7 +10,7 @@ cython==0.29.33 # via -r build_tools/azure/debian_atlas_32bit_requirements.txt joblib==1.1.1 # via -r build_tools/azure/debian_atlas_32bit_requirements.txt -more-itertools==9.0.0 +more-itertools==9.1.0 # via pytest packaging==23.0 # via pytest diff --git a/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock b/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock index 9e6179c378343..4ca6039ea4824 100644 --- a/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock +++ b/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock @@ -4,7 +4,7 @@ @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 https://repo.anaconda.com/pkgs/main/linux-64/blas-1.0-openblas.conda#9ddfcaef10d79366c90128f5dc444be8 -https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2022.10.11-h06a4308_0.conda#e9b86b388e2cf59585fefca34037b783 +https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2023.01.10-h06a4308_0.conda#7704989a2ccf6c1f5a50c985509841c4 https://repo.anaconda.com/pkgs/main/linux-64/ld_impl_linux-64-2.38-h1181459_1.conda#68eedfd9c06f2b0e6888d8db345b7f5b https://repo.anaconda.com/pkgs/main/linux-64/libgfortran4-7.5.0-ha8ba4b0_17.conda#e3883581cbf0a98672250c3e80d292bf https://repo.anaconda.com/pkgs/main/linux-64/libgfortran-ng-7.5.0-ha8ba4b0_17.conda#ecb35c8952579d5c8dc56c6e076ba948 @@ -13,49 +13,49 @@ https://repo.anaconda.com/pkgs/main/linux-64/libstdcxx-ng-11.2.0-h1234567_1.cond https://repo.anaconda.com/pkgs/main/linux-64/_openmp_mutex-5.1-1_gnu.conda#71d281e9c2192cb3fa425655a8defb85 https://repo.anaconda.com/pkgs/main/linux-64/libgcc-ng-11.2.0-h1234567_1.conda#a87728dabf3151fb9cfa990bd2eb0464 https://repo.anaconda.com/pkgs/main/linux-64/expat-2.4.9-h6a678d5_0.conda#3a6139fbcd96384855f0e6037502bf28 -https://repo.anaconda.com/pkgs/main/linux-64/giflib-5.2.1-h7b6447c_0.conda#c2583ad8de5051f19479580c58336f15 +https://repo.anaconda.com/pkgs/main/linux-64/giflib-5.2.1-h5eee18b_3.conda#aa7d64adb3cd8a75d398167f8c29afc3 https://repo.anaconda.com/pkgs/main/linux-64/icu-58.2-he6710b0_3.conda#48cc14d5ad1a9bcd8dac17211a8deb8b -https://repo.anaconda.com/pkgs/main/linux-64/jpeg-9e-h7f8727e_0.conda#a0571bd2254b360aef526307a17f3526 +https://repo.anaconda.com/pkgs/main/linux-64/jpeg-9e-h5eee18b_1.conda#ac373800fda872108412d1ccfe3fa572 https://repo.anaconda.com/pkgs/main/linux-64/lerc-3.0-h295c915_0.conda#b97309770412f10bed8d9448f6f98f87 -https://repo.anaconda.com/pkgs/main/linux-64/libdeflate-1.8-h7f8727e_5.conda#6942d65edab9a800900f43e750b3ad1f +https://repo.anaconda.com/pkgs/main/linux-64/libdeflate-1.17-h5eee18b_0.conda#b4891fa07ca4cad1c53a0d0e539482da https://repo.anaconda.com/pkgs/main/linux-64/libffi-3.4.2-h6a678d5_6.conda#6d65e299b535d3b3613b6d4bce901834 https://repo.anaconda.com/pkgs/main/linux-64/libopenblas-0.3.18-hf726d26_0.conda#10422bb3b9b022e27798fc368cda69ba https://repo.anaconda.com/pkgs/main/linux-64/libuuid-1.41.5-h5eee18b_0.conda#4a6a2354414c9080327274aa514e5299 -https://repo.anaconda.com/pkgs/main/linux-64/libwebp-base-1.2.4-h5eee18b_0.conda#f5f56389136bcd9ca92ee1d64afcceb3 +https://repo.anaconda.com/pkgs/main/linux-64/libwebp-base-1.2.4-h5eee18b_1.conda#a65a20c48061ecf2a6f4f02eae9f2366 https://repo.anaconda.com/pkgs/main/linux-64/libxcb-1.15-h7f8727e_0.conda#ada518dcadd6aaee9aae47ba9a671553 https://repo.anaconda.com/pkgs/main/linux-64/lz4-c-1.9.4-h6a678d5_0.conda#53915e9402180a7f22ea619c41089520 -https://repo.anaconda.com/pkgs/main/linux-64/ncurses-6.3-h5eee18b_3.conda#0c616f387885c1bbb57ec0bd1e779ced +https://repo.anaconda.com/pkgs/main/linux-64/ncurses-6.4-h6a678d5_0.conda#5558eec6e2191741a92f832ea826251c https://repo.anaconda.com/pkgs/main/linux-64/nspr-4.33-h295c915_0.conda#78454e8819eb6701abc74b2ab2889f21 -https://repo.anaconda.com/pkgs/main/linux-64/openssl-1.1.1s-h7f8727e_0.conda#25f9c4e2394976be98d01cccef2ce43a +https://repo.anaconda.com/pkgs/main/linux-64/openssl-1.1.1t-h7f8727e_0.conda#0410db682c02665511bd4203ade48a32 https://repo.anaconda.com/pkgs/main/linux-64/pcre-8.45-h295c915_0.conda#b32ccc24d1d9808618c1e898da60f68d -https://repo.anaconda.com/pkgs/main/linux-64/xz-5.2.8-h5eee18b_0.conda#224260858072f0071140ae18c513620d +https://repo.anaconda.com/pkgs/main/linux-64/xz-5.2.10-h5eee18b_1.conda#dd172c348274807ec0d841df8295b670 https://repo.anaconda.com/pkgs/main/linux-64/zlib-1.2.13-h5eee18b_0.conda#333e31fbfbb5057c92fa845ad6adef93 https://repo.anaconda.com/pkgs/main/linux-64/ccache-3.7.9-hfe4627d_0.conda#bef6fc681c273bb7bd0c67d1a591365e https://repo.anaconda.com/pkgs/main/linux-64/glib-2.69.1-he621ea3_2.conda#51cf1899782b3f3744aedd143fbc07f3 https://repo.anaconda.com/pkgs/main/linux-64/libedit-3.1.20221030-h5eee18b_0.conda#7c724a17739aceaf9d1633ff06962137 https://repo.anaconda.com/pkgs/main/linux-64/libevent-2.1.12-h8f2d780_0.conda#8de03cd4b6ee0ddeb0571a5199db5637 https://repo.anaconda.com/pkgs/main/linux-64/libllvm10-10.0.1-hbcb73fb_5.conda#198e840fc17a5bff7f1ee543ee1981b2 -https://repo.anaconda.com/pkgs/main/linux-64/libpng-1.6.37-hbc83047_0.conda#689f903925dcf6c5ab7bc1de0f58b67b +https://repo.anaconda.com/pkgs/main/linux-64/libpng-1.6.39-h5eee18b_0.conda#f6aee38184512eb05b06c2e94d39ab22 https://repo.anaconda.com/pkgs/main/linux-64/libxml2-2.9.14-h74e7548_0.conda#2eafeb1cb5f00b034d150f3d70436e52 https://repo.anaconda.com/pkgs/main/linux-64/readline-8.2-h5eee18b_0.conda#be42180685cce6e6b0329201d9f48efb https://repo.anaconda.com/pkgs/main/linux-64/tk-8.6.12-h1ccaba5_0.conda#fa10ff4aa631fa4aa090a6234d7770b9 https://repo.anaconda.com/pkgs/main/linux-64/zstd-1.5.2-ha4553b6_0.conda#0e926a5f2e02fe4a9376ece4b732ce36 https://repo.anaconda.com/pkgs/main/linux-64/dbus-1.13.18-hb2f20db_0.conda#6a6a6f1391f807847404344489ef6cf4 https://repo.anaconda.com/pkgs/main/linux-64/freetype-2.12.1-h4a9f257_0.conda#bdc7b5952e9c5dca01bc2f4ccef2f974 -https://repo.anaconda.com/pkgs/main/linux-64/gstreamer-1.14.0-h28cd5cc_2.conda#6af5d0cbd7310e1cd8a6a5c1c99649b2 -https://repo.anaconda.com/pkgs/main/linux-64/krb5-1.19.2-hac12032_0.conda#62a43976b48799377103390c340a3824 +https://repo.anaconda.com/pkgs/main/linux-64/gstreamer-1.14.1-h5eee18b_1.conda#f2f26e6f869b5d87f41bd059fae47c3e +https://repo.anaconda.com/pkgs/main/linux-64/krb5-1.19.4-h568e23c_0.conda#649816c5e24c76bd06e74a0eb671a82e https://repo.anaconda.com/pkgs/main/linux-64/libclang-10.0.1-default_hb85057a_2.conda#9e39ee5217327ba25e341c629b642247 -https://repo.anaconda.com/pkgs/main/linux-64/libtiff-4.5.0-hecacb30_0.conda#ee78c57621673ab656d341c5cd3de211 +https://repo.anaconda.com/pkgs/main/linux-64/libtiff-4.5.0-h6a678d5_2.conda#b3391ee6956636eb8ef159c1c454e3da https://repo.anaconda.com/pkgs/main/linux-64/libxkbcommon-1.0.1-hfa300c1_0.conda#913e6c7c04026ff341960a9700889498 https://repo.anaconda.com/pkgs/main/linux-64/libxslt-1.1.35-h4e12654_0.conda#328c111d87dccd5a3e471a691833f670 https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.40.1-h5082296_0.conda#7d44bb7460f1b1b0764d63240d7f7f81 https://repo.anaconda.com/pkgs/main/linux-64/fontconfig-2.14.1-h52c9d5c_1.conda#cd3f711abef17203045b7bcfc83fac2f -https://repo.anaconda.com/pkgs/main/linux-64/gst-plugins-base-1.14.0-h8213a91_2.conda#838648422452405b86699e780e293c1d +https://repo.anaconda.com/pkgs/main/linux-64/gst-plugins-base-1.14.1-h6a678d5_1.conda#afd9cbe949d670d24cc0a007aaec1fe1 https://repo.anaconda.com/pkgs/main/linux-64/lcms2-2.12-h3be6417_0.conda#719db47afba9f6586eecb5eacac70bff https://repo.anaconda.com/pkgs/main/linux-64/libpq-12.9-h16c4e8d_3.conda#0f127be216a734916faf456bb21404e9 -https://repo.anaconda.com/pkgs/main/linux-64/libwebp-1.2.4-h11a3e52_0.conda#971acc20767cc834a6baffdeaae6a100 +https://repo.anaconda.com/pkgs/main/linux-64/libwebp-1.2.4-h11a3e52_1.conda#9f9153b30e58e9ce896f74634622cbf1 https://repo.anaconda.com/pkgs/main/linux-64/nss-3.74-h0370c37_0.conda#fb2426b2f3cb17c9015fcbdf917a2f7b -https://repo.anaconda.com/pkgs/main/linux-64/python-3.8.15-h7a1cb2a_2.conda#9252075f5f42bf4bc633fe348bbbb3a4 +https://repo.anaconda.com/pkgs/main/linux-64/python-3.8.16-h7a1cb2a_3.conda#c11c0992727585f5f991760f5b18c968 https://repo.anaconda.com/pkgs/main/linux-64/attrs-22.1.0-py38h06a4308_0.conda#51beb64c6f06b5a69529df7ecaccc3f9 https://repo.anaconda.com/pkgs/main/linux-64/certifi-2022.12.7-py38h06a4308_0.conda#243cddde550e2c3e765db25cdea99a13 https://repo.anaconda.com/pkgs/main/noarch/charset-normalizer-2.0.4-pyhd3eb1b0_0.conda#e7a441d94234b2b5fafee06e25dbf076 @@ -68,7 +68,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/joblib-1.1.1-py38h06a4308_0.conda#e https://repo.anaconda.com/pkgs/main/linux-64/kiwisolver-1.4.4-py38h6a678d5_0.conda#7424aa335d22974192800ec19a68486e https://repo.anaconda.com/pkgs/main/linux-64/numpy-base-1.17.3-py38h2f8d375_0.conda#40edbb76ecacefb1e6ab639b514822b1 https://repo.anaconda.com/pkgs/main/linux-64/packaging-22.0-py38h06a4308_0.conda#f09d8a44adf4dae78562c6f9af3603d6 -https://repo.anaconda.com/pkgs/main/linux-64/pillow-9.3.0-py38hace64e9_1.conda#25eba78d0ac0b82f750c09f89d033097 +https://repo.anaconda.com/pkgs/main/linux-64/pillow-9.4.0-py38h6a678d5_0.conda#8afd1f4f8b23a1c44fca4975253b17f7 https://repo.anaconda.com/pkgs/main/linux-64/pluggy-1.0.0-py38h06a4308_1.conda#87bb1d3f6cf3e409a1dac38cee99918e https://repo.anaconda.com/pkgs/main/linux-64/ply-3.11-py38_0.conda#d6a69c576c6e4d19e3074eaae3d149f2 https://repo.anaconda.com/pkgs/main/noarch/py-1.11.0-pyhd3eb1b0_0.conda#7205a898ed2abbf6e9b903dff6abe08e @@ -82,7 +82,7 @@ https://repo.anaconda.com/pkgs/main/noarch/threadpoolctl-2.2.0-pyh0d69192_0.cond https://repo.anaconda.com/pkgs/main/noarch/toml-0.10.2-pyhd3eb1b0_0.conda#cda05f5f6d8509529d1a2743288d197a https://repo.anaconda.com/pkgs/main/linux-64/tomli-2.0.1-py38h06a4308_0.conda#791cce9de9913e9587b0a85cd8419123 https://repo.anaconda.com/pkgs/main/linux-64/tornado-6.2-py38h5eee18b_0.conda#db2f7ebc500d97a4af6889dfd0d03dbc -https://repo.anaconda.com/pkgs/main/noarch/wheel-0.37.1-pyhd3eb1b0_0.conda#ab85e96e26da8d5797c2458232338b86 +https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.38.4-py38h06a4308_0.conda#52f195e95a5f11c5b9a9eed9cd3d6958 https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.15.1-py38h5eee18b_3.conda#ebf03031554d834c5aafdbed9be24f7f https://repo.anaconda.com/pkgs/main/linux-64/numpy-1.17.3-py38h7e8d029_0.conda#5f2b196b515f8fe6b37e3d224650577d https://repo.anaconda.com/pkgs/main/linux-64/pytest-7.1.2-py38h06a4308_0.conda#8d7f526a3d29273e06957d302f515755 @@ -91,21 +91,21 @@ https://repo.anaconda.com/pkgs/main/linux-64/qt-webengine-5.15.9-hd2b0992_4.cond https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.6.3-py38h06a4308_0.conda#7676b836ec3f9cb1b0f8661d5863d1a4 https://repo.anaconda.com/pkgs/main/linux-64/sip-6.6.2-py38h6a678d5_0.conda#cb3f0d10f7f79870945f4dbbe0000f92 https://repo.anaconda.com/pkgs/main/linux-64/brotlipy-0.7.0-py38h27cfd23_1003.conda#e881c8ee8a4048f29da5d20f0330fe37 -https://repo.anaconda.com/pkgs/main/linux-64/cryptography-38.0.4-py38h9ce1e76_0.conda#069a127658760920e9d53c31325fb8ce +https://repo.anaconda.com/pkgs/main/linux-64/cryptography-39.0.1-py38h9ce1e76_0.conda#ad365e5ba98df04384bb85fe322bc1a4 https://repo.anaconda.com/pkgs/main/linux-64/matplotlib-base-3.1.3-py38hef1b27d_0.conda#a7ad7d097c25b7beeb76f370d51687a1 https://repo.anaconda.com/pkgs/main/linux-64/pandas-1.2.4-py38ha9443f7_0.conda#5bd3fd807a294f387feabc65821b75d0 -https://repo.anaconda.com/pkgs/main/linux-64/pip-22.3.1-py38h06a4308_0.conda#6d68389c38118ff466fa861c8904950c +https://repo.anaconda.com/pkgs/main/linux-64/pip-23.0.1-py38h06a4308_0.conda#76496ff05a04113680df82fd3566e215 https://repo.anaconda.com/pkgs/main/linux-64/pyqt5-sip-12.11.0-py38h6a678d5_1.conda#7bc403c7d55f1465e922964d293d2186 https://repo.anaconda.com/pkgs/main/noarch/pytest-cov-3.0.0-pyhd3eb1b0_0.conda#bbdaac2947f507399816d509107945c2 https://repo.anaconda.com/pkgs/main/noarch/pytest-forked-1.3.0-pyhd3eb1b0_0.tar.bz2#07970bffdc78f417d7f8f1c7e620f5c4 https://repo.anaconda.com/pkgs/main/linux-64/qtwebkit-5.212-h4eab89a_4.conda#7317bbf3f3e66a0a02b07b860783ecff https://repo.anaconda.com/pkgs/main/linux-64/scipy-1.3.2-py38he2b7bc3_0.conda#a9df91d5a41c1f39524fc8a53c56bc29 https://repo.anaconda.com/pkgs/main/linux-64/pyamg-4.2.3-py38h79cecc1_0.conda#6e7f4f94000b244396de8bf4e6ae8dc4 -https://repo.anaconda.com/pkgs/main/noarch/pyopenssl-22.0.0-pyhd3eb1b0_0.conda#1dbbf9422269cd62c7094960d9b43f36 +https://repo.anaconda.com/pkgs/main/linux-64/pyopenssl-23.0.0-py38h06a4308_0.conda#3f667b964a242e8c4463935ea3a3331e https://repo.anaconda.com/pkgs/main/linux-64/pyqt-5.15.7-py38h6a678d5_1.conda#62232dc285be8e7e85ae9596d89b3b95 https://repo.anaconda.com/pkgs/main/noarch/pytest-xdist-2.5.0-pyhd3eb1b0_0.conda#d15cdc4207bcf8ca920822597f1d138d https://repo.anaconda.com/pkgs/main/linux-64/matplotlib-3.1.3-py38_0.conda#70d5f6df438d469dc78f082389ada23d -https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.13-py38h06a4308_0.conda#74608767d976ca14529b126842ffb685 -https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py38h06a4308_0.conda#04d482ea4a1e190d688dee2e4048e49f +https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.14-py38h06a4308_0.conda#c84afcc85e999af5ef824aae356cce6a +https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py38h06a4308_1.conda#657ef918b2c2ee58064feb167e451dc6 https://repo.anaconda.com/pkgs/main/noarch/codecov-2.1.11-pyhd3eb1b0_0.conda#83a743cc928162d53d4066c43468b2c7 # pip cython @ https://files.pythonhosted.org/packages/4c/59/3702d649aeb0fef4dac55036279d3981130cc7024ea2492753f66fb622dd/Cython-0.29.33-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl#sha256=b5e8ce3039ff64000d58cd45b3f6f83e13f032dde7f27bb1ab96070d9213550b diff --git a/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock b/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock index 500d1ce658a01..0460596c2df20 100644 --- a/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock +++ b/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock @@ -15,19 +15,18 @@ https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-core-5.3.0-7.tar.bz https://conda.anaconda.org/conda-forge/win-64/vc-14.3-hb6edc58_10.conda#52d246d8d14b83c516229be5bb03a163 https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h8ffe710_4.tar.bz2#7c03c66026944073040cb19a4f3ec3c9 https://conda.anaconda.org/conda-forge/win-64/icu-70.1-h0e60522_0.tar.bz2#64073396a905b6df895ab2489fae3847 -https://conda.anaconda.org/conda-forge/win-64/jpeg-9e-h8ffe710_2.tar.bz2#733066523147548ce368a9bd0c8395af https://conda.anaconda.org/conda-forge/win-64/lerc-4.0.0-h63175ca_0.tar.bz2#1900cb3cab5055833cfddb0ba233b074 https://conda.anaconda.org/conda-forge/win-64/libbrotlicommon-1.0.9-hcfcfb64_8.tar.bz2#e8078e37208cd7d3e1eb5053f370ded8 https://conda.anaconda.org/conda-forge/win-64/libdeflate-1.17-hcfcfb64_0.conda#ae9dfb57bcb42093a2417aceabb530f7 https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2#2c96d1b6915b408893f9472569dee135 https://conda.anaconda.org/conda-forge/win-64/libiconv-1.17-h8ffe710_0.tar.bz2#050119977a86e4856f0416e2edcf81bb -https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-2.1.4-hcfcfb64_0.tar.bz2#24bf30c2957c1bf33b3e1131a88ae17d +https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-2.1.5.1-hcfcfb64_0.conda#f2fad2ae9f1365e343e4329fdb1e9d63 https://conda.anaconda.org/conda-forge/win-64/libogg-1.3.4-h8ffe710_1.tar.bz2#04286d905a0dcb7f7d4a12bdfe02516d https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_0.tar.bz2#5e5a97795de72f8cc3baf3d9ea6327a2 -https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.2.4-h8ffe710_0.tar.bz2#0a09bd195ebeaff5711ccae93ac132ad +https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.3.0-hcfcfb64_0.conda#381a3645c51cbf478872899b16490318 https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#0cc5c5cc64ee1637f37f8540a175854c https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libgfortran-5.3.0-6.tar.bz2#066552ac6b907ec6d72c0ddab29050dc -https://conda.anaconda.org/conda-forge/win-64/openssl-3.0.7-hcfcfb64_1.conda#e48b661f57b25ddf34996fa8b685182d +https://conda.anaconda.org/conda-forge/win-64/openssl-3.0.8-hcfcfb64_0.conda#46cd47b2c18522b98c34e5101e583137 https://conda.anaconda.org/conda-forge/win-64/pthreads-win32-2.9.1-hfa6e2cd_3.tar.bz2#e2da8758d7d51ff6aa78a14dfb9dbed4 https://conda.anaconda.org/conda-forge/win-64/tk-8.6.12-h8ffe710_0.tar.bz2#c69a5047cc9291ae40afd4a1ad6f0c0f https://conda.anaconda.org/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2#515d77642eaa3639413c6b1bc3f94219 @@ -35,15 +34,14 @@ https://conda.anaconda.org/conda-forge/win-64/gettext-0.21.1-h5728263_0.tar.bz2# https://conda.anaconda.org/conda-forge/win-64/krb5-1.20.1-heb0366b_0.conda#a07b05ee8f451ab15698397185efe989 https://conda.anaconda.org/conda-forge/win-64/libbrotlidec-1.0.9-hcfcfb64_8.tar.bz2#99839d9d81f33afa173c0fa82a702038 https://conda.anaconda.org/conda-forge/win-64/libbrotlienc-1.0.9-hcfcfb64_8.tar.bz2#88e62627120c20289bf8982b15e0a6a1 -https://conda.anaconda.org/conda-forge/win-64/libclang13-15.0.7-default_h77d9078_0.conda#fcc96fd81e1cbff83d87e7c641fecbcf +https://conda.anaconda.org/conda-forge/win-64/libclang13-15.0.7-default_h77d9078_1.conda#799890c6c093e7a64ea0dcb3d4f90115 https://conda.anaconda.org/conda-forge/win-64/libpng-1.6.39-h19919ed_0.conda#ab6febdb2dbd9c00803609079db4de71 https://conda.anaconda.org/conda-forge/win-64/libvorbis-1.3.7-h0e60522_0.tar.bz2#e1a22282de0169c93e4ffe6ce6acc212 https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.3-hc3477c8_0.tar.bz2#6dcf17bf780618ddb559d992ea3b6961 https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2#fe759119b8b3bfa720b8762c6fdc35de https://conda.anaconda.org/conda-forge/win-64/pcre2-10.40-h17e33f8_0.tar.bz2#2519de0d9620dc2bc7e19caf6867136d -https://conda.anaconda.org/conda-forge/win-64/python-3.8.15-h4de0772_0_cpython.conda#4059e596f8d7d983bee86bd6845081dc -https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.2-h7755175_4.tar.bz2#13acb3626fcc8c0577249f3a7b6129f4 -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b +https://conda.anaconda.org/conda-forge/win-64/python-3.8.16-h4de0772_1_cpython.conda#461d9fc92cfde68f2ca7ef0988f6326a +https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.2-h12be248_6.conda#62826565682d013b3e2346aaf7bded0e https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/win-64/brotli-bin-1.0.9-hcfcfb64_8.tar.bz2#e18b70ed349d96086fd60a9c642b1b58 https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6 @@ -51,16 +49,16 @@ https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1a https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb https://conda.anaconda.org/conda-forge/win-64/cython-0.29.33-py38hd3f51b4_0.conda#b293ec88e1a282b175b5affc93a8a32d -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 https://conda.anaconda.org/conda-forge/win-64/freetype-2.12.1-h546665d_1.conda#1b513009cd012591f3fdc9e03a74ec0a https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/win-64/kiwisolver-1.4.4-py38hb1fd069_1.tar.bz2#1dcc50e3241f9e4e59713eec2653abd5 -https://conda.anaconda.org/conda-forge/win-64/libclang-15.0.7-default_h77d9078_0.conda#af562fa0445ab8a9cca5830c24113150 +https://conda.anaconda.org/conda-forge/win-64/libclang-15.0.7-default_h77d9078_1.conda#bb88f267b895a8156c75ff119670812d https://conda.anaconda.org/conda-forge/win-64/libglib-2.74.1-he8f3873_1.tar.bz2#09e1cbabfd9d733729843c3b35cb0b6d -https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.8.0-h039e092_1.tar.bz2#e84839b06cdd039130a1d1aa875146d3 -https://conda.anaconda.org/conda-forge/win-64/libtiff-4.5.0-hf8721a0_2.conda#2e003e276cc1375192569c96afd3d984 +https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.9.0-h51c2c0f_0.conda#6cbde93c514acb846762631c15c5d3c2 +https://conda.anaconda.org/conda-forge/win-64/libtiff-4.5.0-hc3b8658_5.conda#9415b560deaf13b6c8c22dfd6e596cd3 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9 @@ -69,59 +67,65 @@ https://conda.anaconda.org/conda-forge/win-64/pthread-stubs-0.4-hcd874cb_1001.ta https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc -https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a +https://conda.anaconda.org/conda-forge/noarch/setuptools-67.6.0-pyhd8ed1ab_0.conda#e18ed61c37145bb9b48d1d98801960f7 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/win-64/tornado-6.2-py38h91455d4_1.tar.bz2#ed09a022d62a1550692f856c104d929e +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/win-64/unicodedata2-15.0.0-py38h91455d4_0.tar.bz2#7a135e40d9f26c15419e5e82e1c436c0 https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyhd8ed1ab_6.tar.bz2#30878ecc4bd36e8deeea1e3c151b2e0b https://conda.anaconda.org/conda-forge/win-64/xorg-libxau-1.0.9-hcd874cb_0.tar.bz2#9cef622e75683c17d05ae62d66e69e6c https://conda.anaconda.org/conda-forge/win-64/xorg-libxdmcp-1.1.3-hcd874cb_0.tar.bz2#46878ebb6b9cbd8afcf8088d7ef00ece +https://conda.anaconda.org/conda-forge/noarch/zipp-3.15.0-pyhd8ed1ab_0.conda#13018819ca8f5b7cc675a8faf1f5fedf https://conda.anaconda.org/conda-forge/win-64/brotli-1.0.9-hcfcfb64_8.tar.bz2#2e661f21e1741c11506bdc7226e6b0bc https://conda.anaconda.org/conda-forge/win-64/cffi-1.15.1-py38h57701bc_3.conda#9b94af390cfdf924a063302a2ddb3860 -https://conda.anaconda.org/conda-forge/win-64/coverage-7.0.5-py38h91455d4_0.conda#530ad5ab383dec17e5fb709dafb86911 +https://conda.anaconda.org/conda-forge/win-64/coverage-7.2.1-py38h91455d4_0.conda#1719d68213cb7c4b35848ef9fd3fd910 https://conda.anaconda.org/conda-forge/win-64/glib-tools-2.74.1-h12be248_1.tar.bz2#cd93cc622f2fa0f68ddc978cb67a5061 +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/win-64/lcms2-2.14-ha5c8aab_1.conda#135bd65be6768b2bc84e864e7141ab77 +https://conda.anaconda.org/conda-forge/win-64/lcms2-2.15-h3e3b177_1.conda#a76c36ad1b4b87f038d67890122d08ec https://conda.anaconda.org/conda-forge/win-64/libxcb-1.13-hcd874cb_1004.tar.bz2#a6d7fd030532378ecb6ba435cd9f8234 https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.0-ha2aaf27_2.conda#db0490689232e8e38c312281df6f31a2 -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d +https://conda.anaconda.org/conda-forge/noarch/pip-23.0.1-pyhd8ed1ab_0.conda#8025ca83b8ba5430b640b83917c2a6f7 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh0701188_6.tar.bz2#56cd9fe388baac0e90c7149cfac95b60 -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/win-64/sip-6.7.5-py38hd3f51b4_0.conda#99a5d7532da18344a6648dd8e0f0e270 -https://conda.anaconda.org/conda-forge/win-64/tbb-2021.7.0-h91493d7_1.conda#39365b918d4f04909485f3055b131c86 +https://conda.anaconda.org/conda-forge/win-64/sip-6.7.7-py38hd3f51b4_0.conda#d22a2af975b99c76d47391a3ed5c5971 +https://conda.anaconda.org/conda-forge/win-64/tbb-2021.8.0-h91493d7_0.conda#e155410da447d8e37302a561b911dcb8 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/win-64/brotlipy-0.7.0-py38h91455d4_1005.tar.bz2#9fabc7fadfb37addbe91cc67c09cda69 -https://conda.anaconda.org/conda-forge/win-64/cryptography-39.0.0-py38h95f5157_0.conda#49fb9d2f5de471aa02f6abbdd848d8ef -https://conda.anaconda.org/conda-forge/win-64/fonttools-4.38.0-py38h91455d4_1.tar.bz2#45aa8e4d44d4b82db1ba373b6b7fbd61 +https://conda.anaconda.org/conda-forge/win-64/cryptography-39.0.2-py38h95f5157_0.conda#016c4a7f3965f42c2ad208b5a9aaf55f +https://conda.anaconda.org/conda-forge/win-64/fonttools-4.39.0-py38h91455d4_0.conda#161c6466cabd436abf9597d3053694b1 https://conda.anaconda.org/conda-forge/win-64/glib-2.74.1-h12be248_1.tar.bz2#7564888ab882b9d3aea46355ab7adaca +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-5.12.0-pyhd8ed1ab_0.conda#3544c818f0720c89eb16ae6940ab440b https://conda.anaconda.org/conda-forge/win-64/mkl-2022.1.0-h6a75c08_874.tar.bz2#2ff89a7337a9636029b4db9466e9f8e3 -https://conda.anaconda.org/conda-forge/win-64/pillow-9.4.0-py38h409c3de_0.conda#992a54266443e5c98bef5992b7d1084d -https://conda.anaconda.org/conda-forge/win-64/pyqt5-sip-12.11.0-py38hd3f51b4_2.tar.bz2#cbc432ec0d62367c7d9d7f486207712a +https://conda.anaconda.org/conda-forge/win-64/pillow-9.4.0-py38h0c7286b_2.conda#0dbb9816e8fe6b4d2620631188aef44f +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/win-64/pyqt5-sip-12.11.0-py38hd3f51b4_3.conda#948a9d38ac004da975f9862194c25f68 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.0.0-pyhd8ed1ab_0.tar.bz2#c9e3f8bfdb9bfc34aa1836a6ed4b25d7 -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf -https://conda.anaconda.org/conda-forge/win-64/gstreamer-1.21.3-h6b5321d_1.conda#6f8a7aeb3edae5e623f445751c2e8536 +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/win-64/gstreamer-1.22.0-h6b5321d_2.conda#86b8d2490f7068f7b23ab856b7f3139a https://conda.anaconda.org/conda-forge/win-64/libblas-3.9.0-16_win64_mkl.tar.bz2#d2e6f4e86cee2b4e8c27ff6884ccdc61 https://conda.anaconda.org/conda-forge/win-64/mkl-devel-2022.1.0-h57928b3_875.tar.bz2#6319a06307af296c1dfae93687c283b2 https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e -https://conda.anaconda.org/conda-forge/win-64/gst-plugins-base-1.21.3-h001b923_1.conda#74daeb89d1a88118af9d7da7a0a5cafd +https://conda.anaconda.org/conda-forge/win-64/gst-plugins-base-1.22.0-h001b923_2.conda#6118a66a6c156d20a703d916aadbe388 https://conda.anaconda.org/conda-forge/win-64/libcblas-3.9.0-16_win64_mkl.tar.bz2#14c2fb03b2bb14dfa3806186ca91d557 https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-16_win64_mkl.tar.bz2#be2f9d5712a5bb05cd900005ee752a05 -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.14-pyhd8ed1ab_0.conda#01f33ad2e0aaf6b5ba4add50dad5ad29 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/win-64/liblapacke-3.9.0-16_win64_mkl.tar.bz2#983e827b7c9562075c2e74d596d056c1 -https://conda.anaconda.org/conda-forge/win-64/numpy-1.24.1-py38h90ce339_0.conda#e727377e872ed8f426b726c7a202e7df -https://conda.anaconda.org/conda-forge/win-64/qt-main-5.15.6-h9580fe5_5.conda#f1351c4f6ac14a9c8d29103914e9b2d4 -https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 +https://conda.anaconda.org/conda-forge/win-64/numpy-1.24.2-py38h7ec9225_0.conda#c3f278e36ed9128fcb6acfd8e2f46449 +https://conda.anaconda.org/conda-forge/win-64/qt-main-5.15.8-h88fe7eb_7.conda#e3428bb2c38bb338c6421d81647a9865 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/win-64/blas-devel-3.9.0-16_win64_mkl.tar.bz2#dc89c75a7dd26c88ac77d64bf313973e https://conda.anaconda.org/conda-forge/noarch/codecov-2.1.12-pyhd8ed1ab_0.conda#0317ed52e504b93da000e8a027628775 https://conda.anaconda.org/conda-forge/win-64/contourpy-1.0.7-py38hb1fd069_0.conda#6b53200dddcec578cdd90cac146eeadd -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 -https://conda.anaconda.org/conda-forge/win-64/pyqt-5.15.7-py38hd6c051e_2.tar.bz2#b33fbea51980ecf275cef2262711f1ad +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/win-64/pyqt-5.15.7-py38hd6c051e_3.conda#9b17c0bbf19c6e265c3967e33df8770a https://conda.anaconda.org/conda-forge/win-64/blas-2.116-mkl.tar.bz2#7529860b43278247a278c6f56a191d2e -https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.6.2-py38h528a6c7_0.tar.bz2#c72de8aadeb6468b23ccfd5be1107c3b -https://conda.anaconda.org/conda-forge/win-64/scipy-1.10.0-py38h0f6ee2a_0.conda#13cfd7bace20d298320bdeaa387304d8 -https://conda.anaconda.org/conda-forge/win-64/matplotlib-3.6.2-py38haa244fe_0.tar.bz2#8e5672391509eae8501a952f4147fd2b +https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.7.1-py38h528a6c7_0.conda#0aebccad15d74ec7f1bc3d62497ad1a8 +https://conda.anaconda.org/conda-forge/win-64/scipy-1.10.1-py38h0f6ee2a_0.conda#ad604d9c7b391da227489d25c38faab7 +https://conda.anaconda.org/conda-forge/win-64/matplotlib-3.7.1-py38haa244fe_0.conda#f41a8af387463a78ad87571c767d0d80 diff --git a/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock b/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock index c9bf0701a51fe..68a408d18f707 100644 --- a/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock +++ b/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock @@ -8,7 +8,7 @@ https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-hab24e00_0.tar.bz2#19410c3df09dfb12d1206132a1d357c5 -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.39-hcc3a1bd_1.conda#737be0d34c22d24432049ab7a3214de4 +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3 https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.2.0-h337968e_19.tar.bz2#164b4b1acaedc47ee7e658ae6b308ca3 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60 https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.8-3_cp38.conda#2f3f7af062b42d664117662612022204 @@ -23,9 +23,9 @@ https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-h27087fc_0.tar.bz2#c4fbad8d4bddeb3c085f18cbf97fbfad https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hf0379b8_106.conda#d7407e695358f068a2a7f8295cde0567 https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 https://conda.anaconda.org/conda-forge/linux-64/gstreamer-orc-0.4.33-h166bdaf_0.tar.bz2#879c93426c9d0b84a9de4513fbce5f4f https://conda.anaconda.org/conda-forge/linux-64/icu-70.1-h27087fc_0.tar.bz2#87473a15119779e021c314249d4b4aed -https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2#a8832b479f93521a9e7b5b743803be51 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f @@ -35,26 +35,34 @@ https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.17-h0b41bf4_0.conda https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-h166bdaf_0.tar.bz2#b62b52da46c39ee2bc3c162ac7f1804d -https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.4-h166bdaf_0.tar.bz2#b4f717df2d377410b462328bf0e8fb7d +https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.5.1-h0b41bf4_0.conda#1edd9e67bdb90d78cea97733ff6b54e6 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2#39b1328babf85c7c3a61636d9cd50206 https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a6416_3.tar.bz2#8c5963a49b6035c40646a763293fbb35 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libudev1-252-h166bdaf_0.tar.bz2#174243089ec111479298a5b7099b64b5 +https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_0.conda#6c2addbd9aa4ee47c76d50c9f0df8cd6 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.3-h9c3ff4c_1.tar.bz2#fbe97e8fa6f275d7c76a09e795adc3e6 +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.2-hcb278e6_0.conda#08efb1e1813f1a151b7a945b972a049b https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.7-h0b41bf4_1.conda#7adaac6ff98219bcb99b45e408b80f4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.38-h0b41bf4_0.conda#9ac34337e5101a87e5d91da05d84aa48 +https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.0.10-h7f98852_0.tar.bz2#d6b0b50b49eccfe0be0373be628be0f3 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 +https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda#bce9f945da8ad2ae9b1d7165a64d0f87 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2#3ceea9668625c18f19530de98b15d5b0 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 -https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.21-h583fa2b_2.conda#7b36a10b58964d4444fcba44244710c5 +https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.22-h11f4161_0.conda#504fa9e712b99494a9cf4630e3ca7d78 https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.tar.bz2#04bac51ba35ea023dc48af73c1c88c25 @@ -69,12 +77,14 @@ https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.b https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8 https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.31-h26416b9_0.tar.bz2#6c531bc30d49ae75b9c7c7f65bd62e3c +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.21-pthreads_h320a7e8_3.tar.bz2#29155b9196b9d78022f11d86733e25a7 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 https://conda.anaconda.org/conda-forge/linux-64/ccache-4.7.3-h2599c5e_0.tar.bz2#4feea9466084c6948bd59539f1c0bb72 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 @@ -85,16 +95,16 @@ https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_0.conda#70cbb0c2033665f2a7339bf0ec51a67f https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-h6adf6a1_2.conda#2e648a34072eb39d7c4fc2a9981c5f0c -https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.0.3-he3ba5ed_0.tar.bz2#f9dbabc7e01c459ed7a1d1d64b206e9b -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.31-hbc51c84_0.tar.bz2#da9633eee814d4e910fe42643a356315 -https://conda.anaconda.org/conda-forge/linux-64/nss-3.82-he02c5a1_0.conda#f8d7f11d19e4cb2207eab159fd4c0152 -https://conda.anaconda.org/conda-forge/linux-64/python-3.8.15-h4a9ceb5_0_cpython.conda#dc29a8a79d0f2c80004cc06d3190104f +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea +https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 +https://conda.anaconda.org/conda-forge/linux-64/python-3.8.16-he550d4f_1_cpython.conda#9de84cccfbc5f8350a3667bb6ef6fc30 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h166bdaf_0.tar.bz2#637054603bb7594302e3bf83f0a99879 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-h166bdaf_0.tar.bz2#732e22f1741bccea861f5668cf7342a7 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h166bdaf_0.tar.bz2#0a8e20a8aef954390b9481a527421a8c -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.4-h0b41bf4_0.conda#ea8fbfeb976ac49cbeb594e985393514 https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_8.tar.bz2#2ff08978892a3e8b954397c461f18418 https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6 @@ -103,21 +113,21 @@ https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb https://conda.anaconda.org/conda-forge/linux-64/cython-0.29.33-py38h8dc9893_0.conda#5d50cd654981f0ccc7c878ac297afaa7 https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.1-hc2a2eb6_0.tar.bz2#78415f0180a8d9c5bcc47889e00d5fb1 +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.74.1-h6239696_1.tar.bz2#5f442e6bc9d89ba236eb25a25c5c2815 https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py38h43d8883_1.tar.bz2#41ca56d5cac7bfc7eb4fcdbee878eb84 -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.14-hfd0df8a_1.conda#c2566c2ea5f153ddd6bf4acaf7547d97 -https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_0.conda#dcfae510179c3de2e42b3a2276d059e0 +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d8aca0bc23ca73fa8caa3e7c84c28 +https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_1.conda#a3a0f7a6f0885f5e1e0ec691566afb77 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c9f4416a34bc91e0eb029f912c68f81f https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_openblas.tar.bz2#823ceb5567e1a595deb643fcd17aed5a -https://conda.anaconda.org/conda-forge/linux-64/libpq-15.1-hb675445_3.conda#9873ab80ec8fab4a2c26c7580e0d7f58 +https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.1-py38hab0fcb9_0.conda#2c0b3c72dad0288d9582ccbceb250cb4 +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.2-py38h10c12cc_0.conda#05592c85b9f6931dc2df1e80c0d56294 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9 @@ -126,45 +136,53 @@ https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b46 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7-pyhd8ed1ab_0.conda#c8d7e34ca76d6ecc03b84bedfd99d689 -https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a +https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7.1-pyhd8ed1ab_0.conda#f59d49a7b464901cf714b9e7984d01a2 +https://conda.anaconda.org/conda-forge/noarch/setuptools-67.6.0-pyhd8ed1ab_0.conda#e18ed61c37145bb9b48d1d98801960f7 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py38h0a891b7_1.tar.bz2#358beb228a53b5e1031862de3525d1d3 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.0.0-py38h0a891b7_0.tar.bz2#44421904760e9f5ae2035193e04360f0 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h166bdaf_0.tar.bz2#c9b568bd804cb2903c6be6f5f68182e4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb +https://conda.anaconda.org/conda-forge/noarch/zipp-3.15.0-pyhd8ed1ab_0.conda#13018819ca8f5b7cc675a8faf1f5fedf https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-16_linux64_openblas.tar.bz2#519562d6176dab9c2ab9a8336a14c8e7 +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py38h4a40e3a_3.conda#3ac112151c6b6cfe457e976de41af0c5 https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.7-py38hfbd4bf9_0.conda#638537863b298151635c05c762a997ab -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.38.0-py38h0a891b7_1.tar.bz2#62c89ddefed9c5835e228a32b357a28d +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py38h1de0b5d_0.conda#aac6f6ca6b8c5d321392f5f7aa3d3186 https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.1-h6239696_1.tar.bz2#f3220a9e9d3abcbfca43419a219df7e4 +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_0.conda#189f7f97245f594b7a9d8e2b9f311cf8 -https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py38hb32c036_0.conda#a288a6e69efc2f20c30ebfa590e11bed -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d +https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py38h961100d_2.conda#26a5eb5d9f097e5011d54aa5cc1571c8 https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-ha8d29e2_1.conda#dbfc2a8d63a43a11acf4c704e1ef9d0c -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.5-py38hfa26641_0.conda#7be81814bae276dc7b4c707cf1e8186b +https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.7-py38h8dc9893_0.conda#ea242937718f3dacf253355e1d634535 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-openblas.tar.bz2#02f34bcf0aceb6fae4c4d1ecb71c852a https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py38h0a891b7_1005.tar.bz2#e99e08812dfff30fdd17b3f8838e2759 -https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.0-py38h3d167d9_0.conda#0ef859aa9dafce54bdf3d56715daed35 -https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.21.3-h25f0c4b_1.conda#0c8a8f15aa319c91d9010072278feddd -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.6.2-py38hb021067_0.tar.bz2#72422499195d8aded0dfd461c6e3e86f -https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.2-py38hdc8b05c_2.conda#1ff5d955870414f6883211edfe0bbf10 -https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py38hfa26641_2.tar.bz2#ad6437509a14f1e8e5b8a354f93f340c -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf -https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.21.3-h4243ec0_1.conda#905563d166c13ba299e39d6c9fcebd1c +https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.2-py38h3d167d9_0.conda#6c60377f8bfa325a2cd80d603627a613 +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.22.0-h25f0c4b_2.conda#461541cb1b387c2a28ab6217f3d38502 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-6.0.0-h8e241bc_0.conda#448fe40d2fed88ccf4d9ded37cbb2b38 +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-5.12.0-pyhd8ed1ab_0.conda#3544c818f0720c89eb16ae6940ab440b +https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.3-py38hdc8b05c_0.conda#5073966d63a54434d2a2fc41d325b072 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py38h8dc9893_3.conda#7bb0328b4a0f857aeb432426b9a5f908 +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0_2.conda#0d0c6604c8ac4ad5e51efa7bb58da05c +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py38hd6c3c57_0.conda#3b8ba76acae09fbd4b2247c4ee4c0324 https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e -https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.6-hf6cd601_5.conda#9c23a5205b67f2a67b19c84bf1fd7f5e -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.14-pyhd8ed1ab_0.conda#01f33ad2e0aaf6b5ba4add50dad5ad29 -https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py38h7492b6b_2.tar.bz2#cfa725eff634872f90dcd5ebf8e8dc1a -https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.6.2-py38h578d9bd_0.tar.bz2#e1a19f0d4686a701d4a4acce2b625acb -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.0-py38h10c12cc_0.conda#466ea530d622838f6cdec4f771ddc249 -https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py38h4e30db6_2.tar.bz2#71e8ccc750d0e6e9a55c63bc39a4e5b8 +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h67dfc38_7.conda#f140acdc15a0196eef664f120c396266 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 +https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py38ha0d8c90_3.conda#e965dc172d67920d058ac2b3a0e27565 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py38h578d9bd_0.conda#50ff9e0a3dd459a0ca365741072bf9a2 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py38h10c12cc_0.conda#1cbc47bb9a600ce4a49d8da797d375bf +https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py38h507a481_2.conda#8b7ce7db24bbe8f2f230b6b0523dde50 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock index b010a1be61122..c5db32b6a8597 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock @@ -8,7 +8,7 @@ https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-hab24e00_0.tar.bz2#19410c3df09dfb12d1206132a1d357c5 -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.39-hcc3a1bd_1.conda#737be0d34c22d24432049ab7a3214de4 +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3 https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.2.0-h337968e_19.tar.bz2#164b4b1acaedc47ee7e658ae6b308ca3 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60 https://conda.anaconda.org/conda-forge/linux-64/mkl-include-2022.1.0-h84fe81f_915.tar.bz2#2dcd1acca05c11410d4494d7fc7dfa2a @@ -25,9 +25,9 @@ https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-h27087fc_0.tar.bz2#c4fbad8d4bddeb3c085f18cbf97fbfad https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hf0379b8_106.conda#d7407e695358f068a2a7f8295cde0567 https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 https://conda.anaconda.org/conda-forge/linux-64/gstreamer-orc-0.4.33-h166bdaf_0.tar.bz2#879c93426c9d0b84a9de4513fbce5f4f https://conda.anaconda.org/conda-forge/linux-64/icu-70.1-h27087fc_0.tar.bz2#87473a15119779e021c314249d4b4aed -https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2#a8832b479f93521a9e7b5b743803be51 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f @@ -37,25 +37,33 @@ https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.17-h0b41bf4_0.conda https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-h166bdaf_0.tar.bz2#b62b52da46c39ee2bc3c162ac7f1804d -https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.4-h166bdaf_0.tar.bz2#b4f717df2d377410b462328bf0e8fb7d +https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.5.1-h0b41bf4_0.conda#1edd9e67bdb90d78cea97733ff6b54e6 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2#39b1328babf85c7c3a61636d9cd50206 https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libudev1-252-h166bdaf_0.tar.bz2#174243089ec111479298a5b7099b64b5 +https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_0.conda#6c2addbd9aa4ee47c76d50c9f0df8cd6 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.3-h9c3ff4c_1.tar.bz2#fbe97e8fa6f275d7c76a09e795adc3e6 +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.2-hcb278e6_0.conda#08efb1e1813f1a151b7a945b972a049b https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.7-h0b41bf4_1.conda#7adaac6ff98219bcb99b45e408b80f4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.38-h0b41bf4_0.conda#9ac34337e5101a87e5d91da05d84aa48 +https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.0.10-h7f98852_0.tar.bz2#d6b0b50b49eccfe0be0373be628be0f3 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 +https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda#bce9f945da8ad2ae9b1d7165a64d0f87 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2#3ceea9668625c18f19530de98b15d5b0 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 -https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.21-h583fa2b_2.conda#7b36a10b58964d4444fcba44244710c5 +https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.22-h11f4161_0.conda#504fa9e712b99494a9cf4630e3ca7d78 https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.tar.bz2#04bac51ba35ea023dc48af73c1c88c25 https://conda.anaconda.org/conda-forge/linux-64/libcap-2.66-ha37c62d_0.tar.bz2#2d7665abd0997f1a6d4b7596bc27b657 @@ -69,30 +77,32 @@ https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.b https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8 https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.31-h26416b9_0.tar.bz2#6c531bc30d49ae75b9c7c7f65bd62e3c +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 https://conda.anaconda.org/conda-forge/linux-64/ccache-4.7.3-h2599c5e_0.tar.bz2#4feea9466084c6948bd59539f1c0bb72 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a41adce7106749573d883b2f657d78 https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.1-h166bdaf_0.tar.bz2#f967fc95089cd247ceed56eda31de3a9 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz2#ed5349aa96776e00b34eccecf4a948fe -https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.8.0-h32351e8_1.tar.bz2#0c52bb2b3b621d684f3beabd4aacaca7 +https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.0-hd6dc26d_0.conda#ab9d052373c9376c0ebcff4dfef3d296 https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_0.conda#70cbb0c2033665f2a7339bf0ec51a67f https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-h6adf6a1_2.conda#2e648a34072eb39d7c4fc2a9981c5f0c -https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.0.3-he3ba5ed_0.tar.bz2#f9dbabc7e01c459ed7a1d1d64b206e9b -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.31-hbc51c84_0.tar.bz2#da9633eee814d4e910fe42643a356315 -https://conda.anaconda.org/conda-forge/linux-64/nss-3.82-he02c5a1_0.conda#f8d7f11d19e4cb2207eab159fd4c0152 +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea +https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-he550d4f_1_cpython.conda#8d14fc2aa12db370a443753c8230be1e https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h166bdaf_0.tar.bz2#637054603bb7594302e3bf83f0a99879 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-h166bdaf_0.tar.bz2#732e22f1741bccea861f5668cf7342a7 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h166bdaf_0.tar.bz2#0a8e20a8aef954390b9481a527421a8c -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.4-h0b41bf4_0.conda#ea8fbfeb976ac49cbeb594e985393514 https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_8.tar.bz2#2ff08978892a3e8b954397c461f18418 https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6 @@ -101,17 +111,17 @@ https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb https://conda.anaconda.org/conda-forge/linux-64/cython-0.29.33-py311hcafe171_0.conda#3e792927e2e16119f8e6910cca25a063 https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.1-hc2a2eb6_0.tar.bz2#78415f0180a8d9c5bcc47889e00d5fb1 +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.74.1-h6239696_1.tar.bz2#5f442e6bc9d89ba236eb25a25c5c2815 https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py311h4dd048b_1.tar.bz2#46d451f575392c01dc193069bd89766d -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.14-hfd0df8a_1.conda#c2566c2ea5f153ddd6bf4acaf7547d97 -https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_0.conda#dcfae510179c3de2e42b3a2276d059e0 +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d8aca0bc23ca73fa8caa3e7c84c28 +https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_1.conda#a3a0f7a6f0885f5e1e0ec691566afb77 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c9f4416a34bc91e0eb029f912c68f81f -https://conda.anaconda.org/conda-forge/linux-64/libpq-15.1-hb675445_3.conda#9873ab80ec8fab4a2c26c7580e0d7f58 +https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea @@ -122,55 +132,60 @@ https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b46 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7-pyhd8ed1ab_0.conda#c8d7e34ca76d6ecc03b84bedfd99d689 -https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a +https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7.1-pyhd8ed1ab_0.conda#f59d49a7b464901cf714b9e7984d01a2 +https://conda.anaconda.org/conda-forge/noarch/setuptools-67.6.0-pyhd8ed1ab_0.conda#e18ed61c37145bb9b48d1d98801960f7 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.7.0-h924138e_1.conda#1a272773743a97aa044fd5bcdac2138a +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.8.0-hf52228f_0.conda#b4188d0c54ead87b3c6bc9cb07281f40 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py311hd4cff14_1.tar.bz2#4d86cd6dbdc1185f4e72d974f1f1f852 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h166bdaf_0.tar.bz2#c9b568bd804cb2903c6be6f5f68182e4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py311h409f033_3.conda#9025d0786dbbe4bc91fd8e85502decce -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.0.5-py311h2582759_0.conda#c23815b638bb37695c5e5f3fa3051e31 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.38.0-py311hd4cff14_1.tar.bz2#871b97970cf7420780f79a62fef8eb48 +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.2.1-py311h2582759_0.conda#4fee06fa1851addd1966f15ba28de7a8 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py311h2582759_0.conda#56d8b988010c53eb8ba5117e15e5b1a7 https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.1-h6239696_1.tar.bz2#f3220a9e9d3abcbfca43419a219df7e4 https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_0.conda#189f7f97245f594b7a9d8e2b9f311cf8 +https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d https://conda.anaconda.org/conda-forge/linux-64/mkl-2022.1.0-h84fe81f_915.tar.bz2#b9c8f925797a93dbff45e1626b025a6b -https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py311h104bd61_0.conda#42357babd6bc40498a2aa13ffdcebe75 -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py311h573f0d3_2.conda#7321881b545202cf9ab8bd24b4151dcb https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-ha8d29e2_1.conda#dbfc2a8d63a43a11acf4c704e1ef9d0c -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.5-py311ha362b79_0.conda#f6dd6ba47e2380b9c715fc45f0d45e62 +https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.7-py311hcafe171_0.conda#cf1adb3a0138cca4bbab415ddf2f57f1 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py311hd4cff14_1005.tar.bz2#9bdac7084ecfc08338bae1b976535724 -https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.0-py311h9b4c7bb_0.conda#74eed5e75574839f1ae7a7048f529a66 -https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.21.3-h25f0c4b_1.conda#0c8a8f15aa319c91d9010072278feddd +https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.2-py311h9b4c7bb_0.conda#f2e305191c0e28ef746a4e6b365807f9 +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.22.0-h25f0c4b_2.conda#461541cb1b387c2a28ab6217f3d38502 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-6.0.0-h8e241bc_0.conda#448fe40d2fed88ccf4d9ded37cbb2b38 https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_mkl.tar.bz2#85f61af03fd291dae33150ffe89dc09a https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2022.1.0-ha770c72_916.tar.bz2#69ba49e445f87aea2cba343a71a35ca2 -https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py311ha362b79_2.tar.bz2#d250de3c3013c210865cc033164d6b60 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py311hcafe171_3.conda#0d79df2a96f6572fed2883374400b235 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.0.0-pyhd8ed1ab_0.tar.bz2#c9e3f8bfdb9bfc34aa1836a6ed4b25d7 -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf -https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.21.3-h4243ec0_1.conda#905563d166c13ba299e39d6c9fcebd1c +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0_2.conda#0d0c6604c8ac4ad5e51efa7bb58da05c https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_mkl.tar.bz2#361bf757b95488de76c4f123805742d3 https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_mkl.tar.bz2#a2f166748917d6d6e4707841ca1f519e https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_mkl.tar.bz2#44ccc4d4dca6a8d57fa17442bc64b5a1 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.1-py311hbde0eaa_0.conda#236dda53b49b70717d7280efb3494db7 -https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.6-hf6cd601_5.conda#9c23a5205b67f2a67b19c84bf1fd7f5e -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.14-pyhd8ed1ab_0.conda#01f33ad2e0aaf6b5ba4add50dad5ad29 +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.2-py311h8e6699e_0.conda#90db8cc0dfa20853329bfc6642f887aa +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h67dfc38_7.conda#f140acdc15a0196eef664f120c396266 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-16_linux64_mkl.tar.bz2#3f92c1c9e1c0e183462c5071aa02cae1 https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.7-py311ha3edf6b_0.conda#e7548e7f58965a2fe97a95950a5fedc6 -https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.2-py311h2872171_2.conda#dde47054db21d0aaf96bc1cfb81ef292 -https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py311h3408d8f_2.tar.bz2#5bf133633260e9d8d3f9a50ef78b49b2 -https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 +https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.3-py311h2872171_0.conda#a129a2aa7f5c2f45808399d60c3080f2 +https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py311ha74522f_3.conda#ad6dd0bed0cdf5f2d4eb2b989d6253b3 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-mkl.tar.bz2#c196a26abf6b4f132c88828ab7c2231c https://conda.anaconda.org/conda-forge/noarch/codecov-2.1.12-pyhd8ed1ab_0.conda#0317ed52e504b93da000e8a027628775 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.6.2-py311he728205_0.tar.bz2#96ec1bd38ecfc5ead0ac1eb8c4bf35ff -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.6.2-py311h38be061_0.tar.bz2#190a1bc60c0f7053daad403fa745fef3 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.0-py311h8e6699e_0.conda#0dd612573e8e8b30bff771dabefc79b1 -https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py311h59ea3da_2.tar.bz2#4521a31493dbc02ffee57c524967b847 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py311h8597a09_0.conda#70c3b734ffe82c16b6d121aaa11929a8 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py311h38be061_0.conda#8fd462c8bcbba5a3affcb2d04e387476 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py311h8e6699e_0.conda#a9dba1242a54275e4914a2540f4eb233 +https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py311hcb41070_2.conda#bcf32a1a23df6e4ae047f90d401b7517 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock index fc84f8da6e9ff..613fb6945fa8b 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock @@ -8,7 +8,7 @@ https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-hab24e00_0.tar.bz2#19410c3df09dfb12d1206132a1d357c5 -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.39-hcc3a1bd_1.conda#737be0d34c22d24432049ab7a3214de4 +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3 https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.2.0-h337968e_19.tar.bz2#164b4b1acaedc47ee7e658ae6b308ca3 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60 https://conda.anaconda.org/conda-forge/linux-64/mkl-include-2022.1.0-h84fe81f_915.tar.bz2#2dcd1acca05c11410d4494d7fc7dfa2a @@ -25,9 +25,9 @@ https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-h27087fc_0.tar.bz2#c4fbad8d4bddeb3c085f18cbf97fbfad https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hf0379b8_106.conda#d7407e695358f068a2a7f8295cde0567 https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 https://conda.anaconda.org/conda-forge/linux-64/gstreamer-orc-0.4.33-h166bdaf_0.tar.bz2#879c93426c9d0b84a9de4513fbce5f4f https://conda.anaconda.org/conda-forge/linux-64/icu-70.1-h27087fc_0.tar.bz2#87473a15119779e021c314249d4b4aed -https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2#a8832b479f93521a9e7b5b743803be51 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f @@ -37,25 +37,33 @@ https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.17-h0b41bf4_0.conda https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-h166bdaf_0.tar.bz2#b62b52da46c39ee2bc3c162ac7f1804d -https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.4-h166bdaf_0.tar.bz2#b4f717df2d377410b462328bf0e8fb7d +https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.5.1-h0b41bf4_0.conda#1edd9e67bdb90d78cea97733ff6b54e6 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2#39b1328babf85c7c3a61636d9cd50206 https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libudev1-252-h166bdaf_0.tar.bz2#174243089ec111479298a5b7099b64b5 +https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_0.conda#6c2addbd9aa4ee47c76d50c9f0df8cd6 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.3-h9c3ff4c_1.tar.bz2#fbe97e8fa6f275d7c76a09e795adc3e6 +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.2-hcb278e6_0.conda#08efb1e1813f1a151b7a945b972a049b https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.7-h0b41bf4_1.conda#7adaac6ff98219bcb99b45e408b80f4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.38-h0b41bf4_0.conda#9ac34337e5101a87e5d91da05d84aa48 +https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.0.10-h7f98852_0.tar.bz2#d6b0b50b49eccfe0be0373be628be0f3 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 +https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda#bce9f945da8ad2ae9b1d7165a64d0f87 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2#3ceea9668625c18f19530de98b15d5b0 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 -https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.21-h583fa2b_2.conda#7b36a10b58964d4444fcba44244710c5 +https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.22-h11f4161_0.conda#504fa9e712b99494a9cf4630e3ca7d78 https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.tar.bz2#04bac51ba35ea023dc48af73c1c88c25 https://conda.anaconda.org/conda-forge/linux-64/libcap-2.66-ha37c62d_0.tar.bz2#2d7665abd0997f1a6d4b7596bc27b657 @@ -69,30 +77,32 @@ https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.b https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8 https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.31-h26416b9_0.tar.bz2#6c531bc30d49ae75b9c7c7f65bd62e3c +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 https://conda.anaconda.org/conda-forge/linux-64/ccache-4.7.3-h2599c5e_0.tar.bz2#4feea9466084c6948bd59539f1c0bb72 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a41adce7106749573d883b2f657d78 https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.1-h166bdaf_0.tar.bz2#f967fc95089cd247ceed56eda31de3a9 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz2#ed5349aa96776e00b34eccecf4a948fe -https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.8.0-h32351e8_1.tar.bz2#0c52bb2b3b621d684f3beabd4aacaca7 +https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.0-hd6dc26d_0.conda#ab9d052373c9376c0ebcff4dfef3d296 https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_0.conda#70cbb0c2033665f2a7339bf0ec51a67f https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-h6adf6a1_2.conda#2e648a34072eb39d7c4fc2a9981c5f0c -https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.0.3-he3ba5ed_0.tar.bz2#f9dbabc7e01c459ed7a1d1d64b206e9b -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.31-hbc51c84_0.tar.bz2#da9633eee814d4e910fe42643a356315 -https://conda.anaconda.org/conda-forge/linux-64/nss-3.82-he02c5a1_0.conda#f8d7f11d19e4cb2207eab159fd4c0152 +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea +https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-he550d4f_1_cpython.conda#8d14fc2aa12db370a443753c8230be1e https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h166bdaf_0.tar.bz2#637054603bb7594302e3bf83f0a99879 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-h166bdaf_0.tar.bz2#732e22f1741bccea861f5668cf7342a7 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h166bdaf_0.tar.bz2#0a8e20a8aef954390b9481a527421a8c -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.4-h0b41bf4_0.conda#ea8fbfeb976ac49cbeb594e985393514 https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_8.tar.bz2#2ff08978892a3e8b954397c461f18418 https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6 @@ -101,17 +111,17 @@ https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb https://conda.anaconda.org/conda-forge/linux-64/cython-0.29.33-py311hcafe171_0.conda#3e792927e2e16119f8e6910cca25a063 https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.1-hc2a2eb6_0.tar.bz2#78415f0180a8d9c5bcc47889e00d5fb1 +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.74.1-h6239696_1.tar.bz2#5f442e6bc9d89ba236eb25a25c5c2815 https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py311h4dd048b_1.tar.bz2#46d451f575392c01dc193069bd89766d -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.14-hfd0df8a_1.conda#c2566c2ea5f153ddd6bf4acaf7547d97 -https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_0.conda#dcfae510179c3de2e42b3a2276d059e0 +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d8aca0bc23ca73fa8caa3e7c84c28 +https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_1.conda#a3a0f7a6f0885f5e1e0ec691566afb77 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c9f4416a34bc91e0eb029f912c68f81f -https://conda.anaconda.org/conda-forge/linux-64/libpq-15.1-hb675445_3.conda#9873ab80ec8fab4a2c26c7580e0d7f58 +https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea @@ -122,52 +132,57 @@ https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b46 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7-pyhd8ed1ab_0.conda#c8d7e34ca76d6ecc03b84bedfd99d689 -https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a +https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7.1-pyhd8ed1ab_0.conda#f59d49a7b464901cf714b9e7984d01a2 +https://conda.anaconda.org/conda-forge/noarch/setuptools-67.6.0-pyhd8ed1ab_0.conda#e18ed61c37145bb9b48d1d98801960f7 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.7.0-h924138e_1.conda#1a272773743a97aa044fd5bcdac2138a +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.8.0-hf52228f_0.conda#b4188d0c54ead87b3c6bc9cb07281f40 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py311hd4cff14_1.tar.bz2#4d86cd6dbdc1185f4e72d974f1f1f852 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h166bdaf_0.tar.bz2#c9b568bd804cb2903c6be6f5f68182e4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py311h409f033_3.conda#9025d0786dbbe4bc91fd8e85502decce -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.38.0-py311hd4cff14_1.tar.bz2#871b97970cf7420780f79a62fef8eb48 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py311h2582759_0.conda#56d8b988010c53eb8ba5117e15e5b1a7 https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.1-h6239696_1.tar.bz2#f3220a9e9d3abcbfca43419a219df7e4 https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_0.conda#189f7f97245f594b7a9d8e2b9f311cf8 +https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d https://conda.anaconda.org/conda-forge/linux-64/mkl-2022.1.0-h84fe81f_915.tar.bz2#b9c8f925797a93dbff45e1626b025a6b -https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py311h104bd61_0.conda#42357babd6bc40498a2aa13ffdcebe75 -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py311h573f0d3_2.conda#7321881b545202cf9ab8bd24b4151dcb https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-ha8d29e2_1.conda#dbfc2a8d63a43a11acf4c704e1ef9d0c -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.5-py311ha362b79_0.conda#f6dd6ba47e2380b9c715fc45f0d45e62 +https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.7-py311hcafe171_0.conda#cf1adb3a0138cca4bbab415ddf2f57f1 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py311hd4cff14_1005.tar.bz2#9bdac7084ecfc08338bae1b976535724 -https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.0-py311h9b4c7bb_0.conda#74eed5e75574839f1ae7a7048f529a66 -https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.21.3-h25f0c4b_1.conda#0c8a8f15aa319c91d9010072278feddd +https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.2-py311h9b4c7bb_0.conda#f2e305191c0e28ef746a4e6b365807f9 +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.22.0-h25f0c4b_2.conda#461541cb1b387c2a28ab6217f3d38502 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-6.0.0-h8e241bc_0.conda#448fe40d2fed88ccf4d9ded37cbb2b38 https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_mkl.tar.bz2#85f61af03fd291dae33150ffe89dc09a https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2022.1.0-ha770c72_916.tar.bz2#69ba49e445f87aea2cba343a71a35ca2 -https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py311ha362b79_2.tar.bz2#d250de3c3013c210865cc033164d6b60 -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf -https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.21.3-h4243ec0_1.conda#905563d166c13ba299e39d6c9fcebd1c +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py311hcafe171_3.conda#0d79df2a96f6572fed2883374400b235 +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0_2.conda#0d0c6604c8ac4ad5e51efa7bb58da05c https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_mkl.tar.bz2#361bf757b95488de76c4f123805742d3 https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_mkl.tar.bz2#a2f166748917d6d6e4707841ca1f519e https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_mkl.tar.bz2#44ccc4d4dca6a8d57fa17442bc64b5a1 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.1-py311hbde0eaa_0.conda#236dda53b49b70717d7280efb3494db7 -https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.6-hf6cd601_5.conda#9c23a5205b67f2a67b19c84bf1fd7f5e -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.14-pyhd8ed1ab_0.conda#01f33ad2e0aaf6b5ba4add50dad5ad29 +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.2-py311h8e6699e_0.conda#90db8cc0dfa20853329bfc6642f887aa +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h67dfc38_7.conda#f140acdc15a0196eef664f120c396266 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-16_linux64_mkl.tar.bz2#3f92c1c9e1c0e183462c5071aa02cae1 https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.7-py311ha3edf6b_0.conda#e7548e7f58965a2fe97a95950a5fedc6 -https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.2-py311h2872171_2.conda#dde47054db21d0aaf96bc1cfb81ef292 -https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py311h3408d8f_2.tar.bz2#5bf133633260e9d8d3f9a50ef78b49b2 -https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 +https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.3-py311h2872171_0.conda#a129a2aa7f5c2f45808399d60c3080f2 +https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py311ha74522f_3.conda#ad6dd0bed0cdf5f2d4eb2b989d6253b3 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-mkl.tar.bz2#c196a26abf6b4f132c88828ab7c2231c -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.6.2-py311he728205_0.tar.bz2#96ec1bd38ecfc5ead0ac1eb8c4bf35ff -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.6.2-py311h38be061_0.tar.bz2#190a1bc60c0f7053daad403fa745fef3 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.0-py311h8e6699e_0.conda#0dd612573e8e8b30bff771dabefc79b1 -https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py311h59ea3da_2.tar.bz2#4521a31493dbc02ffee57c524967b847 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py311h8597a09_0.conda#70c3b734ffe82c16b6d121aaa11929a8 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py311h38be061_0.conda#8fd462c8bcbba5a3affcb2d04e387476 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py311h8e6699e_0.conda#a9dba1242a54275e4914a2540f4eb233 +https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py311hcb41070_2.conda#bcf32a1a23df6e4ae047f90d401b7517 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock index 21cef5900f653..d0968494e5592 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock @@ -4,15 +4,14 @@ @EXPLICIT https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h0d85af4_4.tar.bz2#37edc4e6304ca87316e160f5ca0bd1b5 https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2022.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a -https://conda.anaconda.org/conda-forge/osx-64/jpeg-9e-hac89ed1_2.tar.bz2#60d90a3f5803660c5c2a2e9d883df0a6 https://conda.anaconda.org/conda-forge/osx-64/libbrotlicommon-1.0.9-hb7f2c08_8.tar.bz2#37157d273eaf3bc7d6862104161d9ec9 -https://conda.anaconda.org/conda-forge/osx-64/libcxx-14.0.6-hccf4f1f_0.tar.bz2#208a6a874b073277374de48a782f6b10 +https://conda.anaconda.org/conda-forge/osx-64/libcxx-15.0.7-h71dddab_0.conda#ad1c6c1ddfd7717e3d46bf06ff2e9400 https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.17-hac1461d_0.conda#e3894420cf8b6abbf6c4d3d9742fbb4a https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9 -https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-11.3.0-h824d247_27.conda#3729d4388eb5a801b148dd4802899dba +https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-11.3.0-h824d247_31.conda#ea203ba0aca5cd594aa3b1a2b32e5978 https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hac89ed1_0.tar.bz2#691d103d11180486154af49c037b7ed9 -https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-2.1.4-hb7f2c08_0.tar.bz2#a8adc43e4b09be9c2ddbf89900956db2 -https://conda.anaconda.org/conda-forge/osx-64/libwebp-base-1.2.4-h775f41a_0.tar.bz2#28807bef802a354f9c164e7ab242c5cb +https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-2.1.5.1-hb7f2c08_0.conda#d7309a152b9b79799063b8bb47e34a3a +https://conda.anaconda.org/conda-forge/osx-64/libwebp-base-1.3.0-hb7f2c08_0.conda#18981e4c840126d6118d8952485fea51 https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.2.13-hfd90126_4.tar.bz2#35eb3fce8d51ed3c1fd4122bad48250b https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-15.0.7-h61d9ccf_0.conda#3faa9933dff6e96333b5ca5274674b63 https://conda.anaconda.org/conda-forge/osx-64/mkl-include-2022.1.0-h6bab518_928.tar.bz2#67f8511a5eaf693a202486f74035b3f7 @@ -28,29 +27,28 @@ https://conda.anaconda.org/conda-forge/osx-64/isl-0.25-hb486fe8_0.tar.bz2#45a9a4 https://conda.anaconda.org/conda-forge/osx-64/lerc-4.0.0-hb486fe8_0.tar.bz2#f9d6a4c82889d5ecedec1d90eb673c55 https://conda.anaconda.org/conda-forge/osx-64/libbrotlidec-1.0.9-hb7f2c08_8.tar.bz2#7f952a036d9014b4dab96c6ea0f8c2a7 https://conda.anaconda.org/conda-forge/osx-64/libbrotlienc-1.0.9-hb7f2c08_8.tar.bz2#b36a3bfe866d9127f25f286506982166 -https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-11.3.0-h082f757_27.conda#f7602714b2be91be36f00fb75c45cb14 +https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-12.2.0-he409387_31.conda#5a544130e584b1f204ac896ff071d5b3 https://conda.anaconda.org/conda-forge/osx-64/libllvm14-14.0.6-h5b596cc_1.tar.bz2#c61f692b0e98efc1ef772fdf7d14e81a https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.39-ha978bb4_0.conda#35e4928794c5391aec14ffdf1deaaee5 https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_0.tar.bz2#ceb13b6726534b96e3b4e3dda91e9050 https://conda.anaconda.org/conda-forge/osx-64/libxcb-1.13-h0d85af4_1004.tar.bz2#eb7860935e14aec936065cbc21a1a962 -https://conda.anaconda.org/conda-forge/osx-64/openssl-3.0.7-hfd90126_1.conda#7a3fb6d40e0aa5dbb5b4ef54462f00a8 +https://conda.anaconda.org/conda-forge/osx-64/openssl-3.0.8-hfd90126_0.conda#4239d01834a13512079046ea216b6657 https://conda.anaconda.org/conda-forge/osx-64/readline-8.1.2-h3899abd_0.tar.bz2#89fa404901fa8fb7d4f4e07083b8d635 https://conda.anaconda.org/conda-forge/osx-64/tapi-1100.0.11-h9ce4665_0.tar.bz2#f9ff42ccf809a21ba6f8607f8de36108 -https://conda.anaconda.org/conda-forge/osx-64/tbb-2021.7.0-hb8565cd_1.conda#1d7d711419ed9e4a96370d8749cec3c1 +https://conda.anaconda.org/conda-forge/osx-64/tbb-2021.8.0-hb8565cd_0.conda#17cc6d45a28433867fc74bf67c3d5459 https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.12-h5dbffcc_0.tar.bz2#8e9480d9c47061db2ed1b4ecce519a7f https://conda.anaconda.org/conda-forge/osx-64/zlib-1.2.13-hfd90126_4.tar.bz2#be90e6223c74ea253080abae19b3bdb1 -https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.2-hfa58983_4.tar.bz2#0b446e84f3ccf085e590dc1f73eebe3f +https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.2-hbc0c0cd_6.conda#40a188783d3c425bdccc9ae9104acbb8 https://conda.anaconda.org/conda-forge/osx-64/brotli-bin-1.0.9-hb7f2c08_8.tar.bz2#aac5ad0d8f747ef7f871508146df75d9 https://conda.anaconda.org/conda-forge/osx-64/freetype-2.12.1-h3f81eb7_1.conda#852224ea3e8991a8342228eab274840e https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp14-14.0.6-default_h55ffa42_0.tar.bz2#9b9bc2f878d47e6846e3d01ca0fcb921 -https://conda.anaconda.org/conda-forge/osx-64/libgfortran-5.0.0-11_3_0_h97931a8_27.conda#7d25335e67256924aa04de681e68e807 -https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.5.0-hee9004a_2.conda#35f714269a801f7c3cb522aacd3c0e69 +https://conda.anaconda.org/conda-forge/osx-64/libgfortran-5.0.0-11_3_0_h97931a8_31.conda#97451338600bd9c5b535eb224ef6c471 +https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.5.0-hd920806_5.conda#2a8205156778648e2663c906f83800c5 https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-14.0.6-h5b596cc_1.tar.bz2#d99491efd3d672b3496e9fc9273da7c0 https://conda.anaconda.org/conda-forge/osx-64/mkl-2022.1.0-h860c996_928.tar.bz2#98a4d58de0ba6e61ce46620b775c19ce -https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.1.0-h0f52abe_1.tar.bz2#afe26b08c2d2265b4d663d199000e5da +https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.0-h4f9bd69_0.conda#f48a2f4515be334c5cfeed82517b96e0 https://conda.anaconda.org/conda-forge/osx-64/python-3.11.0-he7542f4_1_cpython.conda#9ecfa530b33aefd0d22e0272336f638a https://conda.anaconda.org/conda-forge/osx-64/sigtool-0.1.3-h88f4db0_0.tar.bz2#fbfb84b9de9a6939cb165c02c69b1865 -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/osx-64/brotli-1.0.9-hb7f2c08_8.tar.bz2#55f612fe4a9b5f6ac76348b6de94aaeb https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6 @@ -59,17 +57,17 @@ https://conda.anaconda.org/conda-forge/osx-64/clang-14-14.0.6-default_h55ffa42_0 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb https://conda.anaconda.org/conda-forge/osx-64/cython-0.29.33-py311h814d153_0.conda#810cc5100d90e38aa366ca32e3e6749d -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.4-py311hd2070f0_1.tar.bz2#5219e72a43e53e8f6af4fdf76a0f90ef -https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.14-h29502cd_1.conda#1e42174021ffc69545f0814b9478dee3 +https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.15-h2dcdeff_1.conda#f1df9b0c2d9fbe985e62f4b24773a9e4 https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-609-hfd63004_11.conda#8881d41cb8fa1104d4545c6b7ddc9671 https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-16_osx64_mkl.tar.bz2#96b23c2ca3208c5cb1ed34270448af5c https://conda.anaconda.org/conda-forge/osx-64/libhiredis-1.0.2-h2beb688_0.tar.bz2#524282b2c46c9dedf051b3bc2ae05494 https://conda.anaconda.org/conda-forge/osx-64/mkl-devel-2022.1.0-h694c41f_929.tar.bz2#041ceef009fe6d29cbd2555907c23ab3 -https://conda.anaconda.org/conda-forge/osx-64/mpc-1.2.1-hbb51d92_0.tar.bz2#9f46d6ad4c460679ee997abc10da3bac +https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h81bd1dd_0.conda#c752c0eb6c250919559172c011e5f65b https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/osx-64/openjpeg-2.5.0-h13ac156_2.conda#299a29af9ac9f550ad459d655739280b https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b @@ -78,58 +76,59 @@ https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b46 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7-pyhd8ed1ab_0.conda#c8d7e34ca76d6ecc03b84bedfd99d689 -https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a +https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7.1-pyhd8ed1ab_0.conda#f59d49a7b464901cf714b9e7984d01a2 +https://conda.anaconda.org/conda-forge/noarch/setuptools-67.6.0-pyhd8ed1ab_0.conda#e18ed61c37145bb9b48d1d98801960f7 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/osx-64/tornado-6.2-py311h5547dcb_1.tar.bz2#bc9918caedfa2de9e582104bf605d57d -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/osx-64/ccache-4.7.3-h2822714_0.tar.bz2#a119676fd25b0268da665107f7176ec6 https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-973.0.1-hcc6d90d_11.conda#f1af817221bc31e7c770e1ea15374355 https://conda.anaconda.org/conda-forge/osx-64/cffi-1.15.1-py311ha86e640_3.conda#5967be4da33261eada7cc79593f71088 https://conda.anaconda.org/conda-forge/osx-64/clang-14.0.6-h694c41f_0.tar.bz2#77667c3c75b88f12782f628d171ffeda -https://conda.anaconda.org/conda-forge/osx-64/coverage-7.0.5-py311h5547dcb_0.conda#a95045e19d6928ff497adc4bd47b032b -https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.38.0-py311h5547dcb_1.tar.bz2#6fc564da4dd28e360f4cfee7bee95cf9 -https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-11.3.0-h1f927f5_27.conda#0bb7f54e22a2136588b33e7b0bf24148 +https://conda.anaconda.org/conda-forge/osx-64/coverage-7.2.1-py311h5547dcb_0.conda#920a96ad1180ab4cd6629f05a3d1aa2b +https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.39.0-py311h5547dcb_0.conda#71ca7a0861fcba81e88c4221e58ca527 +https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-11.3.0-h1f927f5_31.conda#926da9259d77f6a95d60c5a956425c2f https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb https://conda.anaconda.org/conda-forge/osx-64/ld64-609-hc6ad406_11.conda#9e14075f26a915bc6180b40789138adf https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-16_osx64_mkl.tar.bz2#430c4d18fd8bbc987c4367f5d16135cf https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-16_osx64_mkl.tar.bz2#757f1ae46973ce6542784d99b9984d8d -https://conda.anaconda.org/conda-forge/osx-64/pillow-9.4.0-py311hafe3759_0.conda#1a60f73d3348e46610f4b6d4d0b25c5f -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/osx-64/pillow-9.4.0-py311hf47c0a6_2.conda#4607ae953e3b427be289048f8314b778 +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/osx-64/brotlipy-0.7.0-py311h5547dcb_1005.tar.bz2#5f97ac938a90d06eebea42c321abe0d7 https://conda.anaconda.org/conda-forge/osx-64/cctools-973.0.1-h76f1dac_11.conda#77d8192c013d7a4a355aee5b0ae1ae20 https://conda.anaconda.org/conda-forge/osx-64/clangxx-14.0.6-default_h55ffa42_0.tar.bz2#6a46064b0506895d090302433e70397b -https://conda.anaconda.org/conda-forge/osx-64/cryptography-39.0.0-py311h61927ef_0.conda#b2893b3bd6cb56dbac5278a976fc0502 +https://conda.anaconda.org/conda-forge/osx-64/cryptography-39.0.2-py311h61927ef_0.conda#46ed09cb9666419cc7f3547ecb03037f https://conda.anaconda.org/conda-forge/osx-64/liblapacke-3.9.0-16_osx64_mkl.tar.bz2#ba52eebcca282a5abaa3d3ac79cf2b05 -https://conda.anaconda.org/conda-forge/osx-64/numpy-1.24.1-py311h62c7003_0.conda#b1994c9a248f5a0b45b641f185dbaede +https://conda.anaconda.org/conda-forge/osx-64/numpy-1.24.2-py311ha9d2c9f_0.conda#bcd25d27b63e7d57defd8ebdf67dc361 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.0.0-pyhd8ed1ab_0.tar.bz2#c9e3f8bfdb9bfc34aa1836a6ed4b25d7 -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 https://conda.anaconda.org/conda-forge/osx-64/blas-devel-3.9.0-16_osx64_mkl.tar.bz2#2fb6331f94446754c896d1f11d3afa1c https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-14.0.6-hab78ec2_0.tar.bz2#4fdde3f4ed31722a1c811723f5db82f0 https://conda.anaconda.org/conda-forge/osx-64/contourpy-1.0.7-py311hd2070f0_0.conda#d78f75103409d2c7a8774c873821ae9a -https://conda.anaconda.org/conda-forge/osx-64/pandas-1.5.2-py311hd84f3f5_2.conda#2952f7263a51d4286f1ff168887a5715 +https://conda.anaconda.org/conda-forge/osx-64/pandas-1.5.3-py311hd84f3f5_0.conda#ec94f0de8411bbc63098cb01324b6683 https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e https://conda.anaconda.org/conda-forge/osx-64/blas-2.116-mkl.tar.bz2#bcaf774ad76aa575f4b60c585c2a8dab https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-14.0.6-h613da45_0.tar.bz2#b44e0625319f9933e584dc3b96f5baf7 -https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.6.2-py311h2bf763f_0.tar.bz2#23cef32adc676da209c6c4874f29523f -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.14-pyhd8ed1ab_0.conda#01f33ad2e0aaf6b5ba4add50dad5ad29 +https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.7.1-py311h2bf763f_0.conda#d67ac9c9b834ae77ff7b2c59f702803c +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-14.0.6-h3113cd8_4.conda#e1828ef1597292a9ea25627fdfacb9f3 -https://conda.anaconda.org/conda-forge/osx-64/matplotlib-3.6.2-py311h6eed73b_0.tar.bz2#b3db01070d46627acacf2d9d582b4643 -https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 +https://conda.anaconda.org/conda-forge/osx-64/matplotlib-3.7.1-py311h6eed73b_0.conda#c112be16f02d1c68de63ae3ec6fc7db4 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.5.2-hbf74d83_0.conda#c1413ef5a20d658923e12dd3b566d8f3 https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-14.0.6-h6f97653_4.conda#f9f2cc37068e5f2f4332793640329fe3 https://conda.anaconda.org/conda-forge/noarch/codecov-2.1.12-pyhd8ed1ab_0.conda#0317ed52e504b93da000e8a027628775 -https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-11.3.0-h18f7dce_0.tar.bz2#72320d23ed499315d1d1ac332b94bc66 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 +https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-11.3.0-h18f7dce_1.conda#4e066d81dd3b86556b723021980f4ed8 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.5.2-hb8565cd_0.conda#349ae14723b98f76ea0fcb8e532b2ead -https://conda.anaconda.org/conda-forge/osx-64/gfortran-11.3.0-h2c809b3_0.tar.bz2#db5338d1fb1ad08498bdc1b42277a0d5 -https://conda.anaconda.org/conda-forge/osx-64/scipy-1.10.0-py311h939689b_0.conda#e2671de176eb4b2fb0f7bd5071ed3233 +https://conda.anaconda.org/conda-forge/osx-64/gfortran-11.3.0-h2c809b3_1.conda#0d856a032891847a9e61dd68149dd889 +https://conda.anaconda.org/conda-forge/osx-64/scipy-1.10.1-py311h939689b_0.conda#c0ba4b8d033cd4b2af087ef96e98db04 https://conda.anaconda.org/conda-forge/osx-64/fortran-compiler-1.5.2-haad3a49_0.conda#649a324b13eb77c6d5e98d36ea0c59f4 https://conda.anaconda.org/conda-forge/osx-64/pyamg-4.2.3-py311h349b758_2.tar.bz2#59bc03179823f04c8647df161695e8cc https://conda.anaconda.org/conda-forge/osx-64/compilers-1.5.2-h694c41f_0.conda#1fdd3bc173dad6e7a0439962c7764ab8 diff --git a/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock b/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock index ca0232cf3197d..4ac5f819ac18a 100644 --- a/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock +++ b/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock @@ -3,30 +3,29 @@ # input_hash: 211dc0aa2fa7562dd69a06e538952166b6595d4ba2e4d2c8351253db0e501950 @EXPLICIT https://repo.anaconda.com/pkgs/main/osx-64/blas-1.0-mkl.conda#cb2c87e85ac8e0ceae776d26d4214c8a -https://repo.anaconda.com/pkgs/main/osx-64/ca-certificates-2022.10.11-hecd8cb5_0.conda#47d4ae6c764c72394363ca6daa50e6d0 -https://repo.anaconda.com/pkgs/main/osx-64/fftw-3.3.9-h9ed2024_1.conda#9f854d761737b9a8bf9859779a5bb405 -https://repo.anaconda.com/pkgs/main/osx-64/giflib-5.2.1-haf1e3a3_0.conda#0c36d6800a1a0f0ae244699a09d3f982 +https://repo.anaconda.com/pkgs/main/osx-64/ca-certificates-2023.01.10-hecd8cb5_0.conda#4544150389480f19dd67c20b3bb12d61 +https://repo.anaconda.com/pkgs/main/osx-64/giflib-5.2.1-h6c40b1e_3.conda#a5ab49bdb6fdc875fb965221241e3bcf https://repo.anaconda.com/pkgs/main/osx-64/intel-openmp-2021.4.0-hecd8cb5_3538.conda#65e79d0ffef79cbb8ebd3c71e74eb50a -https://repo.anaconda.com/pkgs/main/osx-64/jpeg-9e-hca72f7f_0.conda#99b7d820514a0c07818d58c320ab21fc +https://repo.anaconda.com/pkgs/main/osx-64/jpeg-9e-h6c40b1e_1.conda#fc3e61fa41309946c9283fe8737d7f41 https://repo.anaconda.com/pkgs/main/osx-64/libbrotlicommon-1.0.9-hca72f7f_7.conda#6c865b9e76fa2fad0c8ac32aa0f01f75 https://repo.anaconda.com/pkgs/main/osx-64/libcxx-14.0.6-h9765a3e_0.conda#387757bb354ae9042370452cd0fb5627 -https://repo.anaconda.com/pkgs/main/osx-64/libdeflate-1.8-h9ed2024_5.conda#584dec4a4ba735d8d7841de1948b23b1 +https://repo.anaconda.com/pkgs/main/osx-64/libdeflate-1.17-hb664fd8_0.conda#4236b26b451011822d3a3086282063c0 https://repo.anaconda.com/pkgs/main/osx-64/libffi-3.4.2-hecd8cb5_6.conda#21b9e281d6c7d4c6c9bff64c7644f295 -https://repo.anaconda.com/pkgs/main/osx-64/libwebp-base-1.2.4-hca72f7f_0.conda#4196bca3e5be38659521163af8918460 +https://repo.anaconda.com/pkgs/main/osx-64/libwebp-base-1.2.4-h6c40b1e_1.conda#b5ba90f49396f024ee017794b28e8263 https://repo.anaconda.com/pkgs/main/osx-64/llvm-openmp-14.0.6-h0dcd299_0.conda#b5804d32b87dc61ca94561ade33d5f2d -https://repo.anaconda.com/pkgs/main/osx-64/ncurses-6.3-hca72f7f_3.conda#dba236b91a8c0ef6ddecc56e387e92d2 +https://repo.anaconda.com/pkgs/main/osx-64/ncurses-6.4-hcec6c5f_0.conda#0214d1ee980e217fabc695f1e40662aa https://repo.anaconda.com/pkgs/main/noarch/tzdata-2022g-h04d1e81_0.conda#833facc4bfeebcb61babe76257e8c9e8 -https://repo.anaconda.com/pkgs/main/osx-64/xz-5.2.8-h6c40b1e_0.conda#a10644e3dbb910acd9518a4ecd36624f +https://repo.anaconda.com/pkgs/main/osx-64/xz-5.2.10-h6c40b1e_1.conda#c81635cd7ee34a70b36a3bb3af119c77 https://repo.anaconda.com/pkgs/main/osx-64/zlib-1.2.13-h4dc903c_0.conda#d0202dd912bfb45d3422786531717882 https://repo.anaconda.com/pkgs/main/osx-64/ccache-3.7.9-hf120daa_0.conda#a01515a32e721c51d631283f991bc8ea https://repo.anaconda.com/pkgs/main/osx-64/lerc-3.0-he9d5cce_0.conda#aec2c3dbef836849c9260f05be04f3db https://repo.anaconda.com/pkgs/main/osx-64/libbrotlidec-1.0.9-hca72f7f_7.conda#b85983951745cc666d9a1b42894210b2 https://repo.anaconda.com/pkgs/main/osx-64/libbrotlienc-1.0.9-hca72f7f_7.conda#e306d7a1599202a7c95762443f110832 https://repo.anaconda.com/pkgs/main/osx-64/libgfortran5-11.3.0-h9dfd629_28.conda#1fa1a27ee100b1918c3021dbfa3895a3 -https://repo.anaconda.com/pkgs/main/osx-64/libpng-1.6.37-ha441bb4_0.conda#d69245a20ec59d8dc534c65308607129 +https://repo.anaconda.com/pkgs/main/osx-64/libpng-1.6.39-h6c40b1e_0.conda#a3c824835f53ad27aeb86d2b55e47804 https://repo.anaconda.com/pkgs/main/osx-64/lz4-c-1.9.4-hcec6c5f_0.conda#44291e9e6920cfff30caf1299f48db38 https://repo.anaconda.com/pkgs/main/osx-64/mkl-2021.4.0-hecd8cb5_637.conda#07d14ece4a852cefa17c1c156db8134e -https://repo.anaconda.com/pkgs/main/osx-64/openssl-1.1.1s-hca72f7f_0.conda#180ff0f1449f1d62dc91495e5aef2902 +https://repo.anaconda.com/pkgs/main/osx-64/openssl-1.1.1t-hca72f7f_0.conda#5027baac278975d148ee3887b3f4e911 https://repo.anaconda.com/pkgs/main/osx-64/readline-8.2-hca72f7f_0.conda#971667436260e523f6f7355fdfa238bf https://repo.anaconda.com/pkgs/main/osx-64/tk-8.6.12-h5d9f67b_0.conda#047f0af5486d19163e37fd7f8ae3d29f https://repo.anaconda.com/pkgs/main/osx-64/brotli-bin-1.0.9-hca72f7f_7.conda#110bdca1a20710820e61f7fa3047f737 @@ -35,8 +34,9 @@ https://repo.anaconda.com/pkgs/main/osx-64/libgfortran-5.0.0-11_3_0_hecd8cb5_28. https://repo.anaconda.com/pkgs/main/osx-64/sqlite-3.40.1-h880c91c_0.conda#88f64d3c988ae3688131cb38910776c0 https://repo.anaconda.com/pkgs/main/osx-64/zstd-1.5.2-hcb37349_0.conda#d3ba225e3bc4285d8efd8cdfd7aa6112 https://repo.anaconda.com/pkgs/main/osx-64/brotli-1.0.9-hca72f7f_7.conda#68e54d12ec67591deb2ffd70348fb00f -https://repo.anaconda.com/pkgs/main/osx-64/libtiff-4.5.0-h2cd0358_0.conda#bb0e56075e0028ac3105aede2dcae0cb -https://repo.anaconda.com/pkgs/main/osx-64/python-3.9.15-h218abb5_2.conda#895bf75918bb226c1040edadef5413fc +https://repo.anaconda.com/pkgs/main/osx-64/libtiff-4.5.0-hcec6c5f_2.conda#f0b033a82af1bd028f112cdecef1fe0a +https://repo.anaconda.com/pkgs/main/osx-64/python-3.9.16-h218abb5_2.conda#590b5a60ce20913ad4bc77f38654bc2c +https://repo.anaconda.com/pkgs/main/noarch/appdirs-1.4.4-pyhd3eb1b0_0.conda#5673d98d06171cb6eed03a6736845c4d https://repo.anaconda.com/pkgs/main/osx-64/attrs-22.1.0-py39hecd8cb5_0.conda#d0b7738bb61bd74eedfc833533dd14d4 https://repo.anaconda.com/pkgs/main/osx-64/certifi-2022.12.7-py39hecd8cb5_0.conda#92d58f42b23801c40b4fe2ee5ba93085 https://repo.anaconda.com/pkgs/main/noarch/charset-normalizer-2.0.4-pyhd3eb1b0_0.conda#e7a441d94234b2b5fafee06e25dbf076 @@ -48,7 +48,7 @@ https://repo.anaconda.com/pkgs/main/noarch/iniconfig-1.1.1-pyhd3eb1b0_0.tar.bz2# https://repo.anaconda.com/pkgs/main/osx-64/joblib-1.1.1-py39hecd8cb5_0.conda#8c96155e60c4723afd642a6cee396c26 https://repo.anaconda.com/pkgs/main/osx-64/kiwisolver-1.4.4-py39hcec6c5f_0.conda#2ee58ba7ba854969d0b7f7db4d07459d https://repo.anaconda.com/pkgs/main/osx-64/lcms2-2.12-hf1fd2bf_0.conda#697aba7a3308226df7a93ccfeae16ffa -https://repo.anaconda.com/pkgs/main/osx-64/libwebp-1.2.4-h56c3ce4_0.conda#55aab5176f109c67c355ac018e5f7b4a +https://repo.anaconda.com/pkgs/main/osx-64/libwebp-1.2.4-hf6ce154_1.conda#07d0981c3847293d4aea5778298a12d3 https://repo.anaconda.com/pkgs/main/noarch/munkres-1.1.4-py_0.conda#148362ba07f92abab76999a680c80084 https://repo.anaconda.com/pkgs/main/osx-64/packaging-22.0-py39hecd8cb5_0.conda#a1ac08e4d5f08fcb7240edb91639ac0e https://repo.anaconda.com/pkgs/main/osx-64/pluggy-1.0.0-py39hecd8cb5_1.conda#c5507133514846cc5f54dc4de9ba1563 @@ -62,34 +62,37 @@ https://repo.anaconda.com/pkgs/main/noarch/threadpoolctl-2.2.0-pyh0d69192_0.cond https://repo.anaconda.com/pkgs/main/noarch/toml-0.10.2-pyhd3eb1b0_0.conda#cda05f5f6d8509529d1a2743288d197a https://repo.anaconda.com/pkgs/main/osx-64/tomli-2.0.1-py39hecd8cb5_0.conda#49318006e63c8628ce0a1e2e1433d30d https://repo.anaconda.com/pkgs/main/osx-64/tornado-6.2-py39hca72f7f_0.conda#2653da9c248d53e811364e65353c8742 -https://repo.anaconda.com/pkgs/main/noarch/wheel-0.37.1-pyhd3eb1b0_0.conda#ab85e96e26da8d5797c2458232338b86 +https://repo.anaconda.com/pkgs/main/osx-64/wheel-0.38.4-py39hecd8cb5_0.conda#a220b0cb159f300ced9a8fc9974a2f14 +https://repo.anaconda.com/pkgs/main/osx-64/zipp-3.11.0-py39hecd8cb5_0.conda#9bef65af2d31209e9b0db05b2c83df42 https://repo.anaconda.com/pkgs/main/osx-64/cffi-1.15.1-py39h6c40b1e_3.conda#c9df0a268b6168cb890a6f65e2a81c71 https://repo.anaconda.com/pkgs/main/noarch/fonttools-4.25.0-pyhd3eb1b0_0.conda#bb9c5b5a6d892fca5efe4bf0203b6a48 +https://repo.anaconda.com/pkgs/main/noarch/importlib_resources-5.2.0-pyhd3eb1b0_1.conda#3e7caf9dbd3b4771e9b951ffc7cdad80 https://repo.anaconda.com/pkgs/main/osx-64/mkl-service-2.4.0-py39h9ed2024_0.conda#68ed4da109042256b78f9c46537bd2a3 -https://repo.anaconda.com/pkgs/main/osx-64/pillow-9.3.0-py39h81888ad_1.conda#f4d55ddb76868ac9823f1e986fdfe535 +https://repo.anaconda.com/pkgs/main/osx-64/pillow-9.4.0-py39hcec6c5f_0.conda#5b5389309701442bd3949665e9a88d7e https://repo.anaconda.com/pkgs/main/osx-64/pytest-7.1.2-py39hecd8cb5_0.conda#8239bdb679b675ab8aac1bdc0756d383 https://repo.anaconda.com/pkgs/main/noarch/python-dateutil-2.8.2-pyhd3eb1b0_0.conda#211ee00320b08a1ac9fea6677649f6c9 https://repo.anaconda.com/pkgs/main/osx-64/setuptools-65.6.3-py39hecd8cb5_0.conda#762fa88e92dfd5b5158cc58e7860b252 https://repo.anaconda.com/pkgs/main/osx-64/brotlipy-0.7.0-py39h9ed2024_1003.conda#a08f6f5f899aff4a07351217b36fae41 -https://repo.anaconda.com/pkgs/main/osx-64/cryptography-38.0.4-py39hf6deb26_0.conda#60f85eabbcadcab133178381076a53cb +https://repo.anaconda.com/pkgs/main/osx-64/cryptography-39.0.1-py39hf6deb26_0.conda#47eae0abc1b7f4c285ab4a4b49e34f4b https://repo.anaconda.com/pkgs/main/osx-64/numpy-base-1.22.3-py39h3b1a694_0.conda#f68019d1d839b40739b64b6feae2b436 -https://repo.anaconda.com/pkgs/main/osx-64/pip-22.3.1-py39hecd8cb5_0.conda#2b9cc526d938898ddac198c863985532 +https://repo.anaconda.com/pkgs/main/osx-64/pip-23.0.1-py39hecd8cb5_0.conda#e1064a892ad81368df4de5f5c66225e0 https://repo.anaconda.com/pkgs/main/noarch/pytest-cov-3.0.0-pyhd3eb1b0_0.conda#bbdaac2947f507399816d509107945c2 https://repo.anaconda.com/pkgs/main/noarch/pytest-forked-1.3.0-pyhd3eb1b0_0.tar.bz2#07970bffdc78f417d7f8f1c7e620f5c4 -https://repo.anaconda.com/pkgs/main/noarch/pyopenssl-22.0.0-pyhd3eb1b0_0.conda#1dbbf9422269cd62c7094960d9b43f36 +https://repo.anaconda.com/pkgs/main/osx-64/pyopenssl-23.0.0-py39hecd8cb5_0.conda#ed50ac428785ce7539f175822e834cfd https://repo.anaconda.com/pkgs/main/noarch/pytest-xdist-2.5.0-pyhd3eb1b0_0.conda#d15cdc4207bcf8ca920822597f1d138d -https://repo.anaconda.com/pkgs/main/osx-64/urllib3-1.26.13-py39hecd8cb5_0.conda#e70b93b82feff4e4f9331ed455d1f6dc -https://repo.anaconda.com/pkgs/main/osx-64/requests-2.28.1-py39hecd8cb5_0.conda#c2a59bb72db0abd039ce447be18c139d +https://repo.anaconda.com/pkgs/main/osx-64/urllib3-1.26.14-py39hecd8cb5_0.conda#dc5d0364bf213af8a0ab1e75d608230c +https://repo.anaconda.com/pkgs/main/osx-64/requests-2.28.1-py39hecd8cb5_1.conda#ca1021033fe6ba4cf13b563afed0b9ef https://repo.anaconda.com/pkgs/main/noarch/codecov-2.1.11-pyhd3eb1b0_0.conda#83a743cc928162d53d4066c43468b2c7 +https://repo.anaconda.com/pkgs/main/noarch/pooch-1.4.0-pyhd3eb1b0_0.conda#69ec83cb3d152f9e854115555004f368 https://repo.anaconda.com/pkgs/main/osx-64/bottleneck-1.3.5-py39h67323c0_0.conda#312133560b81ec1a2aaf95835e90b5e9 https://repo.anaconda.com/pkgs/main/osx-64/contourpy-1.0.5-py39haf03e11_0.conda#e4bf1c4fc91f39170273f422f2c97481 -https://repo.anaconda.com/pkgs/main/osx-64/matplotlib-3.6.2-py39hecd8cb5_0.conda#0a51906c4a2e76edaaffac06a1b352e8 -https://repo.anaconda.com/pkgs/main/osx-64/matplotlib-base-3.6.2-py39h220de94_0.conda#3e1c1bc56bf1636b5dd01510cf511c05 +https://repo.anaconda.com/pkgs/main/osx-64/matplotlib-3.7.1-py39hecd8cb5_0.conda#def38432cfad6112990ab62dda400df2 +https://repo.anaconda.com/pkgs/main/osx-64/matplotlib-base-3.7.1-py39hda11e5a_0.conda#855735aaf9938f5a56fa5d02e92cb615 https://repo.anaconda.com/pkgs/main/osx-64/mkl_fft-1.3.1-py39h4ab4a9b_0.conda#f947c9a1c65da729963b3035c219ba10 https://repo.anaconda.com/pkgs/main/osx-64/mkl_random-1.2.2-py39hb2f4e1b_0.conda#1bc33de45069ad534182ca92e616ec7e https://repo.anaconda.com/pkgs/main/osx-64/numpy-1.22.3-py39h2e5f0a9_0.conda#16892a18dae1fb1522845e4b6005b436 https://repo.anaconda.com/pkgs/main/osx-64/numexpr-2.8.4-py39he696674_0.conda#9776eb34625bf969ba017f7362ecf23f -https://repo.anaconda.com/pkgs/main/osx-64/scipy-1.9.3-py39h3d31255_0.conda#c2917042394d646f4a2ca22e0b665a06 -https://repo.anaconda.com/pkgs/main/osx-64/pandas-1.5.2-py39h07fba90_0.conda#ff5c1d08cf4022f6b58ef4f53ba768d1 +https://repo.anaconda.com/pkgs/main/osx-64/scipy-1.10.0-py39h91c6ef4_1.conda#517710e1e02bcaff317d317d73455939 +https://repo.anaconda.com/pkgs/main/osx-64/pandas-1.5.3-py39h07fba90_0.conda#69af9747b3840ae270bf0ec30d321da1 https://repo.anaconda.com/pkgs/main/osx-64/pyamg-4.2.3-py39hc29d2bd_0.conda#728a52ac4cc423a4895158c08b95bedf # pip cython @ https://files.pythonhosted.org/packages/56/3a/e59db3769dee48409c759a88b62cd605324e05d396e10af0a065adc956ad/Cython-0.29.33-py2.py3-none-any.whl#sha256=8b99252bde8ff51cd06a3fe4aeacd3af9b4ff4a4e6b701ac71bddc54f5da61d6 diff --git a/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock b/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock index adb785ba36f92..0b72d882699fb 100644 --- a/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock +++ b/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock @@ -3,7 +3,7 @@ # input_hash: c268536f64c353efd8a32b7f76ae09489ef30493354dfdfa69f5e648f908ad75 @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 -https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2022.10.11-h06a4308_0.conda#e9b86b388e2cf59585fefca34037b783 +https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2023.01.10-h06a4308_0.conda#7704989a2ccf6c1f5a50c985509841c4 https://repo.anaconda.com/pkgs/main/linux-64/ld_impl_linux-64-2.38-h1181459_1.conda#68eedfd9c06f2b0e6888d8db345b7f5b https://repo.anaconda.com/pkgs/main/noarch/tzdata-2022g-h04d1e81_0.conda#833facc4bfeebcb61babe76257e8c9e8 https://repo.anaconda.com/pkgs/main/linux-64/libgomp-11.2.0-h1234567_1.conda#b372c0eea9b60732fdae4b817a63c8cd @@ -11,15 +11,15 @@ https://repo.anaconda.com/pkgs/main/linux-64/libstdcxx-ng-11.2.0-h1234567_1.cond https://repo.anaconda.com/pkgs/main/linux-64/_openmp_mutex-5.1-1_gnu.conda#71d281e9c2192cb3fa425655a8defb85 https://repo.anaconda.com/pkgs/main/linux-64/libgcc-ng-11.2.0-h1234567_1.conda#a87728dabf3151fb9cfa990bd2eb0464 https://repo.anaconda.com/pkgs/main/linux-64/libffi-3.4.2-h6a678d5_6.conda#6d65e299b535d3b3613b6d4bce901834 -https://repo.anaconda.com/pkgs/main/linux-64/ncurses-6.3-h5eee18b_3.conda#0c616f387885c1bbb57ec0bd1e779ced -https://repo.anaconda.com/pkgs/main/linux-64/openssl-1.1.1s-h7f8727e_0.conda#25f9c4e2394976be98d01cccef2ce43a -https://repo.anaconda.com/pkgs/main/linux-64/xz-5.2.8-h5eee18b_0.conda#224260858072f0071140ae18c513620d +https://repo.anaconda.com/pkgs/main/linux-64/ncurses-6.4-h6a678d5_0.conda#5558eec6e2191741a92f832ea826251c +https://repo.anaconda.com/pkgs/main/linux-64/openssl-1.1.1t-h7f8727e_0.conda#0410db682c02665511bd4203ade48a32 +https://repo.anaconda.com/pkgs/main/linux-64/xz-5.2.10-h5eee18b_1.conda#dd172c348274807ec0d841df8295b670 https://repo.anaconda.com/pkgs/main/linux-64/zlib-1.2.13-h5eee18b_0.conda#333e31fbfbb5057c92fa845ad6adef93 https://repo.anaconda.com/pkgs/main/linux-64/ccache-3.7.9-hfe4627d_0.conda#bef6fc681c273bb7bd0c67d1a591365e https://repo.anaconda.com/pkgs/main/linux-64/readline-8.2-h5eee18b_0.conda#be42180685cce6e6b0329201d9f48efb https://repo.anaconda.com/pkgs/main/linux-64/tk-8.6.12-h1ccaba5_0.conda#fa10ff4aa631fa4aa090a6234d7770b9 https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.40.1-h5082296_0.conda#7d44bb7460f1b1b0764d63240d7f7f81 -https://repo.anaconda.com/pkgs/main/linux-64/python-3.9.15-h7a1cb2a_2.conda#11aaa2155e45d001f854b7edb84bca39 +https://repo.anaconda.com/pkgs/main/linux-64/python-3.9.16-h7a1cb2a_2.conda#6b4f255f11b3facb3fa17061757b8cc2 https://repo.anaconda.com/pkgs/main/noarch/alabaster-0.7.12-pyhd3eb1b0_0.tar.bz2#21ad3b69a5ce6c22e724e9dbb4cffa65 https://repo.anaconda.com/pkgs/main/linux-64/certifi-2022.12.7-py39h06a4308_0.conda#b4238d910e43d09651eebe8db79b5c68 https://repo.anaconda.com/pkgs/main/noarch/charset-normalizer-2.0.4-pyhd3eb1b0_0.conda#e7a441d94234b2b5fafee06e25dbf076 @@ -40,7 +40,7 @@ https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd3eb1 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-jsmath-1.0.1-pyhd3eb1b0_0.tar.bz2#e43f8de7d6a717935ab220a0c957771d https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-qthelp-1.0.3-pyhd3eb1b0_0.tar.bz2#08d67f73f640b4d1e5e8890a324b60e3 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd3eb1b0_0.conda#0440b84dfd478f340cf14c2d7c24f6c7 -https://repo.anaconda.com/pkgs/main/noarch/wheel-0.37.1-pyhd3eb1b0_0.conda#ab85e96e26da8d5797c2458232338b86 +https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.38.4-py39h06a4308_0.conda#83e731cfecb3797a0f2865615177f433 https://repo.anaconda.com/pkgs/main/linux-64/zipp-3.11.0-py39h06a4308_0.conda#6b0ec14d6d5182748006e984590daca5 https://repo.anaconda.com/pkgs/main/linux-64/babel-2.11.0-py39h06a4308_0.conda#57afaec3ce18928835e87fa5187ef22c https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.15.1-py39h5eee18b_3.conda#89bf9aee92a2429222630337bec3d73f @@ -48,23 +48,24 @@ https://repo.anaconda.com/pkgs/main/linux-64/importlib-metadata-4.11.3-py39h06a4 https://repo.anaconda.com/pkgs/main/linux-64/jinja2-3.1.2-py39h06a4308_0.conda#1ae40578c29a6ed9ca0cf23c89d48fa4 https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.6.3-py39h06a4308_0.conda#c45480250c7a422ae327df494aced180 https://repo.anaconda.com/pkgs/main/linux-64/brotlipy-0.7.0-py39h27cfd23_1003.conda#be47bcffb9e3e7495897b02589f5ad1a -https://repo.anaconda.com/pkgs/main/linux-64/cryptography-38.0.4-py39h9ce1e76_0.conda#52136f55ebc78ad10354df15ddaa581a -https://repo.anaconda.com/pkgs/main/linux-64/pip-22.3.1-py39h06a4308_0.conda#551a81c65d85d3bfd0f849fdda5bfad8 -https://repo.anaconda.com/pkgs/main/noarch/pyopenssl-22.0.0-pyhd3eb1b0_0.conda#1dbbf9422269cd62c7094960d9b43f36 -https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.13-py39h06a4308_0.conda#5028912afd81b82cb7f70bbb45ce873b -https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py39h06a4308_0.conda#5ae2a5b6b791e0a8f5b0129b59e5e793 +https://repo.anaconda.com/pkgs/main/linux-64/cryptography-39.0.1-py39h9ce1e76_0.conda#38eea02c5f2ff123ddfa0b706482d0d3 +https://repo.anaconda.com/pkgs/main/linux-64/pip-23.0.1-py39h06a4308_0.conda#e36d76b4611ca9b5d8bd180232aecbac +https://repo.anaconda.com/pkgs/main/linux-64/pyopenssl-23.0.0-py39h06a4308_0.conda#9043b6369acf9a81d7156404c0b38806 +https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.14-py39h06a4308_0.conda#db9c2b56e835ae5ba800e8821c37b27c +https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py39h06a4308_1.conda#90e023425c3be3a4b905278703984fbc https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py39h06a4308_0.conda#8ea4d14304219bfcb4a67da8b34d76ce # pip attrs @ https://files.pythonhosted.org/packages/fb/6e/6f83bf616d2becdf333a1640f1d463fef3150e2e926b7010cb0f81c95e88/attrs-22.2.0-py3-none-any.whl#sha256=29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 # pip cycler @ https://files.pythonhosted.org/packages/5c/f9/695d6bedebd747e5eb0fe8fad57b72fdf25411273a39791cde838d5a8f51/cycler-0.11.0-py3-none-any.whl#sha256=3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3 # pip cython @ https://files.pythonhosted.org/packages/87/4c/41e4fc95a31ec6747e74283e987fb9b3b7c0b3cb2cf10af65f02bd0359d4/Cython-0.29.33-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl#sha256=4f88c2dc0653eef6468848eb8022faf64115b39734f750a1c01a7ba7eb04d89f -# pip exceptiongroup @ https://files.pythonhosted.org/packages/e8/14/9c6a7e5f12294ccd6975a45e02899ed25468cd7c2c86f3d9725f387f9f5f/exceptiongroup-1.1.0-py3-none-any.whl#sha256=327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e +# pip exceptiongroup @ https://files.pythonhosted.org/packages/61/97/17ed81b7a8d24d8f69b62c0db37abbd8c0042d4b3fc429c73dab986e7483/exceptiongroup-1.1.1-py3-none-any.whl#sha256=232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e # pip execnet @ https://files.pythonhosted.org/packages/81/c0/3072ecc23f4c5e0a1af35e3a222855cfd9c80a1a105ca67be3b6172637dd/execnet-1.9.0-py2.py3-none-any.whl#sha256=a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142 -# pip fonttools @ https://files.pythonhosted.org/packages/e3/d9/e9bae85e84737e76ebbcbea13607236da0c0699baed0ae4f1151b728a608/fonttools-4.38.0-py3-none-any.whl#sha256=820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb +# pip fonttools @ https://files.pythonhosted.org/packages/43/6e/810648a366d6488e1e0543f72dcb2016e54ec02933e302cd41d72599e90d/fonttools-4.39.0-py3-none-any.whl#sha256=f5e764e1fd6ad54dfc201ff32af0ba111bcfbe0d05b24540af74c63db4ed6390 # pip iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl#sha256=b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # pip joblib @ https://files.pythonhosted.org/packages/91/d4/3b4c8e5a30604df4c7518c562d4bf0502f2fa29221459226e140cf846512/joblib-1.2.0-py3-none-any.whl#sha256=091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385 # pip kiwisolver @ https://files.pythonhosted.org/packages/a4/36/c414d75be311ce97ef7248edcc4fc05afae2998641bf6b592d43a9dee581/kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f +# pip lazy-loader @ https://files.pythonhosted.org/packages/bc/bf/58dbe1f382ecac2c0571c43b6e95028b14e159d67d75e49a00c26ef63d8f/lazy_loader-0.1-py3-none-any.whl#sha256=623bd4831a40ce659d74472af40a58d016f2a5a047685409affbc2ba5c044641 # pip networkx @ https://files.pythonhosted.org/packages/11/eb/929b1a04b1778f4dd606c739c93c134306e4a31012e31e184c8308f3d985/networkx-3.0-py3-none-any.whl#sha256=58058d66b1818043527244fab9d41a51fcd7dcc271748015f3c181b8a90c8e2e -# pip numpy @ https://files.pythonhosted.org/packages/43/55/fea3342371187dea4044521c0ba82b90fb5a42fb92446be019b316dd3320/numpy-1.24.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=ef85cf1f693c88c1fd229ccd1055570cb41cdf4875873b7728b6301f12cd05bf +# pip numpy @ https://files.pythonhosted.org/packages/f4/f4/45e6e3f7a23b9023554903a122c95585e9787f9403d386bafb7a95d24c9b/numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780 # pip pillow @ https://files.pythonhosted.org/packages/f2/cc/71b11ec996744b704637d9ef53ff924b7d208c41be1d251cca33991f6833/Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e # pip pluggy @ https://files.pythonhosted.org/packages/9e/01/f38e2ff29715251cf25532b9082a1589ab7e4f571ced434f98d0139336dc/pluggy-1.0.0-py2.py3-none-any.whl#sha256=74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3 # pip py @ https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl#sha256=607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 @@ -72,24 +73,25 @@ https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py39h06a4308_0.conda#8 # pip six @ https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl#sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # pip threadpoolctl @ https://files.pythonhosted.org/packages/61/cf/6e354304bcb9c6413c4e02a747b600061c21d38ba51e7e544ac7bc66aecc/threadpoolctl-3.1.0-py3-none-any.whl#sha256=8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b # pip tomli @ https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl#sha256=939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc -# pip typing-extensions @ https://files.pythonhosted.org/packages/0b/8e/f1a0a5a76cfef77e1eb6004cb49e5f8d72634da638420b9ea492ce8305e8/typing_extensions-4.4.0-py3-none-any.whl#sha256=16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e +# pip typing-extensions @ https://files.pythonhosted.org/packages/31/25/5abcd82372d3d4a3932e1fa8c3dbf9efac10cc7c0d16e78467460571b404/typing_extensions-4.5.0-py3-none-any.whl#sha256=fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4 # pip contourpy @ https://files.pythonhosted.org/packages/c7/97/ba9ace011734cd01b63eb7d39b2cf97afbfa985b0239ab0db85bafa9b207/contourpy-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=e7281244c99fd7c6f27c1c6bfafba878517b0b62925a09b586d88ce750a016d2 -# pip coverage @ https://files.pythonhosted.org/packages/9b/38/b407288f8142c3b14c3f36a145d1380e5750781b22997eb1b659f194b093/coverage-7.0.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=13250b1f0bd023e0c9f11838bdeb60214dd5b6aaf8e8d2f110c7e232a1bff83b -# pip imageio @ https://files.pythonhosted.org/packages/11/4a/3e6de99afd3227c68b384f5dd420fe8c2d95f9ad765826a3ce75c5f22dc7/imageio-2.24.0-py3-none-any.whl#sha256=c4ccd0293a1aeb566c7fa04260d51897be064b8fb287a77548ce42050ec06d7a +# pip coverage @ https://files.pythonhosted.org/packages/e5/a9/62aabc67971d2fd439474b05cfc25c852b28bb6dfe8082c5b665652899f5/coverage-7.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=8a6450da4c7afc4534305b2b7d8650131e130610cea448ff240b6ab73d7eab63 +# pip imageio @ https://files.pythonhosted.org/packages/dc/0b/202efcb00ba89c749bb7b22634c917f29a58bdf052dabe8041f23743974f/imageio-2.26.0-py3-none-any.whl#sha256=1a4fdb820abc52ba0f08e770ee46293c334908e8d53217808d9d888f993b1df2 +# pip importlib-resources @ https://files.pythonhosted.org/packages/38/71/c13ea695a4393639830bf96baea956538ba7a9d06fcce7cef10bfff20f72/importlib_resources-5.12.0-py3-none-any.whl#sha256=7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a # pip numpydoc @ https://files.pythonhosted.org/packages/c4/81/ad9b8837442ff451eca82515b41ac425f87acff7e2fc016fd1bda13fc01a/numpydoc-1.5.0-py3-none-any.whl#sha256=c997759fb6fc32662801cece76491eedbc0ec619b514932ffd2b270ae89c07f9 -# pip pytest @ https://files.pythonhosted.org/packages/cc/02/8f59bf194c9a1ceac6330850715e9ec11e21e2408a30a596c65d54cf4d2a/pytest-7.2.1-py3-none-any.whl#sha256=c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5 +# pip pytest @ https://files.pythonhosted.org/packages/b2/68/5321b5793bd506961bd40bdbdd0674e7de4fb873ee7cab33dd27283ad513/pytest-7.2.2-py3-none-any.whl#sha256=130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e # pip python-dateutil @ https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl#sha256=961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 # pip pywavelets @ https://files.pythonhosted.org/packages/5a/98/4549479a32972bdfdd5e75e168219e97f4dfaee535a8308efef7291e8398/PyWavelets-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=71ab30f51ee4470741bb55fc6b197b4a2b612232e30f6ac069106f0156342356 -# pip scipy @ https://files.pythonhosted.org/packages/30/71/bb9e677e30c52f938ff71ba528915c579e794ac0f59804e06bfed3596dff/scipy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=0490dc499fe23e4be35b8b6dd1e60a4a34f0c4adb30ac671e6332446b3cbbb5a +# pip scipy @ https://files.pythonhosted.org/packages/5d/30/b2a2a5bf1a3beefb7609fb871dcc6aef7217c69cef19a4631b7ab5622a8a/scipy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601 # pip setuptools-scm @ https://files.pythonhosted.org/packages/1d/66/8f42c941be949ef2b22fe905d850c794e7c170a526023612aad5f3a121ad/setuptools_scm-7.1.0-py3-none-any.whl#sha256=73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e -# pip tifffile @ https://files.pythonhosted.org/packages/d2/cb/1ecf9f39113a7ad0529a0441a16982791e7b37a4efdba2f89a687fdf15c9/tifffile-2022.10.10-py3-none-any.whl#sha256=87f3aee8a0d06b74655269a105de75c1958a24653e1930d523eb516100043503 +# pip tifffile @ https://files.pythonhosted.org/packages/df/30/b3a70a98b1be0ef881593b7f0ea7fd2aed9f5f3440e90547aa79000a8792/tifffile-2023.2.28-py3-none-any.whl#sha256=8357cd8ccbdd4378ad4d6b84ffe3ab15b1d96630b1719f576d4de386f45546f1 # pip codecov @ https://files.pythonhosted.org/packages/dc/e2/964d0881eff5a67bf5ddaea79a13c7b34a74bc4efe917b368830b475a0b9/codecov-2.1.12-py2.py3-none-any.whl#sha256=585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47 -# pip matplotlib @ https://files.pythonhosted.org/packages/71/4d/6d5176b64cfc5b128e859b7675e72c05db52dcb128196b8a27ba834ff5cd/matplotlib-3.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=809119d1cba3ece3c9742eb01827fe7a0e781ea3c5d89534655a75e07979344f -# pip pandas @ https://files.pythonhosted.org/packages/5e/ed/5c9cdaa5d48c7194bef4335eab3cdc2f8afa868a5546027e018ea9deb4c3/pandas-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=344021ed3e639e017b452aa8f5f6bf38a8806f5852e217a7594417fb9bbfa00e +# pip matplotlib @ https://files.pythonhosted.org/packages/9f/77/0cd22f92f7103383cb1ce3b3efc77411b9cc3a495242c8f2a623b498f586/matplotlib-3.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=f883a22a56a84dba3b588696a2b8a1ab0d2c3d41be53264115c71b0a942d8fdb +# pip pandas @ https://files.pythonhosted.org/packages/e1/4d/3eb96e53a9208350ee21615f850c4be9a246d32bf1d34cd36682cb58c3b7/pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5 # pip pyamg @ https://files.pythonhosted.org/packages/8e/08/d512b6e34d502152723b5a4ad9d962a6141dfe83cd8bcd01af4cb6e84f28/pyamg-4.2.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=18af99d2551df07951c35cf270dc76703f8c5d30b16ea8e61657fda098f57dd7 # pip pytest-cov @ https://files.pythonhosted.org/packages/fe/1f/9ec0ddd33bd2b37d6ec50bb39155bca4fe7085fa78b3b434c05459a860e3/pytest_cov-4.0.0-py3-none-any.whl#sha256=2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b -# pip pytest-forked @ https://files.pythonhosted.org/packages/0c/36/c56ef2aea73912190cdbcc39aaa860db8c07c1a5ce8566994ec9425453db/pytest_forked-1.4.0-py3-none-any.whl#sha256=bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8 -# pip scikit-image @ https://files.pythonhosted.org/packages/0f/29/d157cd648b87212e498189c183a32f0f48e24fe22e9673dacd97594f39fa/scikit_image-0.19.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=ff3b1025356508d41f4fe48528e509d95f9e4015e90cf158cd58c56dc63e0ac5 -# pip scikit-learn @ https://files.pythonhosted.org/packages/83/b5/0436307cb4f91ba280c74746fde7c89bed7a87703a2bf6e21791f56ce6de/scikit_learn-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=de897720173b26842e21bed54362f5294e282422116b61cd931d4f5d870b9855 -# pip lightgbm @ https://files.pythonhosted.org/packages/1f/8f/cb077c8cdb54848ee43d4f4cff927ce4812878d01e677583f3f63c575b2c/lightgbm-3.3.4-py3-none-manylinux1_x86_64.whl#sha256=bf79910a75ba6260cdefa3ddfe030707928ba2a0ffb204c0b6ab31f56fc27ebd +# pip pytest-forked @ https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl#sha256=810958f66a91afb1a1e2ae83089d8dc1cd2437ac96b12963042fbb9fb4d16af0 +# pip scikit-image @ https://files.pythonhosted.org/packages/82/e7/c2ac9801403de908462437c05485c806ae8744edcf8d640862f9501e0c48/scikit_image-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=b856efc75e3051bea6d40a8ffcdaabd5682783ece1aa91c3f6777c3372a98ca1 +# pip scikit-learn @ https://files.pythonhosted.org/packages/81/84/756be2b975959a5f94124d5584ead75d7ca99184f2d16664a0157b274b9a/scikit_learn-1.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=ea061bf0283bf9a9f36ea3c5d3231ba2176221bbd430abd2603b1c3b2ed85c89 +# pip lightgbm @ https://files.pythonhosted.org/packages/38/5c/d9773cf0ea7938f3b777eaacc6f9d58f69ca76a667771364ffefed9095b4/lightgbm-3.3.5-py3-none-manylinux1_x86_64.whl#sha256=044f65664c1a32c98cb619bafa97d8cd9d93c2c2d5053376aadfe509a3a3e7fa # pip pytest-xdist @ https://files.pythonhosted.org/packages/21/08/b1945d4b4986eb1aa10cf84efc5293bba39da80a2f95db3573dd90678408/pytest_xdist-2.5.0-py3-none-any.whl#sha256=6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65 diff --git a/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock b/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock index 79bae626bf65c..151c6e0a62fdb 100644 --- a/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock +++ b/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock @@ -3,7 +3,7 @@ # input_hash: 401344e88dad2c8fde3bee9593788afe08d47c9714c6bb772ee8cc2d1cdcc03e @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 -https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2022.10.11-h06a4308_0.conda#e9b86b388e2cf59585fefca34037b783 +https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2023.01.10-h06a4308_0.conda#7704989a2ccf6c1f5a50c985509841c4 https://repo.anaconda.com/pkgs/main/linux-64/ld_impl_linux-64-2.38-h1181459_1.conda#68eedfd9c06f2b0e6888d8db345b7f5b https://repo.anaconda.com/pkgs/main/noarch/tzdata-2022g-h04d1e81_0.conda#833facc4bfeebcb61babe76257e8c9e8 https://repo.anaconda.com/pkgs/main/linux-64/libgomp-11.2.0-h1234567_1.conda#b372c0eea9b60732fdae4b817a63c8cd @@ -13,15 +13,15 @@ https://repo.anaconda.com/pkgs/main/linux-64/libgcc-ng-11.2.0-h1234567_1.conda#a https://repo.anaconda.com/pkgs/main/linux-64/bzip2-1.0.8-h7b6447c_0.conda#9303f4af7c004e069bae22bde8d800ee https://repo.anaconda.com/pkgs/main/linux-64/libffi-3.4.2-h6a678d5_6.conda#6d65e299b535d3b3613b6d4bce901834 https://repo.anaconda.com/pkgs/main/linux-64/libuuid-1.41.5-h5eee18b_0.conda#4a6a2354414c9080327274aa514e5299 -https://repo.anaconda.com/pkgs/main/linux-64/ncurses-6.3-h5eee18b_3.conda#0c616f387885c1bbb57ec0bd1e779ced -https://repo.anaconda.com/pkgs/main/linux-64/openssl-1.1.1s-h7f8727e_0.conda#25f9c4e2394976be98d01cccef2ce43a -https://repo.anaconda.com/pkgs/main/linux-64/xz-5.2.8-h5eee18b_0.conda#224260858072f0071140ae18c513620d +https://repo.anaconda.com/pkgs/main/linux-64/ncurses-6.4-h6a678d5_0.conda#5558eec6e2191741a92f832ea826251c +https://repo.anaconda.com/pkgs/main/linux-64/openssl-1.1.1t-h7f8727e_0.conda#0410db682c02665511bd4203ade48a32 +https://repo.anaconda.com/pkgs/main/linux-64/xz-5.2.10-h5eee18b_1.conda#dd172c348274807ec0d841df8295b670 https://repo.anaconda.com/pkgs/main/linux-64/zlib-1.2.13-h5eee18b_0.conda#333e31fbfbb5057c92fa845ad6adef93 https://repo.anaconda.com/pkgs/main/linux-64/ccache-3.7.9-hfe4627d_0.conda#bef6fc681c273bb7bd0c67d1a591365e https://repo.anaconda.com/pkgs/main/linux-64/readline-8.2-h5eee18b_0.conda#be42180685cce6e6b0329201d9f48efb https://repo.anaconda.com/pkgs/main/linux-64/tk-8.6.12-h1ccaba5_0.conda#fa10ff4aa631fa4aa090a6234d7770b9 https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.40.1-h5082296_0.conda#7d44bb7460f1b1b0764d63240d7f7f81 -https://repo.anaconda.com/pkgs/main/linux-64/python-3.10.8-h7a1cb2a_1.conda#c50aebbb632aea22b13bd654dfe80a5b +https://repo.anaconda.com/pkgs/main/linux-64/python-3.10.9-h7a1cb2a_2.conda#6f7b15ceb8bbfbadbd8574ceb3912328 https://repo.anaconda.com/pkgs/main/noarch/alabaster-0.7.12-pyhd3eb1b0_0.tar.bz2#21ad3b69a5ce6c22e724e9dbb4cffa65 https://repo.anaconda.com/pkgs/main/linux-64/certifi-2022.12.7-py310h06a4308_0.conda#1f28faeb97a361c9998090edc4e7d729 https://repo.anaconda.com/pkgs/main/noarch/charset-normalizer-2.0.4-pyhd3eb1b0_0.conda#e7a441d94234b2b5fafee06e25dbf076 @@ -42,34 +42,34 @@ https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd3eb1 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-jsmath-1.0.1-pyhd3eb1b0_0.tar.bz2#e43f8de7d6a717935ab220a0c957771d https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-qthelp-1.0.3-pyhd3eb1b0_0.tar.bz2#08d67f73f640b4d1e5e8890a324b60e3 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd3eb1b0_0.conda#0440b84dfd478f340cf14c2d7c24f6c7 -https://repo.anaconda.com/pkgs/main/noarch/wheel-0.37.1-pyhd3eb1b0_0.conda#ab85e96e26da8d5797c2458232338b86 +https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.38.4-py310h06a4308_0.conda#fbb0a31c9dbe6a43fd4a8c6abe744890 https://repo.anaconda.com/pkgs/main/linux-64/babel-2.11.0-py310h06a4308_0.conda#1eff25d9f192342c01d960c6bae79c32 https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.15.1-py310h5eee18b_3.conda#d65505a7028c5cb1d6a078fa688be2be https://repo.anaconda.com/pkgs/main/linux-64/jinja2-3.1.2-py310h06a4308_0.conda#f22cc11648fc31b2cebaafed2dd8d5ec https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.6.3-py310h06a4308_0.conda#d8331a85881df5712194edf67638cf08 https://repo.anaconda.com/pkgs/main/linux-64/brotlipy-0.7.0-py310h7f8727e_1002.conda#a8dfa5aefcc49d5e78000b16d2b7714e -https://repo.anaconda.com/pkgs/main/linux-64/cryptography-38.0.4-py310h9ce1e76_0.conda#f75cc72c0e3460f6959f68171721c74f -https://repo.anaconda.com/pkgs/main/linux-64/pip-22.3.1-py310h06a4308_0.conda#3e3d6059e30595fba64fccb77f9044f0 -https://repo.anaconda.com/pkgs/main/noarch/pyopenssl-22.0.0-pyhd3eb1b0_0.conda#1dbbf9422269cd62c7094960d9b43f36 -https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.13-py310h06a4308_0.conda#01a21b6deb69cf39894c174790c3264f -https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py310h06a4308_0.conda#40bbc3476dde7f941c78c2b10fd73166 +https://repo.anaconda.com/pkgs/main/linux-64/cryptography-39.0.1-py310h9ce1e76_0.conda#71f493886ed29220fb1b6e60ae511e68 +https://repo.anaconda.com/pkgs/main/linux-64/pip-23.0.1-py310h06a4308_0.conda#f8f27960f21f51c3945fae93e2993e85 +https://repo.anaconda.com/pkgs/main/linux-64/pyopenssl-23.0.0-py310h06a4308_0.conda#be4c8fd04572aabe5c4cf6f80cfcb1b8 +https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.14-py310h06a4308_0.conda#e0b4cfc539954199295eda612157b195 +https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py310h06a4308_1.conda#65a9f765635f12679cbfff91d8ebed8e https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py310h06a4308_0.conda#9636e58b351ac5c4cc8367bcc0c29321 -# pip appdirs @ https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl#sha256=a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 # pip attrs @ https://files.pythonhosted.org/packages/fb/6e/6f83bf616d2becdf333a1640f1d463fef3150e2e926b7010cb0f81c95e88/attrs-22.2.0-py3-none-any.whl#sha256=29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 -# pip exceptiongroup @ https://files.pythonhosted.org/packages/e8/14/9c6a7e5f12294ccd6975a45e02899ed25468cd7c2c86f3d9725f387f9f5f/exceptiongroup-1.1.0-py3-none-any.whl#sha256=327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e +# pip exceptiongroup @ https://files.pythonhosted.org/packages/61/97/17ed81b7a8d24d8f69b62c0db37abbd8c0042d4b3fc429c73dab986e7483/exceptiongroup-1.1.1-py3-none-any.whl#sha256=232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e # pip execnet @ https://files.pythonhosted.org/packages/81/c0/3072ecc23f4c5e0a1af35e3a222855cfd9c80a1a105ca67be3b6172637dd/execnet-1.9.0-py2.py3-none-any.whl#sha256=a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142 # pip iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl#sha256=b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 +# pip platformdirs @ https://files.pythonhosted.org/packages/7b/e1/593f693096c50411a2bf9571f66bc3be9d0f79a4a50e95aab581458b0e3c/platformdirs-3.1.1-py3-none-any.whl#sha256=e5986afb596e4bb5bde29a79ac9061aa955b94fca2399b7aaac4090860920dd8 # pip pluggy @ https://files.pythonhosted.org/packages/9e/01/f38e2ff29715251cf25532b9082a1589ab7e4f571ced434f98d0139336dc/pluggy-1.0.0-py2.py3-none-any.whl#sha256=74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3 # pip py @ https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl#sha256=607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 # pip six @ https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl#sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # pip threadpoolctl @ https://files.pythonhosted.org/packages/61/cf/6e354304bcb9c6413c4e02a747b600061c21d38ba51e7e544ac7bc66aecc/threadpoolctl-3.1.0-py3-none-any.whl#sha256=8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b # pip tomli @ https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl#sha256=939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc -# pip coverage @ https://files.pythonhosted.org/packages/01/01/8d17427fbeb0ee132111c543bfeea5ab403d6869812cf6085adc18debecf/coverage-7.0.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=a9fed35ca8c6e946e877893bbac022e8563b94404a605af1d1e6accc7eb73289 +# pip coverage @ https://files.pythonhosted.org/packages/f3/ff/0bf7a9497dc91e4b0f11656a50c95fd1e641d912a281a0b0921d20fa5760/coverage-7.2.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=b2167d116309f564af56f9aa5e75ef710ef871c5f9b313a83050035097b56820 # pip numpydoc @ https://files.pythonhosted.org/packages/c4/81/ad9b8837442ff451eca82515b41ac425f87acff7e2fc016fd1bda13fc01a/numpydoc-1.5.0-py3-none-any.whl#sha256=c997759fb6fc32662801cece76491eedbc0ec619b514932ffd2b270ae89c07f9 -# pip pooch @ https://files.pythonhosted.org/packages/8d/64/8e1bfeda3ba0f267b2d9a918e8ca51db8652d0e1a3412a5b3dbce85d90b6/pooch-1.6.0-py3-none-any.whl#sha256=3bf0e20027096836b8dbce0152dbb785a269abeb621618eb4bdd275ff1e23c9c -# pip pytest @ https://files.pythonhosted.org/packages/cc/02/8f59bf194c9a1ceac6330850715e9ec11e21e2408a30a596c65d54cf4d2a/pytest-7.2.1-py3-none-any.whl#sha256=c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5 +# pip pooch @ https://files.pythonhosted.org/packages/84/8c/4da580db7fb4cfce8f5ed78e7d2aa542e6f201edd69d3d8a96917a8ff63c/pooch-1.7.0-py3-none-any.whl#sha256=74258224fc33d58f53113cf955e8d51bf01386b91492927d0d1b6b341a765ad7 +# pip pytest @ https://files.pythonhosted.org/packages/b2/68/5321b5793bd506961bd40bdbdd0674e7de4fb873ee7cab33dd27283ad513/pytest-7.2.2-py3-none-any.whl#sha256=130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e # pip python-dateutil @ https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl#sha256=961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 # pip codecov @ https://files.pythonhosted.org/packages/dc/e2/964d0881eff5a67bf5ddaea79a13c7b34a74bc4efe917b368830b475a0b9/codecov-2.1.12-py2.py3-none-any.whl#sha256=585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47 # pip pytest-cov @ https://files.pythonhosted.org/packages/fe/1f/9ec0ddd33bd2b37d6ec50bb39155bca4fe7085fa78b3b434c05459a860e3/pytest_cov-4.0.0-py3-none-any.whl#sha256=2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b -# pip pytest-forked @ https://files.pythonhosted.org/packages/0c/36/c56ef2aea73912190cdbcc39aaa860db8c07c1a5ce8566994ec9425453db/pytest_forked-1.4.0-py3-none-any.whl#sha256=bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8 +# pip pytest-forked @ https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl#sha256=810958f66a91afb1a1e2ae83089d8dc1cd2437ac96b12963042fbb9fb4d16af0 # pip pytest-xdist @ https://files.pythonhosted.org/packages/21/08/b1945d4b4986eb1aa10cf84efc5293bba39da80a2f95db3573dd90678408/pytest_xdist-2.5.0-py3-none-any.whl#sha256=6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65 diff --git a/build_tools/azure/pypy3_linux-64_conda.lock b/build_tools/azure/pypy3_linux-64_conda.lock index 536f7484e7576..36843bf98634b 100644 --- a/build_tools/azure/pypy3_linux-64_conda.lock +++ b/build_tools/azure/pypy3_linux-64_conda.lock @@ -13,18 +13,17 @@ https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.2.0-h65d4601_19.tar.bz2#e4c94f80aef025c17ab0828cd85ef535 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54 https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-h27087fc_0.tar.bz2#c4fbad8d4bddeb3c085f18cbf97fbfad -https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.0.9-h166bdaf_8.tar.bz2#9194c9bf9428035a05352d031462eae4 https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.17-h0b41bf4_0.conda#5cc781fd91968b11a8a7fdbee0982676 https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a -https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.4-h166bdaf_0.tar.bz2#b4f717df2d377410b462328bf0e8fb7d +https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.5.1-h0b41bf4_0.conda#1edd9e67bdb90d78cea97733ff6b54e6 https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a6416_3.tar.bz2#8c5963a49b6035c40646a763293fbb35 -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.7-h0b41bf4_1.conda#7adaac6ff98219bcb99b45e408b80f4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 @@ -40,56 +39,71 @@ https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.21-pthreads_h320a7e https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 https://conda.anaconda.org/conda-forge/linux-64/ccache-4.7.3-h2599c5e_0.tar.bz2#4feea9466084c6948bd59539f1c0bb72 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/gdbm-1.18-h0a1914f_2.tar.bz2#b77bc399b07a19c00fe12fdc95ee0297 https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openblas.tar.bz2#20bae26d0a1db73f758fc3754cab4719 https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-h6adf6a1_2.conda#2e648a34072eb39d7c4fc2a9981c5f0c +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.40.0-h4ff8645_0.tar.bz2#bb11803129cbbb53ed56f9506ff74145 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_8.tar.bz2#2ff08978892a3e8b954397c461f18418 -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.14-hfd0df8a_1.conda#c2566c2ea5f153ddd6bf4acaf7547d97 +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d8aca0bc23ca73fa8caa3e7c84c28 https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_openblas.tar.bz2#823ceb5567e1a595deb643fcd17aed5a https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea -https://conda.anaconda.org/conda-forge/linux-64/pypy3.9-7.3.9-hd671c94_7.conda#c15f1c977d796bc23dfd0d9428b2733a +https://conda.anaconda.org/conda-forge/linux-64/pypy3.9-7.3.11-h527bfed_0.conda#24cd81dbe06d6d7171ab9996f78fdfc3 https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-16_linux64_openblas.tar.bz2#519562d6176dab9c2ab9a8336a14c8e7 -https://conda.anaconda.org/conda-forge/linux-64/python-3.9.12-0_73_pypy.tar.bz2#12c038a66ca998f24c381de990e942b6 +https://conda.anaconda.org/conda-forge/linux-64/python-3.9.16-0_73_pypy.conda#16eebd2564f86026ea0abe5b8e446438 https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-openblas.tar.bz2#02f34bcf0aceb6fae4c4d1ecb71c852a https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6 +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1ab_0.tar.bz2#c1d5b294fbf9a795dec349a6f4d8be8e https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 +https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.2-py39h3fbe314_0.conda#fd14e3000e48caabc449c4a6020975b0 https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb https://conda.anaconda.org/conda-forge/linux-64/cython-0.29.33-py39he08593d_0.conda#c44087398a8b69ddb560e18f5ae98512 -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 +https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py39h2865249_1.tar.bz2#6b7e75ba141872a00154f312d43d9a8c https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.1-py39hb10b683_0.conda#9356aa7b1653e1bf66637329a2b41429 +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.2-py39h60c9533_0.conda#2c79957b070d5e10eaa969c30a302674 https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b -https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py39h70337d4_0.conda#80409ac8eed1fbe76aaa279faae3b4a5 +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py39hf87a513_2.conda#cac5b707879890f15bada556ad8370c6 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9 https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054 +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc -https://conda.anaconda.org/conda-forge/noarch/pypy-7.3.9-0_pypy39.tar.bz2#4f9efe821e2c2886da9c2fdc8b480738 -https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a +https://conda.anaconda.org/conda-forge/noarch/pypy-7.3.11-0_pypy39.conda#059800e8aa07f99d31e3dd0bf553a3f6 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 +https://conda.anaconda.org/conda-forge/noarch/setuptools-67.6.0-pyhd8ed1ab_0.conda#e18ed61c37145bb9b48d1d98801960f7 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py39h4d8b378_1.tar.bz2#28cd3041080bd963493b35f7ac64cb12 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.0.0-py39h4d8b378_0.tar.bz2#44eea5be274d005065d87df9cf2a9234 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.15.0-pyhd8ed1ab_0.conda#13018819ca8f5b7cc675a8faf1f5fedf +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py39hfda2a12_3.conda#4156b60c4af658e8a7c45e93360f8855 https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.7-py39haa83c70_0.conda#77595fa3e3dfca46289e3722cb97b29b -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.38.0-py39h4d8b378_1.tar.bz2#32eaab5fec9e6108cb431e7eec99d0cc +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py39h3d6e266_0.conda#88b42bab94be85859cf575dc4d340f66 +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.8.1-py39hec0f089_3.tar.bz2#6df34a135e04f0b91a90ef20a70f7dde -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.6.2-py39hd8616df_0.tar.bz2#03f52764fd4319bbbde7e62c84fc2e11 -https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py39h81e4ded_2.tar.bz2#6fde94a3541607887bb0572be1991d9d -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.6.2-py39h4162558_0.tar.bz2#f392ad75fed5d80854323688aacc2bab +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 +https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py39h4d8b378_1005.tar.bz2#e5b7f34ec76d3b7b2c0b3f13e66dbaa7 +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-5.12.0-pyhd8ed1ab_0.conda#3544c818f0720c89eb16ae6940ab440b +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py39h3a8b213_0.conda#9e1009635ea6b7924f827d6022d0ade6 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py39h4162558_0.conda#b6ca076a90a7f2a8d7ff976d243dd4c5 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py39h60c9533_0.conda#5ffadbb1f4fa2758c57ec1579bc3e953 +https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py39hcf8a7be_2.conda#f7a209fe66831b3e3d216b90c2fc9d8a diff --git a/build_tools/azure/ubuntu_atlas_lock.txt b/build_tools/azure/ubuntu_atlas_lock.txt index 9f5973a1ccd53..e5233159eb8b6 100644 --- a/build_tools/azure/ubuntu_atlas_lock.txt +++ b/build_tools/azure/ubuntu_atlas_lock.txt @@ -8,7 +8,7 @@ attrs==22.2.0 # via pytest cython==0.29.33 # via -r build_tools/azure/ubuntu_atlas_requirements.txt -exceptiongroup==1.1.0 +exceptiongroup==1.1.1 # via pytest execnet==1.9.0 # via pytest-xdist @@ -22,12 +22,12 @@ pluggy==1.0.0 # via pytest py==1.11.0 # via pytest-forked -pytest==7.2.1 +pytest==7.2.2 # via # -r build_tools/azure/ubuntu_atlas_requirements.txt # pytest-forked # pytest-xdist -pytest-forked==1.4.0 +pytest-forked==1.6.0 # via pytest-xdist pytest-xdist==2.5.0 # via -r build_tools/azure/ubuntu_atlas_requirements.txt diff --git a/build_tools/circle/doc_environment.yml b/build_tools/circle/doc_environment.yml index ac12c221f317c..0c441a5266906 100644 --- a/build_tools/circle/doc_environment.yml +++ b/build_tools/circle/doc_environment.yml @@ -27,6 +27,5 @@ dependencies: - sphinx-prompt - plotly - pooch + - sphinxext-opengraph - pip - - pip: - - sphinxext-opengraph diff --git a/build_tools/circle/doc_linux-64_conda.lock b/build_tools/circle/doc_linux-64_conda.lock index 0ea1329d35098..74d96ab9de6bb 100644 --- a/build_tools/circle/doc_linux-64_conda.lock +++ b/build_tools/circle/doc_linux-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: ab71a4d47c35d849da7211030836aa7c50d7363575d5a9b000dff69b667208f0 +# input_hash: e94308f010347872a13f1dc0dcc6b19de98bc55b7a0f75b0102c299b78e8b31d @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080 @@ -36,11 +36,10 @@ https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.0.0-h166bdaf_1.tar.bz2#e https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-h27087fc_0.tar.bz2#c4fbad8d4bddeb3c085f18cbf97fbfad https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hf0379b8_106.conda#d7407e695358f068a2a7f8295cde0567 https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 -https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h36c2ea0_2.tar.bz2#626e68ae9cc5912d6adb79d318cf962d +https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h0b41bf4_3.conda#96f3b11872ef6fad973eac856cd2624f https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 https://conda.anaconda.org/conda-forge/linux-64/gstreamer-orc-0.4.33-h166bdaf_0.tar.bz2#879c93426c9d0b84a9de4513fbce5f4f https://conda.anaconda.org/conda-forge/linux-64/icu-70.1-h27087fc_0.tar.bz2#87473a15119779e021c314249d4b4aed -https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-h7f98852_2.tar.bz2#8e787b08fe19986d99d034b839df2961 https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2#a8832b479f93521a9e7b5b743803be51 @@ -52,39 +51,41 @@ https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.17-h0b41bf4_0.conda https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-h516909a_1.tar.bz2#6f8720dff19e17ce5d48cfe7f3d2f0a3 https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-h166bdaf_0.tar.bz2#b62b52da46c39ee2bc3c162ac7f1804d -https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.4-h166bdaf_0.tar.bz2#b4f717df2d377410b462328bf0e8fb7d +https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.5.1-h0b41bf4_0.conda#1edd9e67bdb90d78cea97733ff6b54e6 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2#39b1328babf85c7c3a61636d9cd50206 https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a6416_3.tar.bz2#8c5963a49b6035c40646a763293fbb35 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-11.3.0-h239ccf8_19.tar.bz2#d17fd55aed84ab6592c5419b6600501c https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libudev1-252-h166bdaf_0.tar.bz2#174243089ec111479298a5b7099b64b5 +https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_0.conda#6c2addbd9aa4ee47c76d50c9f0df8cd6 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 https://conda.anaconda.org/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2#c66fe2d123249af7651ebde8984c51c2 https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.2-hcb278e6_0.conda#08efb1e1813f1a151b7a945b972a049b https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.7-h0b41bf4_2.conda#45758f4ece9c8b7b5f99328bd5caae51 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 -https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.9-hbd366e4_2.tar.bz2#48018e187dacc6002d3ede9c824238ac +https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.10-h9fff704_0.conda#e6d228cd0bb74a51dd18f5bfce0b4115 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.38-h0b41bf4_0.conda#9ac34337e5101a87e5d91da05d84aa48 https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.0.10-h7f98852_0.tar.bz2#d6b0b50b49eccfe0be0373be628be0f3 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h7f98852_1002.tar.bz2#1e15f6ad85a7d743a2ac68dae6c82b98 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda#bce9f945da8ad2ae9b1d7165a64d0f87 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2#3ceea9668625c18f19530de98b15d5b0 https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.0-h27087fc_3.tar.bz2#0428af0510c3fafedf1c66b43102a34b https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.0.6-h166bdaf_0.tar.bz2#8650e4fb44c4a618e5ab3e1e19607e32 https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-11.3.0-hab1b70f_19.tar.bz2#89ac16d36e66ccb9ca5d34c9217e5799 -https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.21-h583fa2b_2.conda#7b36a10b58964d4444fcba44244710c5 +https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.22-h11f4161_0.conda#504fa9e712b99494a9cf4630e3ca7d78 https://conda.anaconda.org/conda-forge/linux-64/libavif-0.11.1-h5cdd6b5_0.tar.bz2#2040f9067e8852606208cafa66c3563f https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82 @@ -94,7 +95,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2. https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.10-h28343ad_4.tar.bz2#4a049fc560e00e43151dc51368915fdd https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.2-h27087fc_0.tar.bz2#7daf72d8e2a8e848e11d63ed6d1026e0 https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.46-h620e276_0.conda#27e745f6f2e4b757e95dd7225fbe6bdb -https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.51.0-hff17c54_0.conda#dd682f0b6d65e75b2bc868fc8e93d87e +https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.52.0-h61bc06f_0.conda#613955a50485812985c059e7b269f42e https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e1c890aebdebbfbf87e2c917187b4416 https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-hf14f497_3.tar.bz2#d85acad4b47dff4e3def14a769a97906 @@ -112,7 +113,7 @@ https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.3-hafa529b_0.conda#bcf0664a2dbbbb86cbd4c1e6ff10ddd6 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 -https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.6.1-hf91038e_0.conda#332b553e1a0d22c318756ffcd370384c +https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.7.1-hf91038e_0.conda#3a19cba20d395f47b60b13251eb4e267 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/gcc-11.3.0-h02d0930_11.tar.bz2#6037ebe5f1e3054519ce78b11eec9cd4 https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-11.3.0-he6f903b_11.tar.bz2#25f76cb82e483ce96d118b9edffd12c9 @@ -125,18 +126,17 @@ https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_0.conda#70cbb0c2033665f2a7339bf0ec51a67f https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-h6adf6a1_2.conda#2e648a34072eb39d7c4fc2a9981c5f0c -https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.0.3-he3ba5ed_0.tar.bz2#f9dbabc7e01c459ed7a1d1d64b206e9b +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea -https://conda.anaconda.org/conda-forge/linux-64/nss-3.82-he02c5a1_0.conda#f8d7f11d19e4cb2207eab159fd4c0152 -https://conda.anaconda.org/conda-forge/linux-64/python-3.9.15-hba424b6_0_cpython.conda#7b9485fce17fac2dd4aca6117a9936c2 +https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 +https://conda.anaconda.org/conda-forge/linux-64/python-3.9.16-h2782a2a_0_cpython.conda#95c9b7c96a7fd7342e0c9d0a917b8f78 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h166bdaf_0.tar.bz2#637054603bb7594302e3bf83f0a99879 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-h166bdaf_0.tar.bz2#732e22f1741bccea861f5668cf7342a7 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h166bdaf_0.tar.bz2#0a8e20a8aef954390b9481a527421a8c -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.7.2-h7f98852_0.tar.bz2#12a61e640b8894504326aadafccbb790 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.4-h0b41bf4_0.conda#ea8fbfeb976ac49cbeb594e985393514 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.13-pyhd8ed1ab_0.conda#06006184e203b61d3525f90de394471e -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_8.tar.bz2#2ff08978892a3e8b954397c461f18418 https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.5.2-h0b41bf4_0.conda#69afb4e35be6366c2c1f9ed7f49bc3e6 @@ -149,10 +149,10 @@ https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2 https://conda.anaconda.org/conda-forge/linux-64/cython-0.29.33-py39h227be39_0.conda#34bab6ef3e8cdf86fe78c46a984d3217 https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d https://conda.anaconda.org/conda-forge/linux-64/docutils-0.19-py39hf3d152e_1.tar.bz2#adb733ec2ee669f6d010758d054da60f -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d -https://conda.anaconda.org/conda-forge/noarch/fsspec-2023.1.0-pyhd8ed1ab_0.conda#44f6828b8f7cc3433d68d1d1c0e9add2 +https://conda.anaconda.org/conda-forge/noarch/fsspec-2023.3.0-pyhd8ed1ab_1.conda#0db48a2f5a68e28e5af8d3df276f2255 https://conda.anaconda.org/conda-forge/linux-64/gfortran-11.3.0-ha859ce3_11.tar.bz2#9a6a0c6fc4d192fddc7347a0ca31a329 https://conda.anaconda.org/conda-forge/linux-64/gfortran_linux-64-11.3.0-h3c55166_11.tar.bz2#f70b169eb69320d71f193758b7df67e8 https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.74.1-h6239696_1.tar.bz2#5f442e6bc9d89ba236eb25a25c5c2815 @@ -162,18 +162,18 @@ https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#3427 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py39hf939315_1.tar.bz2#41679a052a8ce841c74df1ebc802e411 -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.14-hfd0df8a_1.conda#c2566c2ea5f153ddd6bf4acaf7547d97 -https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_0.conda#dcfae510179c3de2e42b3a2276d059e0 +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d8aca0bc23ca73fa8caa3e7c84c28 +https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_1.conda#a3a0f7a6f0885f5e1e0ec691566afb77 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c9f4416a34bc91e0eb029f912c68f81f -https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.87.0-hdc1c0ab_0.conda#bc302fa1cf8eda15c60f669b7524a320 +https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.88.1-hdc1c0ab_0.conda#81eaeb3b35163c8e90e57532bc93754d https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_openblas.tar.bz2#823ceb5567e1a595deb643fcd17aed5a -https://conda.anaconda.org/conda-forge/linux-64/libpq-15.1-hb675445_3.conda#9873ab80ec8fab4a2c26c7580e0d7f58 +https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.2-py39h72bdee0_0.conda#35514f5320206df9f4661c138c02e1c1 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/noarch/networkx-3.0-pyhd8ed1ab_0.conda#88e40007414ea9a13f8df20fcffa87e2 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.1-py39h7360e5f_0.conda#fe323c95f3171bd137a7f10d261847a6 +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.2-py39h7360e5f_0.conda#757070dc7cc33003254888808cd34f1e https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9 @@ -185,29 +185,29 @@ https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.b https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7.1-pyhd8ed1ab_0.conda#f59d49a7b464901cf714b9e7984d01a2 https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0-py39hb9d737c_5.tar.bz2#ef9db3c38ae7275f6b14491cfe61a248 -https://conda.anaconda.org/conda-forge/noarch/setuptools-66.1.1-pyhd8ed1ab_0.conda#9467d520d1457018e055bbbfdf9b7567 +https://conda.anaconda.org/conda-forge/noarch/setuptools-67.6.0-pyhd8ed1ab_0.conda#e18ed61c37145bb9b48d1d98801960f7 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.4-pyhd8ed1ab_0.conda#5a31a7d564f551d0e6dff52fd8cb5b16 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.2-py_0.tar.bz2#68e01cac9d38d0e717cd5c87bc3d2cc9 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd8ed1ab_0.tar.bz2#77dad82eb9c8c1525ff7953e0756d708 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.1-pyhd8ed1ab_0.conda#6c8c4d6eb2325e59290ac6dbbeacd5f0 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-py_0.tar.bz2#67cd9d9c0382d37479b4d306c369a2d4 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.3-py_0.tar.bz2#d01180388e6d1838c3e1ad029590aa7a https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd8ed1ab_2.tar.bz2#9ff55a0901cf952f05c654394de76bf7 -https://conda.anaconda.org/conda-forge/noarch/tenacity-8.1.0-pyhd8ed1ab_0.tar.bz2#97e6f26dd5b93c9f5e6142e16ee3af62 +https://conda.anaconda.org/conda-forge/noarch/tenacity-8.2.2-pyhd8ed1ab_0.conda#7b39e842b52966a99e229739cd4dc36e https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36 https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py39hb9d737c_1.tar.bz2#8a7d309b08cff6386fe384aa10dd3748 -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.4.0-pyha770c72_0.tar.bz2#2d93b130d148d7fc77e583677792fc6a +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.0.0-py39hb9d737c_0.tar.bz2#230d65004135bf312504a1bbcb0c7a08 https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h166bdaf_0.tar.bz2#c9b568bd804cb2903c6be6f5f68182e4 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h7f98852_1.tar.bz2#536cc5db4d0a3ba0630541aec064b5e4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb -https://conda.anaconda.org/conda-forge/noarch/zipp-3.12.0-pyhd8ed1ab_0.conda#edc3568566cc48335f0b5d86d40fdbb9 -https://conda.anaconda.org/conda-forge/noarch/babel-2.11.0-pyhd8ed1ab_0.tar.bz2#2ea70fde8d581ba9425a761609eed6ba +https://conda.anaconda.org/conda-forge/noarch/zipp-3.15.0-pyhd8ed1ab_0.conda#13018819ca8f5b7cc675a8faf1f5fedf +https://conda.anaconda.org/conda-forge/noarch/babel-2.12.1-pyhd8ed1ab_1.conda#ac432e732804a81ddcf29c92ead57cde https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-16_linux64_openblas.tar.bz2#519562d6176dab9c2ab9a8336a14c8e7 https://conda.anaconda.org/conda-forge/linux-64/brunsli-0.1-h9c3ff4c_0.tar.bz2#c1ac6229d0bfd14f8354ff9ad2a26cad https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 @@ -216,56 +216,60 @@ https://conda.anaconda.org/conda-forge/linux-64/cfitsio-4.2.0-hd9d235c_0.conda#8 https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.7-py39h4b4f3f3_0.conda#c5387f3fb1f5b8b71e1c865fc55f4951 https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.5.2-hf52228f_0.conda#6b3b19e359824b97df7145c8c878c8be https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.0-py39hb9d737c_1.tar.bz2#eb31327ace8dac15c2df243d9505a132 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.38.0-py39hb9d737c_1.tar.bz2#3f2d104f2fefdd5e8a205dd3aacbf1d7 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py39h72bdee0_0.conda#7ed17a60087175112fbbf5882bebddc2 https://conda.anaconda.org/conda-forge/linux-64/fortran-compiler-1.5.2-hdb1a99f_0.conda#265323e1bd53709aeb739c9b1794b398 https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.1-h6239696_1.tar.bz2#f3220a9e9d3abcbfca43419a219df7e4 https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.0.0-pyha770c72_0.conda#691644becbcdca9f73243450b1c63e62 +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37 https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_0.conda#189f7f97245f594b7a9d8e2b9f311cf8 +https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d https://conda.anaconda.org/conda-forge/noarch/memory_profiler-0.61.0-pyhd8ed1ab_0.tar.bz2#8b45f9f2b2f7a98b0ec179c8991a4a9b https://conda.anaconda.org/conda-forge/noarch/partd-1.3.0-pyhd8ed1ab_0.tar.bz2#af8c82d121e63082926062d61d9abb54 -https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py39ha08a7e4_0.conda#d62ba9d1a981544c809813afaf0be5c0 -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d -https://conda.anaconda.org/conda-forge/noarch/plotly-5.13.0-pyhd8ed1ab_0.conda#27c003c456599f43bac3752a88b4db28 +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py39h7207d5c_2.conda#58d50d33cf1abe2055d2a1c90c7179a5 +https://conda.anaconda.org/conda-forge/noarch/pip-23.0.1-pyhd8ed1ab_0.conda#8025ca83b8ba5430b640b83917c2a6f7 +https://conda.anaconda.org/conda-forge/noarch/plotly-5.13.1-pyhd8ed1ab_0.conda#761501a3de96c5855d840f4287a65e77 https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-ha8d29e2_1.conda#dbfc2a8d63a43a11acf4c704e1ef9d0c https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1 -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.4.1-py39h389d5f1_0.conda#9eeb2b2549f836ca196c6cbd22344122 -https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.6-py39h227be39_0.conda#0ab8c402dbae25ae20a7688013b0f8ea +https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.7-py39h227be39_0.conda#7d9a35091552af3655151f164ddd64a3 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-openblas.tar.bz2#02f34bcf0aceb6fae4c4d1ecb71c852a https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py39hb9d737c_1005.tar.bz2#a639fdd9428d8b25f8326a3838d54045 https://conda.anaconda.org/conda-forge/linux-64/compilers-1.5.2-ha770c72_0.conda#f95226244ee1c487cf53272f971323f4 -https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.0-py39h079d5ae_0.conda#70ac60b214a8df9b9ce63e05af7d0976 -https://conda.anaconda.org/conda-forge/noarch/dask-core-2023.1.1-pyhd8ed1ab_0.conda#025c84e82996ab0a01c0af0069399192 -https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.21.3-h25f0c4b_1.conda#0c8a8f15aa319c91d9010072278feddd +https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.2-py39h079d5ae_0.conda#c492b565817a019f025c7d17b57ef479 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2023.3.1-pyhd8ed1ab_0.conda#0a3abdbff6e296d056ce01ee3529638d +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.22.0-h25f0c4b_2.conda#461541cb1b387c2a28ab6217f3d38502 https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-6.0.0-h8e241bc_0.conda#448fe40d2fed88ccf4d9ded37cbb2b38 -https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2023.1.23-py39hd061359_0.conda#9f923217bbae164509b875ded0426559 -https://conda.anaconda.org/conda-forge/noarch/imageio-2.25.0-pyh24c5eb1_0.conda#76d0f424ca72cd598b4fa421e7ac46c2 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.6.3-py39he190548_0.conda#5ade95e6e99425e3e5916019dcd01e55 +https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2023.1.23-py39hbb14963_1.conda#9f9f388e0c28900e360f1a1deb97e000 +https://conda.anaconda.org/conda-forge/noarch/imageio-2.26.0-pyh24c5eb1_0.conda#7158487eb6dbc42fbb5d20f0c5796c48 +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-5.12.0-pyhd8ed1ab_0.conda#3544c818f0720c89eb16ae6940ab440b https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.3-py39h2ad29b5_0.conda#3ea96adbbc2a66fa45178102a9cfbecc +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py39h227be39_3.conda#9e381db00691e26bcf670c3586397be1 -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf -https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.21.3-h4243ec0_1.conda#905563d166c13ba299e39d6c9fcebd1c +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0_2.conda#0d0c6604c8ac4ad5e51efa7bb58da05c +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py39he190548_0.conda#f2a931db797bb58bd335f4a857b4c898 https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e -https://conda.anaconda.org/conda-forge/noarch/tifffile-2023.1.23.1-pyhd8ed1ab_0.conda#5288e510d61d156d6cede1a604eb2a28 -https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.6-h602db52_6.conda#050ed331c6b32c82b845907fd3494d3a -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.14-pyhd8ed1ab_0.conda#01f33ad2e0aaf6b5ba4add50dad5ad29 +https://conda.anaconda.org/conda-forge/noarch/tifffile-2023.2.28-pyhd8ed1ab_0.conda#6ed72880d5af877a3c8252bb52d355ae +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h67dfc38_7.conda#f140acdc15a0196eef664f120c396266 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py39h5c7b992_3.conda#19e30314fe824605750da905febb8ee6 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.6.3-py39hf3d152e_0.conda#dbef5ffeeca5c5112cc3be8f03e6d1a5 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py39hf3d152e_0.conda#682772fa385911fb5efffbce21b269c5 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e https://conda.anaconda.org/conda-forge/noarch/sphinx-6.0.0-pyhd8ed1ab_2.conda#ac1d3b55da1669ee3a56973054fd7efb https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.5.0-pyhd8ed1ab_0.tar.bz2#3c275d7168a6a135329f4acb364c229a -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.0-py39h7360e5f_0.conda#d6d4f8195ec2c846deebe71306f60298 -https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.11.1-pyhd8ed1ab_0.tar.bz2#729254314a5d178eefca50acbc2687b8 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py39h7360e5f_0.conda#7584d1bc5499d25eccfd24a7f656e3ee +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.12.2-pyhd8ed1ab_0.conda#cb7e912f6f31de2d45984fa40a4fe78c https://conda.anaconda.org/conda-forge/noarch/sphinx-prompt-1.4.0-pyhd8ed1ab_0.tar.bz2#88ee91e8679603f2a5bd036d52919cc2 +https://conda.anaconda.org/conda-forge/noarch/sphinxext-opengraph-0.8.1-pyhd8ed1ab_0.conda#8f0192db5ac024dcf320532c883fdf67 https://conda.anaconda.org/conda-forge/noarch/patsy-0.5.3-pyhd8ed1ab_0.tar.bz2#50ef6b29b1fb0768ca82c5aeb4fb2d96 -https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py39h7c9e3ff_2.tar.bz2#d2f1c4eed5ed41fb1bf3e905ccac0eb8 +https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py39h0354152_2.conda#3b7a5ecba69a8e7d5a74b5ef00ea8f7e https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.19.3-py39h4661b88_2.tar.bz2#a8d53b12aedcd84107ba8c85c81be56f https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.12.2-pyhd8ed1ab_0.conda#cf88f3a1c11536bc3c10c14ad00ccc42 https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.13.5-py39h2ae25f5_2.tar.bz2#598b14b778a8f3e06a3579649f0e3c00 https://conda.anaconda.org/conda-forge/noarch/seaborn-0.12.2-hd8ed1ab_0.conda#50847a47c07812f88581081c620f5160 -# pip sphinxext-opengraph @ https://files.pythonhosted.org/packages/f2/eb/9ac8de50b67ca607f31c95facfdc499b8ce5a3c696f6691b6a9213d84f23/sphinxext_opengraph-0.7.5-py3-none-any.whl#sha256=d7fcf48b5d6477292492c0c7da6ddc469e3657159952e2a0a0df074f54aad99e diff --git a/build_tools/circle/doc_min_dependencies_linux-64_conda.lock b/build_tools/circle/doc_min_dependencies_linux-64_conda.lock index 8333762deaeb2..1919d8f3497b5 100644 --- a/build_tools/circle/doc_min_dependencies_linux-64_conda.lock +++ b/build_tools/circle/doc_min_dependencies_linux-64_conda.lock @@ -23,19 +23,18 @@ https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-h27087fc_0.tar.bz2#c https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-7.5.0-habd7529_20.tar.bz2#42140612518a7ce78f571d64b6a50ba3 https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 https://conda.anaconda.org/conda-forge/linux-64/icu-64.2-he1b5a44_1.tar.bz2#8e881214a23508f1541eb7a3135d6fcb -https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 +https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h0b41bf4_3.conda#c7a069243e1fbe9a556ed2ec030e6407 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.17-h0b41bf4_0.conda#5cc781fd91968b11a8a7fdbee0982676 https://conda.anaconda.org/conda-forge/linux-64/libffi-3.2.1-he1b5a44_1007.tar.bz2#11389072d7d6036fd811c3d9460475cd https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-h166bdaf_0.tar.bz2#b62b52da46c39ee2bc3c162ac7f1804d -https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.4-h166bdaf_0.tar.bz2#b4f717df2d377410b462328bf0e8fb7d https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-0.10.0-he1b5a44_0.tar.bz2#78ccac2098edcd3673af2ceb3e95f932 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-1.1.1s-h0b41bf4_1.conda#c5405eccf20334e57a80c1c3a9e68266 +https://conda.anaconda.org/conda-forge/linux-64/openssl-1.1.1t-h0b41bf4_0.conda#a35dc66c4cee8c4399507d14cf1501b1 https://conda.anaconda.org/conda-forge/linux-64/pcre-8.45-h9c3ff4c_0.tar.bz2#c05d1820a6d34ff07aaaab7a9b7eddaa https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 @@ -53,7 +52,7 @@ https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.co https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.1.1-h516909a_0.tar.bz2#d98aa4948ec35f52907e2d6152e2b255 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/gfortran_linux-64-7.5.0-h78c8a43_33.tar.bz2#b2879010fb369f4012040f7a27657cd8 @@ -63,30 +62,29 @@ https://conda.anaconda.org/conda-forge/linux-64/libglib-2.66.3-hbe7bbb4_0.tar.bz https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-h6adf6a1_2.conda#2e648a34072eb39d7c4fc2a9981c5f0c https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.9.10-hee79883_0.tar.bz2#0217b0926808b1adf93247bba489d733 https://conda.anaconda.org/conda-forge/linux-64/mkl-2020.4-h726a3e6_304.tar.bz2#b9b35a50e5377b19da6ec0709ae77fc3 -https://conda.anaconda.org/conda-forge/linux-64/nss-3.82-he02c5a1_0.conda#f8d7f11d19e4cb2207eab159fd4c0152 +https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.40.0-h4ff8645_0.tar.bz2#bb11803129cbbb53ed56f9506ff74145 https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.1.1-hc9558a2_0.tar.bz2#1eb7c67eb11eab0c98a87f84174fdde1 -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.1-hc2a2eb6_0.tar.bz2#78415f0180a8d9c5bcc47889e00d5fb1 +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d https://conda.anaconda.org/conda-forge/linux-64/fortran-compiler-1.1.1-he991be0_0.tar.bz2#e38ac82cc517b9e245c1ae99f9f140da -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.14-hfd0df8a_1.conda#c2566c2ea5f153ddd6bf4acaf7547d97 +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-hfd0df8a_0.conda#aa8840cdf17ef0c6084d1e24abc7a28b https://conda.anaconda.org/conda-forge/linux-64/libblas-3.8.0-20_mkl.tar.bz2#8fbce60932c01d0e193a1a814f2002be https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea https://conda.anaconda.org/conda-forge/linux-64/python-3.8.6-h852b56e_0_cpython.tar.bz2#dd65401dfb61ac030edc0dc4d15c2c51 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.13-pyhd8ed1ab_0.conda#06006184e203b61d3525f90de394471e -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1ab_0.tar.bz2#c1d5b294fbf9a795dec349a6f4d8be8e https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf -https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.0-pyhd8ed1ab_0.tar.bz2#a6cf47b09786423200d7982d1faa19eb +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 https://conda.anaconda.org/conda-forge/linux-64/compilers-1.1.1-0.tar.bz2#1ba267e19dbaf3db9dd0404e6fb9cdb9 https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb https://conda.anaconda.org/conda-forge/linux-64/cython-0.29.33-py38h8dc9893_0.conda#5d50cd654981f0ccc7c878ac297afaa7 https://conda.anaconda.org/conda-forge/linux-64/docutils-0.17.1-py38h578d9bd_3.tar.bz2#34e1f12e3ed15aff218644e9d865b722 -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2022.11.0-pyhd8ed1ab_0.tar.bz2#eb919f2119a6db5d0192f9e9c3711572 +https://conda.anaconda.org/conda-forge/noarch/fsspec-2023.3.0-pyhd8ed1ab_1.conda#0db48a2f5a68e28e5af8d3df276f2255 https://conda.anaconda.org/conda-forge/linux-64/glib-2.66.3-h58526e2_0.tar.bz2#62c2e5c84f6cdc7ded2307ef9c30dc8c https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 @@ -98,32 +96,32 @@ https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2# https://conda.anaconda.org/conda-forge/linux-64/markupsafe-1.1.1-py38h0a891b7_4.tar.bz2#d182e0c60439427453ed4a7abd28ef0d https://conda.anaconda.org/conda-forge/noarch/networkx-3.0-pyhd8ed1ab_0.conda#88e40007414ea9a13f8df20fcffa87e2 https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b -https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py38hb32c036_0.conda#a288a6e69efc2f20c30ebfa590e11bed +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py38hde6dc18_1.conda#3de5619d3f556f966189e5251a266125 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9 https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.4-py38h0a891b7_0.tar.bz2#fe2ef279417faa1af0adf178de2032f7 https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7-pyhd8ed1ab_0.conda#c8d7e34ca76d6ecc03b84bedfd99d689 +https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7.1-pyhd8ed1ab_0.conda#f59d49a7b464901cf714b9e7984d01a2 https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0-py38h0a891b7_5.tar.bz2#0856c59f9ddb710c640dc0428d66b1b7 https://conda.anaconda.org/conda-forge/linux-64/setuptools-59.8.0-py38h578d9bd_1.tar.bz2#da023e4a9c777abc28434d7a6473dcc2 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.2-py_0.tar.bz2#20b2eaeaeea4ef9a9a0d99770620fd09 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.4-pyhd8ed1ab_0.conda#5a31a7d564f551d0e6dff52fd8cb5b16 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.2-py_0.tar.bz2#68e01cac9d38d0e717cd5c87bc3d2cc9 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd8ed1ab_0.tar.bz2#77dad82eb9c8c1525ff7953e0756d708 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.1-pyhd8ed1ab_0.conda#6c8c4d6eb2325e59290ac6dbbeacd5f0 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-py_0.tar.bz2#67cd9d9c0382d37479b4d306c369a2d4 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.3-py_0.tar.bz2#d01180388e6d1838c3e1ad029590aa7a https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd8ed1ab_2.tar.bz2#9ff55a0901cf952f05c654394de76bf7 -https://conda.anaconda.org/conda-forge/noarch/tenacity-8.1.0-pyhd8ed1ab_0.tar.bz2#97e6f26dd5b93c9f5e6142e16ee3af62 +https://conda.anaconda.org/conda-forge/noarch/tenacity-8.2.2-pyhd8ed1ab_0.conda#7b39e842b52966a99e229739cd4dc36e https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36 https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py38h0a891b7_1.tar.bz2#358beb228a53b5e1031862de3525d1d3 -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.4.0-pyha770c72_0.tar.bz2#2d93b130d148d7fc77e583677792fc6a +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 -https://conda.anaconda.org/conda-forge/noarch/babel-2.11.0-pyhd8ed1ab_0.tar.bz2#2ea70fde8d581ba9425a761609eed6ba +https://conda.anaconda.org/conda-forge/noarch/babel-2.12.1-pyhd8ed1ab_1.conda#ac432e732804a81ddcf29c92ead57cde https://conda.anaconda.org/conda-forge/linux-64/cffi-1.14.4-py38ha312104_0.tar.bz2#8f82b87522fbb1d4b24e8b5e2b1d0501 https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.0-py38h0a891b7_1.tar.bz2#183f6160ab3498b882e903b06be7d430 https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-hfdff14a_1.tar.bz2#4caaca6356992ee545080c7d7193b5a3 @@ -134,20 +132,22 @@ https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.8.0-20_mkl.tar.bz2# https://conda.anaconda.org/conda-forge/noarch/memory_profiler-0.61.0-pyhd8ed1ab_0.tar.bz2#8b45f9f2b2f7a98b0ec179c8991a4a9b https://conda.anaconda.org/conda-forge/linux-64/numpy-1.17.3-py38h95a1406_0.tar.bz2#bc0cbf611fe2f86eab29b98e51404f5e https://conda.anaconda.org/conda-forge/noarch/partd-1.3.0-pyhd8ed1ab_0.tar.bz2#af8c82d121e63082926062d61d9abb54 -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d +https://conda.anaconda.org/conda-forge/noarch/pip-23.0.1-pyhd8ed1ab_0.conda#8025ca83b8ba5430b640b83917c2a6f7 https://conda.anaconda.org/conda-forge/noarch/plotly-5.10.0-pyhd8ed1ab_0.tar.bz2#e95502aa0f8e3db05d198214472575de https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1 -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/linux-64/blas-2.20-mkl.tar.bz2#e7d09a07f5413e53dca5282b8fa50bed https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py38h0a891b7_1005.tar.bz2#e99e08812dfff30fdd17b3f8838e2759 https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.0-py38h1724139_0.conda#24e75282e857cb0641c4f1b82cf6d6ea -https://conda.anaconda.org/conda-forge/noarch/dask-core-2023.1.0-pyhd8ed1ab_0.conda#c0ed29fe7454e551b7328024af21426f +https://conda.anaconda.org/conda-forge/noarch/dask-core-2023.3.1-pyhd8ed1ab_0.conda#0a3abdbff6e296d056ce01ee3529638d https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.14.5-h0935bb2_2.tar.bz2#eb125ee86480e00a4a1ed45a577c3311 -https://conda.anaconda.org/conda-forge/noarch/imageio-2.24.0-pyh24c5eb1_0.conda#e8a7ffa70678faf378356ed2719120e9 +https://conda.anaconda.org/conda-forge/noarch/imageio-2.26.0-pyh24c5eb1_0.conda#7158487eb6dbc42fbb5d20f0c5796c48 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.1.3-py38h250f245_0.tar.bz2#eb182969d8ed019d4de6939f393270d2 https://conda.anaconda.org/conda-forge/linux-64/pandas-1.0.5-py38hcb8c335_0.tar.bz2#1e1b4382170fd26cf722ef008ffb651e -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.1.1-py38h5c078b8_3.tar.bz2#dafeef887e68bd18ec84681747ca0fd5 https://conda.anaconda.org/conda-forge/linux-64/scipy-1.3.2-py38h921218d_0.tar.bz2#278670dc2fef5a6309d1635f047bd456 https://conda.anaconda.org/conda-forge/noarch/patsy-0.5.3-pyhd8ed1ab_0.tar.bz2#50ef6b29b1fb0768ca82c5aeb4fb2d96 @@ -159,11 +159,11 @@ https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.16.2-py38hb3f55d8 https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.12.2-pyhd8ed1ab_0.conda#cf88f3a1c11536bc3c10c14ad00ccc42 https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.12.3-py38ha8c2ead_3.tar.bz2#242c206b0c30fdc4c18aea16f04c4262 https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.12.2-py38h5c078b8_0.tar.bz2#33787719ad03d33cffc4e2e3ea82bc9e -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.14-pyhd8ed1ab_0.conda#01f33ad2e0aaf6b5ba4add50dad5ad29 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.1.3-py38_0.tar.bz2#1992ab91bbff86ded8d99d1f488d8e8b -https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/noarch/seaborn-0.12.2-hd8ed1ab_0.conda#50847a47c07812f88581081c620f5160 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e https://conda.anaconda.org/conda-forge/noarch/sphinx-4.0.1-pyh6c4a22f_2.tar.bz2#c203dcc46f262853ecbb9552c50d664e https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.2-pyhd8ed1ab_0.tar.bz2#025ad7ca2c7f65007ab6b6f5d93a56eb https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.7.0-py_0.tar.bz2#80bad3f857ecc86a4ab73f3e57addd13 diff --git a/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock b/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock index b502362381f0e..963e1204e44a3 100644 --- a/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock +++ b/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock @@ -3,7 +3,7 @@ # input_hash: 8cbd4b39fff3a0b91b6adc652e12de7b27aa74abb8b90e9d9aa0fc141dd28d84 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-aarch64/ca-certificates-2022.12.7-h4fd8a4c_0.conda#2450fbcaf65634e0d071e47e2b8487b4 -https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.39-h16cd69b_1.conda#9daf385ebefaea92087d3a315e398964 +https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.40-h2d8c526_0.conda#16246d69e945d0b1969a6099e7c5d457 https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-12.2.0-hf695500_19.tar.bz2#bc890809e1f807b51bf04dfbee70ddf5 https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-ng-12.2.0-hc13a102_19.tar.bz2#981741cd4321edd5c504b48f74fe91f2 https://conda.anaconda.org/conda-forge/linux-aarch64/python_abi-3.9-3_cp39.conda#b6f330b045cf3425945d536a6b5cd240 @@ -12,20 +12,19 @@ https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-ng-12.2.0-he943 https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2#98a1185182fec3c434069fa74e6473d6 https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-12.2.0-h607ecd0_19.tar.bz2#8456a29b6d9fc3123ccb9a966b6b2c49 https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-hf897c2e_4.tar.bz2#2d787570a729e273a4e75775ddf3348a -https://conda.anaconda.org/conda-forge/linux-aarch64/jpeg-9e-h9cdd2b7_2.tar.bz2#8fd15daa7515a0fea9b3b68495118238 https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.0.0-h4de3ea5_0.tar.bz2#1a0ffc65e03ce81559dbcb0695ad1476 https://conda.anaconda.org/conda-forge/linux-aarch64/libbrotlicommon-1.0.9-h4e544f5_8.tar.bz2#3cedc3935cfaa2a5303daa25fb12cb1d https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.17-hb4cce97_0.conda#0a26f36963967687f4cab7c4a017a189 https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.4.2-h3557bc0_5.tar.bz2#dddd85f4d52121fab0a8b099c5e06501 https://conda.anaconda.org/conda-forge/linux-aarch64/libhiredis-1.0.2-h05efe27_0.tar.bz2#a87f068744fd20334cd41489eb163bee -https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-2.1.4-h4e544f5_0.tar.bz2#04a9a55dd9c81b15378fc96753c11be9 +https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-2.1.5.1-hb4cce97_0.conda#89a30f83837239a008593afb78d210f2 https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.0-hf897c2e_0.tar.bz2#36fdbc05c9d9145ece86f5a63c3f352e https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.21-pthreads_h6cb6f83_3.tar.bz2#bc66302748a788c3bce59999ed6d737d https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.32.1-hf897c2e_1000.tar.bz2#e038da5ef9095b0d79aac14a311394e7 -https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.2.4-h4e544f5_0.tar.bz2#9c307c3dba834b9529f6dcd95db543ed +https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.3.0-hb4cce97_0.conda#53670eaee6d77d9fe60a84f7fd226a4c https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.2.13-h4e544f5_4.tar.bz2#88596b6277fe6d39f046983aae6044db https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.3-headf329_1.tar.bz2#486b68148e121bc8bbadc3cefae4c04f -https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.0.7-hb4cce97_1.conda#04ef6664eed137b63ebf19ac7fbb59ca +https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.0.8-hb4cce97_0.conda#268fe30a14a3f40fe54da04fc053fd2d https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-hb9de7d4_1001.tar.bz2#d0183ec6ce0b5aaa3486df25fa5f0ded https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.9-h3557bc0_0.tar.bz2#e0c187f5ce240897762bbb89a8a407cc https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.3-h3557bc0_0.tar.bz2#a6c9016ae1ca5c47a3603ed4cd65fedd @@ -40,15 +39,14 @@ https://conda.anaconda.org/conda-forge/linux-aarch64/llvm-openmp-15.0.7-hb3b5123 https://conda.anaconda.org/conda-forge/linux-aarch64/openblas-0.3.21-pthreads_h2d9dd7e_3.tar.bz2#17a824cf9bbf0e31998d2c1a2140204c https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.1.2-h38e3740_0.tar.bz2#3cdbfb7d7b63ae2c2d35bb167d257ecd https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.12-hd8af866_0.tar.bz2#7894e82ff743bd96c76585ddebe28e2a -https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.2-hc1e27d5_4.tar.bz2#f5627b0fef9a5267fd4d2ad5d8b5c1b3 +https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.2-h44f6412_6.conda#6d0d1cd6d184129eabb96bb220afb5b2 https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-bin-1.0.9-h4e544f5_8.tar.bz2#0980429a0148a53edd0f1f207ec28a39 https://conda.anaconda.org/conda-forge/linux-aarch64/ccache-4.7.3-hb064cd7_0.tar.bz2#8e71c7d1731d80d773cdafaa2ddcde50 https://conda.anaconda.org/conda-forge/linux-aarch64/freetype-2.12.1-hbbbf32d_1.conda#e0891290982420d67651589c8584eec3 https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.9.0-16_linuxaarch64_openblas.tar.bz2#520a3ecbebc63239c27dd6f70c2ababe https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.9.0-16_linuxaarch64_openblas.tar.bz2#62990b2d1efc22d0beb394e893d39541 -https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.5.0-h4c1066a_2.conda#45b240c8ce410ecc8f82cd085279dce9 -https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.9.15-hcd6f746_0_cpython.conda#4f20c6aad727bf0e2c9bb13a82f9a5fd -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b +https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.5.0-h540f74b_5.conda#761deeaa1ea335cdbd65e1ef4b4e4deb +https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.9.16-hb363c5e_0_cpython.conda#0a7ef29549eaef817898062eeeefebd3 https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-1.0.9-h4e544f5_8.tar.bz2#259d82bd990ba225508389509634b157 https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6 @@ -56,15 +54,15 @@ https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1a https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb https://conda.anaconda.org/conda-forge/linux-aarch64/cython-0.29.33-py39hdcdd789_0.conda#7a94705550f5c09d4a3b069f0488caed -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.0-pyhd8ed1ab_0.conda#a385c3e8968b4cf8fbc426ace915fd1a +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.1.1-pyhd8ed1ab_0.conda#7312299d7a0ea4993159229b7d2dceb2 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/linux-aarch64/kiwisolver-1.4.4-py39h110580c_1.tar.bz2#9c045502f6ab8c89bfda6be3c389e503 -https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.14-h7576be9_1.conda#33f4117db8c2b9ff0888cedd74b2f8e9 +https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.15-h3e0bdec_1.conda#5d6c6a9042e2316cec7410dd085814d1 https://conda.anaconda.org/conda-forge/linux-aarch64/liblapacke-3.9.0-16_linuxaarch64_openblas.tar.bz2#97743bccc8b7edec0b9a726a8b80ecdf https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-1.24.1-py39hc9a35f1_0.conda#cb6ed5a4bc0972f3d27016f5ce2754d4 +https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-1.24.2-py39hafab3e7_0.conda#e8d27fa9b6e02d6fba071d9c555d7962 https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.0-h9508984_2.conda#3d56d402a845c243f8c2dd3c8e836029 https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9 @@ -72,31 +70,37 @@ https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b46 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a +https://conda.anaconda.org/conda-forge/noarch/setuptools-67.6.0-pyhd8ed1ab_0.conda#e18ed61c37145bb9b48d1d98801960f7 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/linux-aarch64/tornado-6.2-py39hb9a1dbb_1.tar.bz2#f5f4671e5e76b582263699cb4ab3172c +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/linux-aarch64/unicodedata2-15.0.0-py39h0fd3b05_0.tar.bz2#835f1a9631e600e0176593e95e85f73f https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.15.0-pyhd8ed1ab_0.conda#13018819ca8f5b7cc675a8faf1f5fedf https://conda.anaconda.org/conda-forge/linux-aarch64/blas-devel-3.9.0-16_linuxaarch64_openblas.tar.bz2#5e5a376c40e95ab4b99519dfe6dc8912 https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-1.15.1-py39hb26bf21_3.conda#dee0362c4fde8edce396183fd6390d6e https://conda.anaconda.org/conda-forge/linux-aarch64/contourpy-1.0.7-py39hd9a2fea_0.conda#efa783bf5c2b30aba3cf22599fe0274e -https://conda.anaconda.org/conda-forge/linux-aarch64/fonttools-4.38.0-py39h0fd3b05_1.tar.bz2#c4eda904dc52f53c948d64d20662525f +https://conda.anaconda.org/conda-forge/linux-aarch64/fonttools-4.39.0-py39h24fc6b6_0.conda#7d2ae43219725cd4eb35a501e46370e7 +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-9.4.0-py39h32ea969_0.conda#af264aff235dba6dc88f6af322ad6835 -https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d -https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.1-pyhd8ed1ab_0.conda#f0be05afc9c9ab45e273c088e00c258b +https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-9.4.0-py39h3f802df_2.conda#b3a6f14743d98bde497be57b54c21cce +https://conda.anaconda.org/conda-forge/noarch/pip-23.0.1-pyhd8ed1ab_0.conda#8025ca83b8ba5430b640b83917c2a6f7 +https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/linux-aarch64/blas-2.116-openblas.tar.bz2#ded0db9695cd575ec1c68a68873363c5 https://conda.anaconda.org/conda-forge/linux-aarch64/brotlipy-0.7.0-py39h0fd3b05_1005.tar.bz2#5d37ef329c084829d3ff5b172a08b8f9 -https://conda.anaconda.org/conda-forge/linux-aarch64/cryptography-39.0.0-py39h8a84b6a_0.conda#dbf0c4fe3e4cd291219b108e8d3deab6 -https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-base-3.6.2-py39h15a8d8b_0.tar.bz2#b6d1b0f734ac62c1d737a9f297aef8de -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_1.tar.bz2#60958bab291681d9c3ba69e80f1434cf -https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-3.6.2-py39ha65689a_0.tar.bz2#b4d712f422b5dad5259f38151be6f492 +https://conda.anaconda.org/conda-forge/linux-aarch64/cryptography-39.0.2-py39h8a84b6a_0.conda#1430428b279f5bacdaa4357d88145434 +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-5.12.0-pyhd8ed1ab_0.conda#3544c818f0720c89eb16ae6940ab440b +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-base-3.7.1-py39h2983639_0.conda#6ca14f00270585ac4ff20b04106817ee https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.14-pyhd8ed1ab_0.conda#01f33ad2e0aaf6b5ba4add50dad5ad29 -https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 -https://conda.anaconda.org/conda-forge/linux-aarch64/scipy-1.10.0-py39hafab3e7_0.conda#65d57c881ae668b5372bb6ad5e08bb78 +https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-3.7.1-py39ha65689a_0.conda#ba11d081599ada176b3ca99821e1b753 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/linux-aarch64/scipy-1.10.1-py39hafab3e7_0.conda#d5364063c02425a7faa8aca680bdf146 diff --git a/build_tools/update_environments_and_lock_files.py b/build_tools/update_environments_and_lock_files.py index 8e2bc193c92f3..2c06a298d6e92 100644 --- a/build_tools/update_environments_and_lock_files.py +++ b/build_tools/update_environments_and_lock_files.py @@ -301,8 +301,9 @@ def remove_from(alist, to_remove): "sphinx-prompt", "plotly", "pooch", + "sphinxext-opengraph", + "pip", ], - "pip_dependencies": ["sphinxext-opengraph"], "package_constraints": { "python": "3.9", # XXX: sphinx > 6.0 does not correctly generate searchindex.js diff --git a/examples/calibration/plot_calibration_curve.py b/examples/calibration/plot_calibration_curve.py index 3ba7c2c6404c7..5f8ad621bc7a8 100644 --- a/examples/calibration/plot_calibration_curve.py +++ b/examples/calibration/plot_calibration_curve.py @@ -78,7 +78,7 @@ # %% fig = plt.figure(figsize=(10, 10)) gs = GridSpec(4, 2) -colors = plt.cm.get_cmap("Dark2") +colors = plt.get_cmap("Dark2") ax_calibration_curve = fig.add_subplot(gs[:2, :2]) calibration_displays = {} diff --git a/examples/calibration/plot_compare_calibration.py b/examples/calibration/plot_compare_calibration.py index 026737ee0e455..cd4782122a07b 100644 --- a/examples/calibration/plot_compare_calibration.py +++ b/examples/calibration/plot_compare_calibration.py @@ -109,7 +109,7 @@ def predict_proba(self, X): fig = plt.figure(figsize=(10, 10)) gs = GridSpec(4, 2) -colors = plt.cm.get_cmap("Dark2") +colors = plt.get_cmap("Dark2") ax_calibration_curve = fig.add_subplot(gs[:2, :2]) calibration_displays = {} diff --git a/examples/svm/plot_svm_margin.py b/examples/svm/plot_svm_margin.py index 9f52881f1faf2..43cef2544721c 100644 --- a/examples/svm/plot_svm_margin.py +++ b/examples/svm/plot_svm_margin.py @@ -20,7 +20,6 @@ import numpy as np import matplotlib.pyplot as plt -from matplotlib import cm from sklearn import svm # we create 40 separable points @@ -65,10 +64,10 @@ facecolors="none", zorder=10, edgecolors="k", - cmap=cm.get_cmap("RdBu"), + cmap=plt.get_cmap("RdBu"), ) plt.scatter( - X[:, 0], X[:, 1], c=Y, zorder=10, cmap=cm.get_cmap("RdBu"), edgecolors="k" + X[:, 0], X[:, 1], c=Y, zorder=10, cmap=plt.get_cmap("RdBu"), edgecolors="k" ) plt.axis("tight") @@ -82,7 +81,7 @@ Z = clf.decision_function(xy).reshape(XX.shape) # Put the result into a contour plot - plt.contourf(XX, YY, Z, cmap=cm.get_cmap("RdBu"), alpha=0.5, linestyles=["-"]) + plt.contourf(XX, YY, Z, cmap=plt.get_cmap("RdBu"), alpha=0.5, linestyles=["-"]) plt.xlim(x_min, x_max) plt.ylim(y_min, y_max) diff --git a/sklearn/_min_dependencies.py b/sklearn/_min_dependencies.py index b06c7fb47afb4..c2314528f5745 100644 --- a/sklearn/_min_dependencies.py +++ b/sklearn/_min_dependencies.py @@ -51,7 +51,7 @@ "plotly": ("5.10.0", "docs, examples"), # XXX: Pin conda-lock to the latest released version (needs manual update # from time to time) - "conda-lock": ("1.3.0", "maintenance"), + "conda-lock": ("1.4.0", "maintenance"), } diff --git a/sklearn/metrics/_plot/tests/test_confusion_matrix_display.py b/sklearn/metrics/_plot/tests/test_confusion_matrix_display.py index fd70be4fbc07e..48b7a44f39ea8 100644 --- a/sklearn/metrics/_plot/tests/test_confusion_matrix_display.py +++ b/sklearn/metrics/_plot/tests/test_confusion_matrix_display.py @@ -333,10 +333,7 @@ def test_confusion_matrix_with_unknown_labels(pyplot, constructor_name): def test_colormap_max(pyplot): """Check that the max color is used for the color of the text.""" - - from matplotlib import cm - - gray = cm.get_cmap("gray", 1024) + gray = pyplot.get_cmap("gray", 1024) confusion_matrix = np.array([[1.0, 0.0], [0.0, 1.0]]) disp = ConfusionMatrixDisplay(confusion_matrix) From 76519665dbd6515e7308cc5e0657d04a71dd6802 Mon Sep 17 00:00:00 2001 From: zeeshan lone <56621467+still-learning-ev@users.noreply.github.com> Date: Wed, 15 Mar 2023 20:48:26 +0530 Subject: [PATCH 042/230] MAINT Added Parameter Validation for metrics.mean_gamma_deviance (#25853) --- sklearn/metrics/_regression.py | 7 +++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 8 insertions(+) diff --git a/sklearn/metrics/_regression.py b/sklearn/metrics/_regression.py index 70a3303a4770d..d4337cad59984 100644 --- a/sklearn/metrics/_regression.py +++ b/sklearn/metrics/_regression.py @@ -1186,6 +1186,13 @@ def mean_poisson_deviance(y_true, y_pred, *, sample_weight=None): return mean_tweedie_deviance(y_true, y_pred, sample_weight=sample_weight, power=1) +@validate_params( + { + "y_true": ["array-like"], + "y_pred": ["array-like"], + "sample_weight": ["array-like", None], + } +) def mean_gamma_deviance(y_true, y_pred, *, sample_weight=None): """Mean Gamma deviance regression loss. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index a9fff191b06a7..84c15bf25c389 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -152,6 +152,7 @@ def _check_function_param_validation( "sklearn.metrics.max_error", "sklearn.metrics.mean_absolute_error", "sklearn.metrics.mean_absolute_percentage_error", + "sklearn.metrics.mean_gamma_deviance", "sklearn.metrics.mean_pinball_loss", "sklearn.metrics.mean_squared_error", "sklearn.metrics.mean_tweedie_deviance", From 7469de6dd3d0dc1d83479f3d00cac4ee5ddfbd3c Mon Sep 17 00:00:00 2001 From: Benedek Harsanyi <80836204+hbenedek@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:33:20 +0100 Subject: [PATCH 043/230] MAINT Parameters validation for feature_selection.mutual_info_regression (#25850) --- sklearn/feature_selection/_mutual_info.py | 10 ++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 11 insertions(+) diff --git a/sklearn/feature_selection/_mutual_info.py b/sklearn/feature_selection/_mutual_info.py index f353d78acf4c4..9cacfc3890784 100644 --- a/sklearn/feature_selection/_mutual_info.py +++ b/sklearn/feature_selection/_mutual_info.py @@ -311,6 +311,16 @@ def _estimate_mi( return np.array(mi) +@validate_params( + { + "X": ["array-like", "sparse matrix"], + "y": ["array-like"], + "discrete_features": [StrOptions({"auto"}), "boolean", "array-like"], + "n_neighbors": [Interval(Integral, 1, None, closed="left")], + "copy": ["boolean"], + "random_state": ["random_state"], + } +) def mutual_info_regression( X, y, *, discrete_features="auto", n_neighbors=3, copy=True, random_state=None ): diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 84c15bf25c389..ea1b64cda62f9 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -125,6 +125,7 @@ def _check_function_param_validation( "sklearn.feature_selection.f_classif", "sklearn.feature_selection.f_regression", "sklearn.feature_selection.mutual_info_classif", + "sklearn.feature_selection.mutual_info_regression", "sklearn.feature_selection.r_regression", "sklearn.linear_model.orthogonal_mp", "sklearn.metrics.accuracy_score", From 91ba52d2ef847fcdf25a4b29e84853e67689ec5b Mon Sep 17 00:00:00 2001 From: Pooja Subramaniam Date: Wed, 15 Mar 2023 19:10:29 +0100 Subject: [PATCH 044/230] MAINT parameter validation metrics.class_likelihood_ratios (#25863) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/metrics/_classification.py | 9 +++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 10 insertions(+) diff --git a/sklearn/metrics/_classification.py b/sklearn/metrics/_classification.py index 9aba3f57a54e6..5fb5c0c3e69e6 100644 --- a/sklearn/metrics/_classification.py +++ b/sklearn/metrics/_classification.py @@ -1761,6 +1761,15 @@ def precision_recall_fscore_support( return precision, recall, f_score, true_sum +@validate_params( + { + "y_true": ["array-like", "sparse matrix"], + "y_pred": ["array-like", "sparse matrix"], + "labels": ["array-like", None], + "sample_weight": ["array-like", None], + "raise_warning": ["boolean"], + } +) def class_likelihood_ratios( y_true, y_pred, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index ea1b64cda62f9..b15685eaf122f 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -133,6 +133,7 @@ def _check_function_param_validation( "sklearn.metrics.average_precision_score", "sklearn.metrics.balanced_accuracy_score", "sklearn.metrics.brier_score_loss", + "sklearn.metrics.class_likelihood_ratios", "sklearn.metrics.cluster.contingency_matrix", "sklearn.metrics.cohen_kappa_score", "sklearn.metrics.confusion_matrix", From 509bc9dd84e21839ac42e5e7eeaa2080ed1991c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Wed, 15 Mar 2023 19:44:09 +0100 Subject: [PATCH 045/230] MAINT Ensure disjoint interval constraints (#25797) --- sklearn/cluster/_optics.py | 15 +- sklearn/cluster/tests/test_optics.py | 2 +- sklearn/decomposition/_pca.py | 3 +- sklearn/ensemble/_bagging.py | 7 +- sklearn/ensemble/_forest.py | 3 +- .../gradient_boosting.py | 3 +- sklearn/ensemble/_iforest.py | 3 +- sklearn/feature_extraction/image.py | 7 +- sklearn/feature_extraction/text.py | 7 +- sklearn/feature_selection/_rfe.py | 7 +- sklearn/feature_selection/_sequential.py | 3 +- sklearn/linear_model/_ransac.py | 3 +- sklearn/model_selection/_split.py | 5 +- sklearn/preprocessing/_encoders.py | 5 +- sklearn/tests/test_public_functions.py | 18 +- sklearn/tree/_classes.py | 7 +- sklearn/utils/_param_validation.py | 165 +++++------------- sklearn/utils/estimator_checks.py | 20 ++- sklearn/utils/tests/test_param_validation.py | 83 ++++----- 19 files changed, 168 insertions(+), 198 deletions(-) diff --git a/sklearn/cluster/_optics.py b/sklearn/cluster/_optics.py index fb8daa4db1226..0dd5fb7f7daad 100755 --- a/sklearn/cluster/_optics.py +++ b/sklearn/cluster/_optics.py @@ -20,6 +20,7 @@ from ..metrics.pairwise import _VALID_METRICS from ..utils import gen_batches, get_chunk_n_rows from ..utils._param_validation import Interval, HasMethods, StrOptions, validate_params +from ..utils._param_validation import RealNotInt from ..utils.validation import check_memory from ..neighbors import NearestNeighbors from ..base import BaseEstimator, ClusterMixin @@ -233,7 +234,7 @@ class OPTICS(ClusterMixin, BaseEstimator): _parameter_constraints: dict = { "min_samples": [ Interval(Integral, 2, None, closed="left"), - Interval(Real, 0, 1, closed="both"), + Interval(RealNotInt, 0, 1, closed="both"), ], "max_eps": [Interval(Real, 0, None, closed="both")], "metric": [StrOptions(set(_VALID_METRICS) | {"precomputed"}), callable], @@ -245,7 +246,7 @@ class OPTICS(ClusterMixin, BaseEstimator): "predecessor_correction": ["boolean"], "min_cluster_size": [ Interval(Integral, 2, None, closed="left"), - Interval(Real, 0, 1, closed="right"), + Interval(RealNotInt, 0, 1, closed="right"), None, ], "algorithm": [StrOptions({"auto", "brute", "ball_tree", "kd_tree"})], @@ -431,7 +432,7 @@ def _compute_core_distances_(X, neighbors, min_samples, working_memory): "X": [np.ndarray, "sparse matrix"], "min_samples": [ Interval(Integral, 2, None, closed="left"), - Interval(Real, 0, 1, closed="both"), + Interval(RealNotInt, 0, 1, closed="both"), ], "max_eps": [Interval(Real, 0, None, closed="both")], "metric": [StrOptions(set(_VALID_METRICS) | {"precomputed"}), callable], @@ -723,12 +724,12 @@ def cluster_optics_dbscan(*, reachability, core_distances, ordering, eps): "predecessor": [np.ndarray], "ordering": [np.ndarray], "min_samples": [ - Interval(Integral, 1, None, closed="neither"), - Interval(Real, 0, 1, closed="both"), + Interval(Integral, 2, None, closed="left"), + Interval(RealNotInt, 0, 1, closed="both"), ], "min_cluster_size": [ - Interval(Integral, 1, None, closed="neither"), - Interval(Real, 0, 1, closed="both"), + Interval(Integral, 2, None, closed="left"), + Interval(RealNotInt, 0, 1, closed="both"), None, ], "xi": [Interval(Real, 0, 1, closed="both")], diff --git a/sklearn/cluster/tests/test_optics.py b/sklearn/cluster/tests/test_optics.py index 48ebd11751ef3..38c92f855b746 100644 --- a/sklearn/cluster/tests/test_optics.py +++ b/sklearn/cluster/tests/test_optics.py @@ -197,7 +197,7 @@ def test_minimum_number_of_sample_check(): # Compute OPTICS X = [[1, 1]] - clust = OPTICS(max_eps=5.0 * 0.3, min_samples=10, min_cluster_size=1) + clust = OPTICS(max_eps=5.0 * 0.3, min_samples=10, min_cluster_size=1.0) # Run the fit with pytest.raises(ValueError, match=msg): diff --git a/sklearn/decomposition/_pca.py b/sklearn/decomposition/_pca.py index 789b38c9cd455..e8c302fc47129 100644 --- a/sklearn/decomposition/_pca.py +++ b/sklearn/decomposition/_pca.py @@ -27,6 +27,7 @@ from ..utils.extmath import stable_cumsum from ..utils.validation import check_is_fitted from ..utils._param_validation import Interval, StrOptions +from ..utils._param_validation import RealNotInt def _assess_dimension(spectrum, rank, n_samples): @@ -363,7 +364,7 @@ class PCA(_BasePCA): _parameter_constraints: dict = { "n_components": [ Interval(Integral, 0, None, closed="left"), - Interval(Real, 0, 1, closed="neither"), + Interval(RealNotInt, 0, 1, closed="neither"), StrOptions({"mle"}), None, ], diff --git a/sklearn/ensemble/_bagging.py b/sklearn/ensemble/_bagging.py index d10f89102ea82..c4fb966aacac3 100644 --- a/sklearn/ensemble/_bagging.py +++ b/sklearn/ensemble/_bagging.py @@ -8,7 +8,7 @@ import numbers import numpy as np from abc import ABCMeta, abstractmethod -from numbers import Integral, Real +from numbers import Integral from warnings import warn from functools import partial @@ -22,6 +22,7 @@ from ..utils.multiclass import check_classification_targets from ..utils.random import sample_without_replacement from ..utils._param_validation import Interval, HasMethods, StrOptions +from ..utils._param_validation import RealNotInt from ..utils.validation import has_fit_parameter, check_is_fitted, _check_sample_weight from ..utils._tags import _safe_tags from ..utils.parallel import delayed, Parallel @@ -248,11 +249,11 @@ class BaseBagging(BaseEnsemble, metaclass=ABCMeta): "n_estimators": [Interval(Integral, 1, None, closed="left")], "max_samples": [ Interval(Integral, 1, None, closed="left"), - Interval(Real, 0, 1, closed="right"), + Interval(RealNotInt, 0, 1, closed="right"), ], "max_features": [ Interval(Integral, 1, None, closed="left"), - Interval(Real, 0, 1, closed="right"), + Interval(RealNotInt, 0, 1, closed="right"), ], "bootstrap": ["boolean"], "bootstrap_features": ["boolean"], diff --git a/sklearn/ensemble/_forest.py b/sklearn/ensemble/_forest.py index c84468536b64b..c33d833aeb95f 100644 --- a/sklearn/ensemble/_forest.py +++ b/sklearn/ensemble/_forest.py @@ -74,6 +74,7 @@ class calls the ``fit`` method of each sub-estimator on random samples ) from ..utils.validation import _num_samples from ..utils._param_validation import Interval, StrOptions +from ..utils._param_validation import RealNotInt __all__ = [ @@ -206,7 +207,7 @@ class BaseForest(MultiOutputMixin, BaseEnsemble, metaclass=ABCMeta): "warm_start": ["boolean"], "max_samples": [ None, - Interval(Real, 0.0, 1.0, closed="right"), + Interval(RealNotInt, 0.0, 1.0, closed="right"), Interval(Integral, 1, None, closed="left"), ], } diff --git a/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py b/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py index 6014fc845b8a6..6396d1d43f631 100644 --- a/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py +++ b/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py @@ -26,6 +26,7 @@ _check_monotonic_cst, ) from ...utils._param_validation import Interval, StrOptions +from ...utils._param_validation import RealNotInt from ...utils._openmp_helpers import _openmp_effective_n_threads from ...utils.multiclass import check_classification_targets from ...metrics import check_scoring @@ -99,7 +100,7 @@ class BaseHistGradientBoosting(BaseEstimator, ABC): ], "n_iter_no_change": [Interval(Integral, 1, None, closed="left")], "validation_fraction": [ - Interval(Real, 0, 1, closed="neither"), + Interval(RealNotInt, 0, 1, closed="neither"), Interval(Integral, 1, None, closed="left"), None, ], diff --git a/sklearn/ensemble/_iforest.py b/sklearn/ensemble/_iforest.py index 4e5422c50e614..4d6c1c3f0b7f9 100644 --- a/sklearn/ensemble/_iforest.py +++ b/sklearn/ensemble/_iforest.py @@ -17,6 +17,7 @@ get_chunk_n_rows, ) from ..utils._param_validation import Interval, StrOptions +from ..utils._param_validation import RealNotInt from ..utils.validation import check_is_fitted, _num_samples from ..base import OutlierMixin @@ -206,7 +207,7 @@ class IsolationForest(OutlierMixin, BaseBagging): "max_samples": [ StrOptions({"auto"}), Interval(Integral, 1, None, closed="left"), - Interval(Real, 0, 1, closed="right"), + Interval(RealNotInt, 0, 1, closed="right"), ], "contamination": [ StrOptions({"auto"}), diff --git a/sklearn/feature_extraction/image.py b/sklearn/feature_extraction/image.py index ec7c9dfec90ea..06cbe3b423276 100644 --- a/sklearn/feature_extraction/image.py +++ b/sklearn/feature_extraction/image.py @@ -18,6 +18,7 @@ from ..base import BaseEstimator, TransformerMixin from ..utils import check_array, check_random_state from ..utils._param_validation import Hidden, Interval, validate_params +from ..utils._param_validation import RealNotInt __all__ = [ "PatchExtractor", @@ -343,8 +344,8 @@ def _extract_patches(arr, patch_shape=8, extraction_step=1): "image": [np.ndarray], "patch_size": [tuple, list], "max_patches": [ - Interval(Real, left=0, right=1, closed="neither"), - Interval(Integral, left=1, right=None, closed="left"), + Interval(RealNotInt, 0, 1, closed="neither"), + Interval(Integral, 1, None, closed="left"), None, ], "random_state": ["random_state"], @@ -542,7 +543,7 @@ class PatchExtractor(TransformerMixin, BaseEstimator): "patch_size": [tuple, None], "max_patches": [ None, - Interval(Real, 0, 1, closed="neither"), + Interval(RealNotInt, 0, 1, closed="neither"), Interval(Integral, 1, None, closed="left"), ], "random_state": ["random_state"], diff --git a/sklearn/feature_extraction/text.py b/sklearn/feature_extraction/text.py index 0160bfeaa539f..9d56d2d1bf2dd 100644 --- a/sklearn/feature_extraction/text.py +++ b/sklearn/feature_extraction/text.py @@ -15,7 +15,7 @@ from collections import defaultdict from collections.abc import Mapping from functools import partial -from numbers import Integral, Real +from numbers import Integral from operator import itemgetter import re import unicodedata @@ -32,6 +32,7 @@ from ..utils import _IS_32BIT from ..exceptions import NotFittedError from ..utils._param_validation import StrOptions, Interval, HasMethods +from ..utils._param_validation import RealNotInt __all__ = [ @@ -1148,11 +1149,11 @@ class CountVectorizer(_VectorizerMixin, BaseEstimator): "ngram_range": [tuple], "analyzer": [StrOptions({"word", "char", "char_wb"}), callable], "max_df": [ - Interval(Real, 0, 1, closed="both"), + Interval(RealNotInt, 0, 1, closed="both"), Interval(Integral, 1, None, closed="left"), ], "min_df": [ - Interval(Real, 0, 1, closed="both"), + Interval(RealNotInt, 0, 1, closed="both"), Interval(Integral, 1, None, closed="left"), ], "max_features": [Interval(Integral, 1, None, closed="left"), None], diff --git a/sklearn/feature_selection/_rfe.py b/sklearn/feature_selection/_rfe.py index d105ba1ae3567..214ac9e0c30cf 100644 --- a/sklearn/feature_selection/_rfe.py +++ b/sklearn/feature_selection/_rfe.py @@ -7,13 +7,14 @@ """Recursive feature elimination for feature ranking""" import numpy as np -from numbers import Integral, Real +from numbers import Integral from joblib import effective_n_jobs from ..utils.metaestimators import available_if from ..utils.metaestimators import _safe_split from ..utils._param_validation import HasMethods, Interval +from ..utils._param_validation import RealNotInt from ..utils._tags import _safe_tags from ..utils.validation import check_is_fitted from ..utils.parallel import delayed, Parallel @@ -187,12 +188,12 @@ class RFE(SelectorMixin, MetaEstimatorMixin, BaseEstimator): "estimator": [HasMethods(["fit"])], "n_features_to_select": [ None, - Interval(Real, 0, 1, closed="right"), + Interval(RealNotInt, 0, 1, closed="right"), Interval(Integral, 0, None, closed="neither"), ], "step": [ Interval(Integral, 0, None, closed="neither"), - Interval(Real, 0, 1, closed="neither"), + Interval(RealNotInt, 0, 1, closed="neither"), ], "verbose": ["verbose"], "importance_getter": [str, callable], diff --git a/sklearn/feature_selection/_sequential.py b/sklearn/feature_selection/_sequential.py index 91ea7bdc719b9..e983c55de7d25 100644 --- a/sklearn/feature_selection/_sequential.py +++ b/sklearn/feature_selection/_sequential.py @@ -10,6 +10,7 @@ from ._base import SelectorMixin from ..base import BaseEstimator, MetaEstimatorMixin, clone from ..utils._param_validation import HasMethods, Hidden, Interval, StrOptions +from ..utils._param_validation import RealNotInt from ..utils._tags import _safe_tags from ..utils.validation import check_is_fitted from ..model_selection import cross_val_score @@ -154,7 +155,7 @@ class SequentialFeatureSelector(SelectorMixin, MetaEstimatorMixin, BaseEstimator "estimator": [HasMethods(["fit"])], "n_features_to_select": [ StrOptions({"auto", "warn"}, deprecated={"warn"}), - Interval(Real, 0, 1, closed="right"), + Interval(RealNotInt, 0, 1, closed="right"), Interval(Integral, 0, None, closed="neither"), Hidden(None), ], diff --git a/sklearn/linear_model/_ransac.py b/sklearn/linear_model/_ransac.py index ff58e067cde35..472f2275ffa6b 100644 --- a/sklearn/linear_model/_ransac.py +++ b/sklearn/linear_model/_ransac.py @@ -15,6 +15,7 @@ from ._base import LinearRegression from ..utils.validation import has_fit_parameter from ..utils._param_validation import Interval, Options, StrOptions, HasMethods, Hidden +from ..utils._param_validation import RealNotInt from ..exceptions import ConvergenceWarning _EPSILON = np.spacing(1) @@ -236,7 +237,7 @@ class RANSACRegressor( "estimator": [HasMethods(["fit", "score", "predict"]), None], "min_samples": [ Interval(Integral, 1, None, closed="left"), - Interval(Real, 0, 1, closed="both"), + Interval(RealNotInt, 0, 1, closed="both"), None, ], "residual_threshold": [Interval(Real, 0, None, closed="left"), None], diff --git a/sklearn/model_selection/_split.py b/sklearn/model_selection/_split.py index 5c3854cfc9d3b..dded962a350d8 100644 --- a/sklearn/model_selection/_split.py +++ b/sklearn/model_selection/_split.py @@ -29,6 +29,7 @@ from ..utils.validation import check_array from ..utils.multiclass import type_of_target from ..utils._param_validation import validate_params, Interval +from ..utils._param_validation import RealNotInt __all__ = [ "BaseCrossValidator", @@ -2464,12 +2465,12 @@ def check_cv(cv=5, y=None, *, classifier=False): @validate_params( { "test_size": [ - Interval(numbers.Real, 0, 1, closed="neither"), + Interval(RealNotInt, 0, 1, closed="neither"), Interval(numbers.Integral, 1, None, closed="left"), None, ], "train_size": [ - Interval(numbers.Real, 0, 1, closed="neither"), + Interval(RealNotInt, 0, 1, closed="neither"), Interval(numbers.Integral, 1, None, closed="left"), None, ], diff --git a/sklearn/preprocessing/_encoders.py b/sklearn/preprocessing/_encoders.py index 4c3e80771c35a..7df0584ba9d5b 100644 --- a/sklearn/preprocessing/_encoders.py +++ b/sklearn/preprocessing/_encoders.py @@ -3,7 +3,7 @@ # License: BSD 3 clause import numbers -from numbers import Integral, Real +from numbers import Integral import warnings import numpy as np @@ -14,6 +14,7 @@ from ..utils.validation import check_is_fitted from ..utils.validation import _check_feature_names_in from ..utils._param_validation import Interval, StrOptions, Hidden +from ..utils._param_validation import RealNotInt from ..utils._mask import _get_mask from ..utils._encode import _encode, _check_unknown, _unique, _get_counts @@ -493,7 +494,7 @@ class OneHotEncoder(_BaseEncoder): "max_categories": [Interval(Integral, 1, None, closed="left"), None], "min_frequency": [ Interval(Integral, 1, None, closed="left"), - Interval(Real, 0, 1, closed="neither"), + Interval(RealNotInt, 0, 1, closed="neither"), None, ], "sparse": [Hidden(StrOptions({"deprecated"})), "boolean"], # deprecated diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index b15685eaf122f..a81264e2e6ccd 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -1,5 +1,6 @@ from importlib import import_module from inspect import signature +from numbers import Integral, Real import pytest @@ -7,6 +8,7 @@ from sklearn.utils._param_validation import generate_valid_param from sklearn.utils._param_validation import make_constraint from sklearn.utils._param_validation import InvalidParameterError +from sklearn.utils._param_validation import Interval def _get_func_info(func_module): @@ -70,6 +72,20 @@ def _check_function_param_validation( # This parameter is not validated continue + # Mixing an interval of reals and an interval of integers must be avoided. + if any( + isinstance(constraint, Interval) and constraint.type == Integral + for constraint in constraints + ) and any( + isinstance(constraint, Interval) and constraint.type == Real + for constraint in constraints + ): + raise ValueError( + f"The constraint for parameter {param_name} of {func_name} can't have a" + " mix of intervals of Integral and Real types. Use the type" + " RealNotInt instead of Real." + ) + match = ( rf"The '{param_name}' parameter of {func_name} must be .* Got .* instead." ) @@ -85,7 +101,7 @@ def _check_function_param_validation( for constraint in constraints: try: - bad_value = generate_invalid_param_val(constraint, constraints) + bad_value = generate_invalid_param_val(constraint) except NotImplementedError: continue diff --git a/sklearn/tree/_classes.py b/sklearn/tree/_classes.py index 6e01b8b49e594..e0e341d9a89f6 100644 --- a/sklearn/tree/_classes.py +++ b/sklearn/tree/_classes.py @@ -38,6 +38,7 @@ from ..utils.multiclass import check_classification_targets from ..utils.validation import check_is_fitted from ..utils._param_validation import Hidden, Interval, StrOptions +from ..utils._param_validation import RealNotInt from ._criterion import Criterion from ._splitter import Splitter @@ -99,16 +100,16 @@ class BaseDecisionTree(MultiOutputMixin, BaseEstimator, metaclass=ABCMeta): "max_depth": [Interval(Integral, 1, None, closed="left"), None], "min_samples_split": [ Interval(Integral, 2, None, closed="left"), - Interval("real_not_int", 0.0, 1.0, closed="right"), + Interval(RealNotInt, 0.0, 1.0, closed="right"), ], "min_samples_leaf": [ Interval(Integral, 1, None, closed="left"), - Interval("real_not_int", 0.0, 1.0, closed="neither"), + Interval(RealNotInt, 0.0, 1.0, closed="neither"), ], "min_weight_fraction_leaf": [Interval(Real, 0.0, 0.5, closed="both")], "max_features": [ Interval(Integral, 1, None, closed="left"), - Interval("real_not_int", 0.0, 1.0, closed="right"), + Interval(RealNotInt, 0.0, 1.0, closed="right"), StrOptions({"auto", "sqrt", "log2"}, deprecated={"auto"}), None, ], diff --git a/sklearn/utils/_param_validation.py b/sklearn/utils/_param_validation.py index 8d23f0b23b6eb..4370817094be8 100644 --- a/sklearn/utils/_param_validation.py +++ b/sklearn/utils/_param_validation.py @@ -207,6 +207,18 @@ def wrapper(*args, **kwargs): return decorator +class RealNotInt(Real): + """A type that represents reals that are not instances of int. + + Behaves like float, but also works with values extracted from numpy arrays. + isintance(1, RealNotInt) -> False + isinstance(1.0, RealNotInt) -> True + """ + + +RealNotInt.register(float) + + def _type_name(t): """Convert type into human readable string.""" module = t.__module__ @@ -364,10 +376,10 @@ class Interval(_Constraint): Parameters ---------- - type : {numbers.Integral, numbers.Real, "real_not_int"} + type : {numbers.Integral, numbers.Real, RealNotInt} The set of numbers in which to set the interval. - If "real_not_int", only reals that don't have the integer type + If RealNotInt, only reals that don't have the integer type are allowed. For example 1.0 is allowed but 1 is not. left : float or int or None @@ -405,9 +417,9 @@ def __init__(self, type, left, right, *, closed): self._check_params() def _check_params(self): - if self.type not in (Integral, Real, "real_not_int"): + if self.type not in (Integral, Real, RealNotInt): raise ValueError( - "type must be either numbers.Integral, numbers.Real or 'real_not_int'." + "type must be either numbers.Integral, numbers.Real or RealNotInt." f" Got {self.type} instead." ) @@ -459,13 +471,8 @@ def __contains__(self, val): return False return True - def _has_valid_type(self, val): - if self.type == "real_not_int": - return isinstance(val, Real) and not isinstance(val, Integral) - return isinstance(val, self.type) - def is_satisfied_by(self, val): - if not self._has_valid_type(val): + if not isinstance(val, self.type): return False return val in self @@ -476,6 +483,13 @@ def __str__(self): left_bound = "-inf" if self.left is None else self.left right_bound = "inf" if self.right is None else self.right right_bracket = "]" if self.closed in ("right", "both") else ")" + + # better repr if the bounds were given as integers + if not self.type == Integral and isinstance(self.left, Real): + left_bound = float(left_bound) + if not self.type == Integral and isinstance(self.right, Real): + right_bound = float(right_bound) + return ( f"{type_str} in the range " f"{left_bracket}{left_bound}, {right_bound}{right_bracket}" @@ -718,7 +732,7 @@ def __init__(self, constraint): self.constraint = constraint -def generate_invalid_param_val(constraint, constraints=None): +def generate_invalid_param_val(constraint): """Return a value that does not satisfy the constraint. Raises a NotImplementedError if there exists no invalid value for this constraint. @@ -730,10 +744,6 @@ def generate_invalid_param_val(constraint, constraints=None): constraint : _Constraint instance The constraint to generate a value for. - constraints : list of _Constraint instances or None, default=None - The list of all constraints for this parameter. If None, the list only - containing `constraint` is used. - Returns ------- val : object @@ -757,116 +767,31 @@ def generate_invalid_param_val(constraint, constraints=None): if isinstance(constraint, _CVObjects): return "not a cv object" - if not isinstance(constraint, Interval): - raise NotImplementedError - - # constraint is an interval - constraints = [constraint] if constraints is None else constraints - return _generate_invalid_param_val_interval(constraint, constraints) + if isinstance(constraint, Interval) and constraint.type is Integral: + if constraint.left is not None: + return constraint.left - 1 + if constraint.right is not None: + return constraint.right + 1 + # There's no integer outside (-inf, +inf) + raise NotImplementedError -def _generate_invalid_param_val_interval(interval, constraints): - """Return a value that does not satisfy an interval constraint. - - Generating an invalid value for an integer interval depends on the other constraints - since an int is a real, meaning that it can be valid for a real interval. - Assumes that there can be at most 2 interval constraints: one integer interval - and/or one real interval. - - This is only useful for testing purpose. - - Parameters - ---------- - interval : Interval instance - The interval to generate a value for. - - constraints : list of _Constraint instances - The list of all constraints for this parameter. - - Returns - ------- - val : object - A value that does not satisfy the interval constraint. - """ - if interval.type is Real: - # generate a non-integer value such that it can't be valid even if there's also - # an integer interval constraint. - if interval.left is None and interval.right is None: - if interval.closed in ("left", "neither"): - return np.inf - elif interval.closed in ("right", "neither"): - return -np.inf - else: - raise NotImplementedError + if isinstance(constraint, Interval) and constraint.type in (Real, RealNotInt): + if constraint.left is not None: + return constraint.left - 1e-6 + if constraint.right is not None: + return constraint.right + 1e-6 - if interval.left is not None: - return np.floor(interval.left) - 0.5 - else: # right is not None - return np.ceil(interval.right) + 0.5 + # bounds are -inf, +inf + if constraint.closed in ("right", "neither"): + return -np.inf + if constraint.closed in ("left", "neither"): + return np.inf - else: # interval.type is Integral - if interval.left is None and interval.right is None: - raise NotImplementedError + # interval is [-inf, +inf] + return np.nan - # We need to check if there's also a real interval constraint to generate a - # value that is not valid for any of the 2 interval constraints. - real_intervals = [ - i for i in constraints if isinstance(i, Interval) and i.type is Real - ] - real_interval = real_intervals[0] if real_intervals else None - - if real_interval is None: - # Only the integer interval constraint -> easy - if interval.left is not None: - return interval.left - 1 - else: # interval.right is not None - return interval.right + 1 - - # There's also a real interval constraint. Try to find a value left to both or - # right to both or in between them. - - # redefine left and right bounds to be smallest and largest valid integers in - # both intervals. - int_left = interval.left - if int_left is not None and interval.closed in ("right", "neither"): - int_left = int_left + 1 - - int_right = interval.right - if int_right is not None and interval.closed in ("left", "neither"): - int_right = int_right - 1 - - real_left = real_interval.left - if real_interval.left is not None: - real_left = int(np.ceil(real_interval.left)) - if real_interval.closed in ("right", "neither"): - real_left = real_left + 1 - - real_right = real_interval.right - if real_interval.right is not None: - real_right = int(np.floor(real_interval.right)) - if real_interval.closed in ("left", "neither"): - real_right = real_right - 1 - - if int_left is not None and real_left is not None: - # there exists an int left to both intervals - return min(int_left, real_left) - 1 - - if int_right is not None and real_right is not None: - # there exists an int right to both intervals - return max(int_right, real_right) + 1 - - if int_left is not None: - if real_right is not None and int_left - real_right >= 2: - # there exists an int between the 2 intervals - return int_left - 1 - else: - raise NotImplementedError - else: # int_right is not None - if real_left is not None and real_left - int_right >= 2: - # there exists an int between the 2 intervals - return int_right + 1 - else: - raise NotImplementedError + raise NotImplementedError def generate_valid_param(constraint): diff --git a/sklearn/utils/estimator_checks.py b/sklearn/utils/estimator_checks.py index 14aaf8b40e8e0..d38473693efd0 100644 --- a/sklearn/utils/estimator_checks.py +++ b/sklearn/utils/estimator_checks.py @@ -4,7 +4,7 @@ from copy import deepcopy from functools import partial, wraps from inspect import signature -from numbers import Real +from numbers import Real, Integral import numpy as np from scipy import sparse @@ -1434,7 +1434,7 @@ def check_fit2d_1sample(name, estimator_orig): # min_cluster_size cannot be less than the data size for OPTICS. if name == "OPTICS": - estimator.set_params(min_samples=1) + estimator.set_params(min_samples=1.0) # perplexity cannot be more than the number of samples for TSNE. if name == "TSNE": @@ -4155,6 +4155,20 @@ def check_param_validation(name, estimator_orig): # This parameter is not validated continue + # Mixing an interval of reals and an interval of integers must be avoided. + if any( + isinstance(constraint, Interval) and constraint.type == Integral + for constraint in constraints + ) and any( + isinstance(constraint, Interval) and constraint.type == Real + for constraint in constraints + ): + raise ValueError( + f"The constraint for parameter {param_name} of {name} can't have a mix" + " of intervals of Integral and Real types. Use the type RealNotInt" + " instead of Real." + ) + match = rf"The '{param_name}' parameter of {name} must be .* Got .* instead." err_msg = ( f"{name} does not raise an informative error message when the " @@ -4188,7 +4202,7 @@ def check_param_validation(name, estimator_orig): for constraint in constraints: try: - bad_value = generate_invalid_param_val(constraint, constraints) + bad_value = generate_invalid_param_val(constraint) except NotImplementedError: continue diff --git a/sklearn/utils/tests/test_param_validation.py b/sklearn/utils/tests/test_param_validation.py index ce8f9cdf939fd..bfbbf2a1b29df 100644 --- a/sklearn/utils/tests/test_param_validation.py +++ b/sklearn/utils/tests/test_param_validation.py @@ -29,6 +29,7 @@ from sklearn.utils._param_validation import generate_valid_param from sklearn.utils._param_validation import validate_params from sklearn.utils._param_validation import InvalidParameterError +from sklearn.utils._param_validation import RealNotInt # Some helpers for the tests @@ -219,75 +220,75 @@ def test_generate_invalid_param_val(constraint): [ ( Interval(Integral, None, 3, closed="right"), - Interval(Real, -5, 5, closed="both"), + Interval(RealNotInt, -5, 5, closed="both"), ), ( Interval(Integral, None, 3, closed="right"), - Interval(Real, -5, 5, closed="neither"), + Interval(RealNotInt, -5, 5, closed="neither"), ), ( Interval(Integral, None, 3, closed="right"), - Interval(Real, 4, 5, closed="both"), + Interval(RealNotInt, 4, 5, closed="both"), ), ( Interval(Integral, None, 3, closed="right"), - Interval(Real, 5, None, closed="left"), + Interval(RealNotInt, 5, None, closed="left"), ), ( Interval(Integral, None, 3, closed="right"), - Interval(Real, 4, None, closed="neither"), + Interval(RealNotInt, 4, None, closed="neither"), ), ( Interval(Integral, 3, None, closed="left"), - Interval(Real, -5, 5, closed="both"), + Interval(RealNotInt, -5, 5, closed="both"), ), ( Interval(Integral, 3, None, closed="left"), - Interval(Real, -5, 5, closed="neither"), + Interval(RealNotInt, -5, 5, closed="neither"), ), ( Interval(Integral, 3, None, closed="left"), - Interval(Real, 1, 2, closed="both"), + Interval(RealNotInt, 1, 2, closed="both"), ), ( Interval(Integral, 3, None, closed="left"), - Interval(Real, None, -5, closed="left"), + Interval(RealNotInt, None, -5, closed="left"), ), ( Interval(Integral, 3, None, closed="left"), - Interval(Real, None, -4, closed="neither"), + Interval(RealNotInt, None, -4, closed="neither"), ), ( Interval(Integral, -5, 5, closed="both"), - Interval(Real, None, 1, closed="right"), + Interval(RealNotInt, None, 1, closed="right"), ), ( Interval(Integral, -5, 5, closed="both"), - Interval(Real, 1, None, closed="left"), + Interval(RealNotInt, 1, None, closed="left"), ), ( Interval(Integral, -5, 5, closed="both"), - Interval(Real, -10, -4, closed="neither"), + Interval(RealNotInt, -10, -4, closed="neither"), ), ( Interval(Integral, -5, 5, closed="both"), - Interval(Real, -10, -4, closed="right"), + Interval(RealNotInt, -10, -4, closed="right"), ), ( Interval(Integral, -5, 5, closed="neither"), - Interval(Real, 6, 10, closed="neither"), + Interval(RealNotInt, 6, 10, closed="neither"), ), ( Interval(Integral, -5, 5, closed="neither"), - Interval(Real, 6, 10, closed="left"), + Interval(RealNotInt, 6, 10, closed="left"), ), ( Interval(Integral, 2, None, closed="left"), - Interval(Real, 0, 1, closed="both"), + Interval(RealNotInt, 0, 1, closed="both"), ), ( Interval(Integral, 1, None, closed="left"), - Interval(Real, 0, 1, closed="both"), + Interval(RealNotInt, 0, 1, closed="both"), ), ], ) @@ -295,42 +296,34 @@ def test_generate_invalid_param_val_2_intervals(integer_interval, real_interval) """Check that the value generated for an interval constraint does not satisfy any of the interval constraints. """ - bad_value = generate_invalid_param_val( - real_interval, constraints=[real_interval, integer_interval] - ) + bad_value = generate_invalid_param_val(constraint=real_interval) assert not real_interval.is_satisfied_by(bad_value) assert not integer_interval.is_satisfied_by(bad_value) - bad_value = generate_invalid_param_val( - integer_interval, constraints=[real_interval, integer_interval] - ) + bad_value = generate_invalid_param_val(constraint=integer_interval) assert not real_interval.is_satisfied_by(bad_value) assert not integer_interval.is_satisfied_by(bad_value) @pytest.mark.parametrize( - "constraints", + "constraint", [ - [_ArrayLikes()], - [_InstancesOf(list)], - [_Callables()], - [_NoneConstraint()], - [_RandomStates()], - [_SparseMatrices()], - [_Booleans()], - [Interval(Real, None, None, closed="both")], - [ - Interval(Integral, 0, None, closed="left"), - Interval(Real, None, 0, closed="neither"), - ], + _ArrayLikes(), + _InstancesOf(list), + _Callables(), + _NoneConstraint(), + _RandomStates(), + _SparseMatrices(), + _Booleans(), + Interval(Integral, None, None, closed="neither"), ], ) -def test_generate_invalid_param_val_all_valid(constraints): +def test_generate_invalid_param_val_all_valid(constraint): """Check that the function raises NotImplementedError when there's no invalid value for the constraint. """ with pytest.raises(NotImplementedError): - generate_invalid_param_val(constraints[0], constraints=constraints) + generate_invalid_param_val(constraint) @pytest.mark.parametrize( @@ -665,7 +658,15 @@ def fit(self, X=None, y=None): def test_interval_real_not_int(): - """Check for the type "real_not_int" in the Interval constraint.""" - constraint = Interval("real_not_int", 0, 1, closed="both") + """Check for the type RealNotInt in the Interval constraint.""" + constraint = Interval(RealNotInt, 0, 1, closed="both") assert constraint.is_satisfied_by(1.0) assert not constraint.is_satisfied_by(1) + + +def test_real_not_int(): + """Check for the RealNotInt type.""" + assert isinstance(1.0, RealNotInt) + assert not isinstance(1, RealNotInt) + assert isinstance(np.float64(1), RealNotInt) + assert not isinstance(np.int64(1), RealNotInt) From d641985b4da45fb3e74054455083d4a44ca574d6 Mon Sep 17 00:00:00 2001 From: Pooja Subramaniam Date: Wed, 15 Mar 2023 20:23:27 +0100 Subject: [PATCH 046/230] MAINT Parameters validation for utils.gen_batches (#25864) --- sklearn/tests/test_public_functions.py | 1 + sklearn/utils/__init__.py | 14 ++++++++------ sklearn/utils/tests/test_utils.py | 14 -------------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index a81264e2e6ccd..7f8fe0f2717ab 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -189,6 +189,7 @@ def _check_function_param_validation( "sklearn.model_selection.train_test_split", "sklearn.random_projection.johnson_lindenstrauss_min_dim", "sklearn.svm.l1_min_c", + "sklearn.utils.gen_batches", ] diff --git a/sklearn/utils/__init__.py b/sklearn/utils/__init__.py index 923c08d44c6f4..0b3119c0bfa03 100644 --- a/sklearn/utils/__init__.py +++ b/sklearn/utils/__init__.py @@ -39,6 +39,7 @@ ) from .. import get_config from ._bunch import Bunch +from ._param_validation import validate_params, Interval # Do not deprecate parallel_backend and register_parallel_backend as they are @@ -725,6 +726,13 @@ def _chunk_generator(gen, chunksize): return +@validate_params( + { + "n": [Interval(numbers.Integral, 1, None, closed="left")], + "batch_size": [Interval(numbers.Integral, 1, None, closed="left")], + "min_batch_size": [Interval(numbers.Integral, 0, None, closed="left")], + } +) def gen_batches(n, batch_size, *, min_batch_size=0): """Generator to create slices containing `batch_size` elements from 0 to `n`. @@ -762,12 +770,6 @@ def gen_batches(n, batch_size, *, min_batch_size=0): >>> list(gen_batches(7, 3, min_batch_size=2)) [slice(0, 3, None), slice(3, 7, None)] """ - if not isinstance(batch_size, numbers.Integral): - raise TypeError( - "gen_batches got batch_size=%s, must be an integer" % batch_size - ) - if batch_size <= 0: - raise ValueError("gen_batches got batch_size=%s, must be positive" % batch_size) start = 0 for _ in range(int(n // batch_size)): end = start + batch_size diff --git a/sklearn/utils/tests/test_utils.py b/sklearn/utils/tests/test_utils.py index 848985f267c92..a000394bbee28 100644 --- a/sklearn/utils/tests/test_utils.py +++ b/sklearn/utils/tests/test_utils.py @@ -17,7 +17,6 @@ from sklearn.utils import check_random_state from sklearn.utils import _determine_key_type from sklearn.utils import deprecated -from sklearn.utils import gen_batches from sklearn.utils import _get_column_indices from sklearn.utils import resample from sklearn.utils import safe_mask @@ -56,19 +55,6 @@ def test_make_rng(): check_random_state("some invalid seed") -def test_gen_batches(): - # Make sure gen_batches errors on invalid batch_size - - assert_array_equal(list(gen_batches(4, 2)), [slice(0, 2, None), slice(2, 4, None)]) - msg_zero = "gen_batches got batch_size=0, must be positive" - with pytest.raises(ValueError, match=msg_zero): - next(gen_batches(4, 0)) - - msg_float = "gen_batches got batch_size=0.5, must be an integer" - with pytest.raises(TypeError, match=msg_float): - next(gen_batches(4, 0.5)) - - def test_deprecated(): # Test whether the deprecated decorator issues appropriate warnings # Copied almost verbatim from https://docs.python.org/library/warnings.html From f08dadb42fada30982ee0895affa73ac3b26ecfb Mon Sep 17 00:00:00 2001 From: Rushil Desai Date: Thu, 16 Mar 2023 02:53:22 +0530 Subject: [PATCH 047/230] TST use global_random_seed in test_dict_vectorizer.py (#24533) --- sklearn/feature_extraction/tests/test_dict_vectorizer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sklearn/feature_extraction/tests/test_dict_vectorizer.py b/sklearn/feature_extraction/tests/test_dict_vectorizer.py index 613b7eeee4f4e..c8b9aaa8b5c8a 100644 --- a/sklearn/feature_extraction/tests/test_dict_vectorizer.py +++ b/sklearn/feature_extraction/tests/test_dict_vectorizer.py @@ -145,10 +145,10 @@ def test_unseen_or_no_features(): v.transform([]) -def test_deterministic_vocabulary(): +def test_deterministic_vocabulary(global_random_seed): # Generate equal dictionaries with different memory layouts items = [("%03d" % i, i) for i in range(1000)] - rng = Random(42) + rng = Random(global_random_seed) d_sorted = dict(items) rng.shuffle(items) d_shuffled = dict(items) From 0da26961d3e3be9f4c03b9f62402ea8bcff0209f Mon Sep 17 00:00:00 2001 From: Xiao Yuan Date: Thu, 16 Mar 2023 05:30:46 +0800 Subject: [PATCH 048/230] TST use global_random_seed in test_pls.py (#24526) Co-authored-by: jeremiedbb --- sklearn/cross_decomposition/tests/test_pls.py | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/sklearn/cross_decomposition/tests/test_pls.py b/sklearn/cross_decomposition/tests/test_pls.py index aff2b76034b0b..55ef8b482d58e 100644 --- a/sklearn/cross_decomposition/tests/test_pls.py +++ b/sklearn/cross_decomposition/tests/test_pls.py @@ -484,31 +484,35 @@ def test_n_components_upper_bounds(Estimator): @pytest.mark.parametrize("n_samples, n_features", [(100, 10), (100, 200)]) -@pytest.mark.parametrize("seed", range(10)) -def test_singular_value_helpers(n_samples, n_features, seed): +def test_singular_value_helpers(n_samples, n_features, global_random_seed): # Make sure SVD and power method give approximately the same results - X, Y = make_regression(n_samples, n_features, n_targets=5, random_state=seed) + X, Y = make_regression( + n_samples, n_features, n_targets=5, random_state=global_random_seed + ) u1, v1, _ = _get_first_singular_vectors_power_method(X, Y, norm_y_weights=True) u2, v2 = _get_first_singular_vectors_svd(X, Y) _svd_flip_1d(u1, v1) _svd_flip_1d(u2, v2) - rtol = 1e-1 - assert_allclose(u1, u2, rtol=rtol) - assert_allclose(v1, v2, rtol=rtol) + rtol = 1e-3 + # Setting atol because some coordinates are very close to zero + assert_allclose(u1, u2, atol=u2.max() * rtol) + assert_allclose(v1, v2, atol=v2.max() * rtol) -def test_one_component_equivalence(): +def test_one_component_equivalence(global_random_seed): # PLSSVD, PLSRegression and PLSCanonical should all be equivalent when # n_components is 1 - X, Y = make_regression(100, 10, n_targets=5, random_state=0) + X, Y = make_regression(100, 10, n_targets=5, random_state=global_random_seed) svd = PLSSVD(n_components=1).fit(X, Y).transform(X) reg = PLSRegression(n_components=1).fit(X, Y).transform(X) canonical = PLSCanonical(n_components=1).fit(X, Y).transform(X) - assert_allclose(svd, reg, rtol=1e-2) - assert_allclose(svd, canonical, rtol=1e-2) + rtol = 1e-3 + # Setting atol because some entries are very close to zero + assert_allclose(svd, reg, atol=reg.max() * rtol) + assert_allclose(svd, canonical, atol=canonical.max() * rtol) def test_svd_flip_1d(): @@ -526,9 +530,11 @@ def test_svd_flip_1d(): assert_allclose(v, [-1, -2, -3]) -def test_loadings_converges(): +def test_loadings_converges(global_random_seed): """Test that CCA converges. Non-regression test for #19549.""" - X, y = make_regression(n_samples=200, n_features=20, n_targets=20, random_state=20) + X, y = make_regression( + n_samples=200, n_features=20, n_targets=20, random_state=global_random_seed + ) cca = CCA(n_components=10, max_iter=500) From 01341cde034e04ecf8a6ef03f096727db893e889 Mon Sep 17 00:00:00 2001 From: Omar Salman Date: Thu, 16 Mar 2023 03:23:57 +0500 Subject: [PATCH 049/230] TST use global_random_seed in test_gpc.py (#24600) Co-authored-by: jeremiedbb --- sklearn/gaussian_process/tests/test_gpc.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sklearn/gaussian_process/tests/test_gpc.py b/sklearn/gaussian_process/tests/test_gpc.py index 2173f77c161c1..aefdb2e8ff0e2 100644 --- a/sklearn/gaussian_process/tests/test_gpc.py +++ b/sklearn/gaussian_process/tests/test_gpc.py @@ -118,11 +118,11 @@ def test_lml_gradient(kernel): assert_almost_equal(lml_gradient, lml_gradient_approx, 3) -def test_random_starts(): +def test_random_starts(global_random_seed): # Test that an increasing number of random-starts of GP fitting only # increases the log marginal likelihood of the chosen theta. n_samples, n_features = 25, 2 - rng = np.random.RandomState(0) + rng = np.random.RandomState(global_random_seed) X = rng.randn(n_samples, n_features) * 2 - 1 y = (np.sin(X).sum(axis=1) + np.sin(3 * X).sum(axis=1)) > 0 @@ -132,7 +132,9 @@ def test_random_starts(): last_lml = -np.inf for n_restarts_optimizer in range(5): gp = GaussianProcessClassifier( - kernel=kernel, n_restarts_optimizer=n_restarts_optimizer, random_state=0 + kernel=kernel, + n_restarts_optimizer=n_restarts_optimizer, + random_state=global_random_seed, ).fit(X, y) lml = gp.log_marginal_likelihood(gp.kernel_.theta) assert lml > last_lml - np.finfo(np.float32).eps @@ -140,11 +142,11 @@ def test_random_starts(): @pytest.mark.parametrize("kernel", non_fixed_kernels) -def test_custom_optimizer(kernel): +def test_custom_optimizer(kernel, global_random_seed): # Test that GPC can use externally defined optimizers. # Define a dummy optimizer that simply tests 10 random hyperparameters def optimizer(obj_func, initial_theta, bounds): - rng = np.random.RandomState(0) + rng = np.random.RandomState(global_random_seed) theta_opt, func_min = initial_theta, obj_func( initial_theta, eval_gradient=False ) @@ -160,9 +162,9 @@ def optimizer(obj_func, initial_theta, bounds): gpc = GaussianProcessClassifier(kernel=kernel, optimizer=optimizer) gpc.fit(X, y_mc) # Checks that optimizer improved marginal likelihood - assert gpc.log_marginal_likelihood(gpc.kernel_.theta) > gpc.log_marginal_likelihood( - kernel.theta - ) + assert gpc.log_marginal_likelihood( + gpc.kernel_.theta + ) >= gpc.log_marginal_likelihood(kernel.theta) @pytest.mark.parametrize("kernel", kernels) From 794d7e9e6d86798b90fdc18fb48188d9a26f6c99 Mon Sep 17 00:00:00 2001 From: 2357juan <29247195+2357juan@users.noreply.github.com> Date: Thu, 16 Mar 2023 02:31:28 -0700 Subject: [PATCH 050/230] DOC Fix overlapping plot axis in bench_sample_without_replacement.py (#25870) --- benchmarks/bench_sample_without_replacement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/bench_sample_without_replacement.py b/benchmarks/bench_sample_without_replacement.py index 4f1041a6d1022..6e68073c93860 100644 --- a/benchmarks/bench_sample_without_replacement.py +++ b/benchmarks/bench_sample_without_replacement.py @@ -208,7 +208,7 @@ def bench_sample(sampling, n_population, n_samples): print("") fig = plt.figure("scikit-learn sample w/o replacement benchmark results") - plt.title("n_population = %s, n_times = %s" % (opts.n_population, opts.n_times)) + fig.suptitle("n_population = %s, n_times = %s" % (opts.n_population, opts.n_times)) ax = fig.add_subplot(111) for name in sampling_algorithm: ax.plot(ratio, time[name], label=name) From e2b3b6dd5d88d6707b0692a20346877c79793de2 Mon Sep 17 00:00:00 2001 From: 2357juan <29247195+2357juan@users.noreply.github.com> Date: Thu, 16 Mar 2023 02:39:42 -0700 Subject: [PATCH 051/230] MAINT Use contiguous memoryviews in _random.pyx (#25871) --- sklearn/utils/_random.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sklearn/utils/_random.pyx b/sklearn/utils/_random.pyx index 3589ffd2fdc4c..9b71b112aa1fb 100644 --- a/sklearn/utils/_random.pyx +++ b/sklearn/utils/_random.pyx @@ -78,7 +78,7 @@ cpdef _sample_without_replacement_with_tracking_selection( cdef cnp.int_t i cdef cnp.int_t j - cdef cnp.int_t[:] out = np.empty((n_samples, ), dtype=int) + cdef cnp.int_t[::1] out = np.empty((n_samples, ), dtype=int) rng = check_random_state(random_state) rng_randint = rng.randint @@ -133,9 +133,9 @@ cpdef _sample_without_replacement_with_pool(cnp.int_t n_population, cdef cnp.int_t i cdef cnp.int_t j - cdef cnp.int_t[:] out = np.empty((n_samples, ), dtype=int) + cdef cnp.int_t[::1] out = np.empty((n_samples, ), dtype=int) - cdef cnp.int_t[:] pool = np.empty((n_population, ), + cdef cnp.int_t[::1] pool = np.empty((n_population, ), dtype=int) rng = check_random_state(random_state) @@ -195,7 +195,7 @@ cpdef _sample_without_replacement_with_reservoir_sampling( cdef cnp.int_t i cdef cnp.int_t j - cdef cnp.int_t[:] out = np.empty((n_samples, ), dtype=int) + cdef cnp.int_t[::1] out = np.empty((n_samples, ), dtype=int) rng = check_random_state(random_state) rng_randint = rng.randint From 8745bf2e214a3ee83b3060ff8a0e30e53a9eb0f4 Mon Sep 17 00:00:00 2001 From: Shiva chauhan <103742975+Shivachauhan17@users.noreply.github.com> Date: Thu, 16 Mar 2023 19:28:40 +0530 Subject: [PATCH 052/230] MAINT parameter validation sklearn.datasets.fetch_lfw_pair (#25857) --- sklearn/datasets/_lfw.py | 13 ++++++++++++- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sklearn/datasets/_lfw.py b/sklearn/datasets/_lfw.py index c6f1a5f9a90c8..01f993fc52873 100644 --- a/sklearn/datasets/_lfw.py +++ b/sklearn/datasets/_lfw.py @@ -10,7 +10,7 @@ from os import listdir, makedirs, remove from os.path import join, exists, isdir -from ..utils._param_validation import validate_params, Interval, Hidden +from ..utils._param_validation import validate_params, Interval, Hidden, StrOptions from numbers import Integral, Real import logging @@ -427,6 +427,17 @@ def _fetch_lfw_pairs( return pairs, target, np.array(["Different persons", "Same person"]) +@validate_params( + { + "subset": [StrOptions({"train", "test", "10_folds"})], + "data_home": [str, None], + "funneled": ["boolean"], + "resize": [Interval(Real, 0, None, closed="neither"), None], + "color": ["boolean"], + "slice_": [tuple, Hidden(None)], + "download_if_missing": ["boolean"], + } +) def fetch_lfw_pairs( *, subset="train", diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 7f8fe0f2717ab..686ce3c1be6b6 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -124,6 +124,7 @@ def _check_function_param_validation( "sklearn.datasets.fetch_california_housing", "sklearn.datasets.fetch_covtype", "sklearn.datasets.fetch_kddcup99", + "sklearn.datasets.fetch_lfw_pairs", "sklearn.datasets.fetch_lfw_people", "sklearn.datasets.fetch_olivetti_faces", "sklearn.datasets.load_svmlight_file", From 05f3bdf10a68c840109110698a6f5f40b6a3906d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Thu, 16 Mar 2023 15:02:46 +0100 Subject: [PATCH 053/230] MAINT Parameters validation for metrics.classification_report (#25868) --- sklearn/metrics/_classification.py | 17 ++++++++++++++++- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/sklearn/metrics/_classification.py b/sklearn/metrics/_classification.py index 5fb5c0c3e69e6..187863e44515f 100644 --- a/sklearn/metrics/_classification.py +++ b/sklearn/metrics/_classification.py @@ -2350,6 +2350,21 @@ def balanced_accuracy_score(y_true, y_pred, *, sample_weight=None, adjusted=Fals return score +@validate_params( + { + "y_true": ["array-like", "sparse matrix"], + "y_pred": ["array-like", "sparse matrix"], + "labels": ["array-like", None], + "target_names": ["array-like", None], + "sample_weight": ["array-like", None], + "digits": [Interval(Integral, 0, None, closed="left")], + "output_dict": ["boolean"], + "zero_division": [ + Options(Real, {0, 1}), + StrOptions({"warn"}), + ], + } +) def classification_report( y_true, y_pred, @@ -2376,7 +2391,7 @@ def classification_report( labels : array-like of shape (n_labels,), default=None Optional list of label indices to include in the report. - target_names : list of str of shape (n_labels,), default=None + target_names : array-like of shape (n_labels,), default=None Optional display names matching the labels (same order). sample_weight : array-like of shape (n_samples,), default=None diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 686ce3c1be6b6..2fa93fdfb6adf 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -151,6 +151,7 @@ def _check_function_param_validation( "sklearn.metrics.balanced_accuracy_score", "sklearn.metrics.brier_score_loss", "sklearn.metrics.class_likelihood_ratios", + "sklearn.metrics.classification_report", "sklearn.metrics.cluster.contingency_matrix", "sklearn.metrics.cohen_kappa_score", "sklearn.metrics.confusion_matrix", From 08b8f763f2776f0767cb7ce47b87b5d4846c7fc6 Mon Sep 17 00:00:00 2001 From: Olivier Grisel Date: Thu, 16 Mar 2023 15:16:39 +0100 Subject: [PATCH 054/230] Empty commit From 9200411d7a889c5b00590946d8a656e26c6e8d8b Mon Sep 17 00:00:00 2001 From: Guillaume Lemaitre Date: Thu, 16 Mar 2023 15:20:44 +0100 Subject: [PATCH 055/230] DOC fix docstring dtype parameter in OrdinalEncoder (#25877) --- sklearn/preprocessing/_encoders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/preprocessing/_encoders.py b/sklearn/preprocessing/_encoders.py index 7df0584ba9d5b..53228c7b1f19a 100644 --- a/sklearn/preprocessing/_encoders.py +++ b/sklearn/preprocessing/_encoders.py @@ -1182,7 +1182,7 @@ class OrdinalEncoder(OneToOneFeatureMixin, _BaseEncoder): The used categories can be found in the ``categories_`` attribute. - dtype : number type, default np.float64 + dtype : number type, default=np.float64 Desired dtype of output. handle_unknown : {'error', 'use_encoded_value'}, default='error' From 23f969497409970f96e88eedf9663a82a1487138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:12:37 +0100 Subject: [PATCH 056/230] MAINT Clean up depreacted "log" loss of SGDClassifier for 1.3 (#25865) --- sklearn/linear_model/_stochastic_gradient.py | 26 ++++---------------- sklearn/linear_model/tests/test_sgd.py | 26 +------------------- 2 files changed, 6 insertions(+), 46 deletions(-) diff --git a/sklearn/linear_model/_stochastic_gradient.py b/sklearn/linear_model/_stochastic_gradient.py index 006bfc73da63e..ff6878d5e1686 100644 --- a/sklearn/linear_model/_stochastic_gradient.py +++ b/sklearn/linear_model/_stochastic_gradient.py @@ -158,14 +158,6 @@ def _more_validate_params(self, for_partial_fit=False): self._get_penalty_type(self.penalty) self._get_learning_rate_type(self.learning_rate) - # TODO(1.3): remove "log" - if self.loss == "log": - warnings.warn( - "The loss 'log' was deprecated in v1.1 and will be removed in version " - "1.3. Use `loss='log_loss'` which is equivalent.", - FutureWarning, - ) - def _get_loss_function(self, loss): """Get concrete ``LossFunction`` object for str ``loss``.""" loss_ = self.loss_functions[loss] @@ -501,13 +493,11 @@ def _get_plain_sgd_function(input_dtype): class BaseSGDClassifier(LinearClassifierMixin, BaseSGD, metaclass=ABCMeta): - # TODO(1.3): Remove "log"" loss_functions = { "hinge": (Hinge, 1.0), "squared_hinge": (SquaredHinge, 1.0), "perceptron": (Hinge, 0.0), "log_loss": (Log,), - "log": (Log,), "modified_huber": (ModifiedHuber,), "squared_error": (SquaredLoss,), "huber": (Huber, DEFAULT_EPSILON), @@ -517,7 +507,7 @@ class BaseSGDClassifier(LinearClassifierMixin, BaseSGD, metaclass=ABCMeta): _parameter_constraints: dict = { **BaseSGD._parameter_constraints, - "loss": [StrOptions(set(loss_functions), deprecated={"log"})], + "loss": [StrOptions(set(loss_functions))], "early_stopping": ["boolean"], "validation_fraction": [Interval(Real, 0, 1, closed="neither")], "n_iter_no_change": [Interval(Integral, 1, None, closed="left")], @@ -950,7 +940,7 @@ class SGDClassifier(BaseSGDClassifier): Parameters ---------- - loss : {'hinge', 'log_loss', 'log', 'modified_huber', 'squared_hinge',\ + loss : {'hinge', 'log_loss', 'modified_huber', 'squared_hinge',\ 'perceptron', 'squared_error', 'huber', 'epsilon_insensitive',\ 'squared_epsilon_insensitive'}, default='hinge' The loss function to be used. @@ -958,7 +948,7 @@ class SGDClassifier(BaseSGDClassifier): - 'hinge' gives a linear SVM. - 'log_loss' gives logistic regression, a probabilistic classifier. - 'modified_huber' is another smooth loss that brings tolerance to - outliers as well as probability estimates. + outliers as well as probability estimates. - 'squared_hinge' is like hinge but is quadratically penalized. - 'perceptron' is the linear loss used by the perceptron algorithm. - The other losses, 'squared_error', 'huber', 'epsilon_insensitive' and @@ -969,10 +959,6 @@ class SGDClassifier(BaseSGDClassifier): More details about the losses formulas can be found in the :ref:`User Guide `. - .. deprecated:: 1.1 - The loss 'log' was deprecated in v1.1 and will be removed - in version 1.3. Use `loss='log_loss'` which is equivalent. - penalty : {'l2', 'l1', 'elasticnet', None}, default='l2' The penalty (aka regularization term) to be used. Defaults to 'l2' which is the standard regularizer for linear SVM models. 'l1' and @@ -1249,8 +1235,7 @@ def __init__( ) def _check_proba(self): - # TODO(1.3): Remove "log" - if self.loss not in ("log_loss", "log", "modified_huber"): + if self.loss not in ("log_loss", "modified_huber"): raise AttributeError( "probability estimates are not available for loss=%r" % self.loss ) @@ -1295,8 +1280,7 @@ def predict_proba(self, X): """ check_is_fitted(self) - # TODO(1.3): Remove "log" - if self.loss in ("log_loss", "log"): + if self.loss == "log_loss": return self._predict_proba_lr(X) elif self.loss == "modified_huber": diff --git a/sklearn/linear_model/tests/test_sgd.py b/sklearn/linear_model/tests/test_sgd.py index c5f0d4507227e..51c166869f174 100644 --- a/sklearn/linear_model/tests/test_sgd.py +++ b/sklearn/linear_model/tests/test_sgd.py @@ -716,8 +716,7 @@ def test_sgd_predict_proba_method_access(klass): # details. for loss in linear_model.SGDClassifier.loss_functions: clf = SGDClassifier(loss=loss) - # TODO(1.3): Remove "log" - if loss in ("log_loss", "log", "modified_huber"): + if loss in ("log_loss", "modified_huber"): assert hasattr(clf, "predict_proba") assert hasattr(clf, "predict_log_proba") else: @@ -2060,29 +2059,6 @@ def test_SGDClassifier_fit_for_all_backends(backend): assert_array_almost_equal(clf_sequential.coef_, clf_parallel.coef_) -# TODO(1.3): Remove -@pytest.mark.parametrize( - "old_loss, new_loss, Estimator", - [ - ("log", "log_loss", linear_model.SGDClassifier), - ], -) -def test_loss_deprecated(old_loss, new_loss, Estimator): - - # Note: class BaseSGD calls self._validate_params() in __init__, therefore - # even instantiation of class raises FutureWarning for deprecated losses. - with pytest.warns(FutureWarning, match=f"The loss '{old_loss}' was deprecated"): - est1 = Estimator(loss=old_loss, random_state=0) - est1.fit(X, Y) - - est2 = Estimator(loss=new_loss, random_state=0) - est2.fit(X, Y) - if hasattr(est1, "predict_proba"): - assert_allclose(est1.predict_proba(X), est2.predict_proba(X)) - else: - assert_allclose(est1.predict(X), est2.predict(X)) - - @pytest.mark.parametrize( "Estimator", [linear_model.SGDClassifier, linear_model.SGDRegressor] ) From d13af4cc8ab4b86ecdc89d673f62d7b97b826a3c Mon Sep 17 00:00:00 2001 From: "Thomas J. Fan" Date: Thu, 16 Mar 2023 11:59:20 -0400 Subject: [PATCH 057/230] ENH Adds TargetEncoder (#25334) Co-authored-by: Andreas Mueller Co-authored-by: Olivier Grisel Co-authored-by: Jovan Stojanovic <62058944+jovan-stojanovic@users.noreply.github.com> Co-authored-by: Guillaume Lemaitre --- .../target_encoder_cross_validation.svg | 3 + doc/modules/classes.rst | 1 + doc/modules/preprocessing.rst | 86 +++ doc/whats_new/v1.3.rst | 4 + examples/preprocessing/plot_target_encoder.py | 227 ++++++++ setup.py | 6 + sklearn/preprocessing/__init__.py | 2 + sklearn/preprocessing/_encoders.py | 8 +- sklearn/preprocessing/_target_encoder.py | 341 +++++++++++ .../preprocessing/_target_encoder_fast.pyx | 168 ++++++ .../tests/test_target_encoder.py | 549 ++++++++++++++++++ 11 files changed, 1394 insertions(+), 1 deletion(-) create mode 100644 doc/images/target_encoder_cross_validation.svg create mode 100644 examples/preprocessing/plot_target_encoder.py create mode 100644 sklearn/preprocessing/_target_encoder.py create mode 100644 sklearn/preprocessing/_target_encoder_fast.pyx create mode 100644 sklearn/preprocessing/tests/test_target_encoder.py diff --git a/doc/images/target_encoder_cross_validation.svg b/doc/images/target_encoder_cross_validation.svg new file mode 100644 index 0000000000000..769d5a8affb2e --- /dev/null +++ b/doc/images/target_encoder_cross_validation.svg @@ -0,0 +1,3 @@ + + +
Fold1
Fold1
Train
Train
Train
Train
Train
Train
Train
Train
Train
Train
Fold2
Fold2
Train
Train
Train
Train
Train
Train
Train
Train
Train
Train
Fold3
Fold3
Train
Train
Train
Train
Train
Train
Train
Train
Train
Train
Fold4
Fold4
Train
Train
Train
Train
Train
Train
Train
Train
Train
Train
Fold5
Fold5
Fold1
Fold1
Fold2
Fold2
Fold3
Fold3
Fold4
Fold4
Fold5
Fold5
Combine
Folds
Combine...
Text is not SVG - cannot display
diff --git a/doc/modules/classes.rst b/doc/modules/classes.rst index 23d689fc92a74..ed934d3a9fb84 100644 --- a/doc/modules/classes.rst +++ b/doc/modules/classes.rst @@ -1438,6 +1438,7 @@ details. preprocessing.RobustScaler preprocessing.SplineTransformer preprocessing.StandardScaler + preprocessing.TargetEncoder .. autosummary:: :toctree: generated/ diff --git a/doc/modules/preprocessing.rst b/doc/modules/preprocessing.rst index e7d3969d7a212..86f2d29cf4ecf 100644 --- a/doc/modules/preprocessing.rst +++ b/doc/modules/preprocessing.rst @@ -830,6 +830,92 @@ lexicon order. >>> enc.infrequent_categories_ [array(['b', 'c'], dtype=object)] +.. _target_encoder: + +Target Encoder +-------------- + +.. currentmodule:: sklearn.preprocessing + +The :class:`TargetEncoder` uses the target mean conditioned on the categorical +feature for encoding unordered categories, i.e. nominal categories [PAR]_ +[MIC]_. This encoding scheme is useful with categorical features with high +cardinality, where one-hot encoding would inflate the feature space making it +more expensive for a downstream model to process. A classical example of high +cardinality categories are location based such as zip code or region. For the +binary classification target, the target encoding is given by: + +.. math:: + S_i = \lambda_i\frac{n_{iY}}{n_i} + (1 - \lambda_i)\frac{n_y}{n} + +where :math:`S_i` is the encoding for category :math:`i`, :math:`n_{iY}` is the +number of observations with :math:`Y=1` with category :math:`i`, :math:`n_i` is +the number of observations with category :math:`i`, :math:`n_y` is the number of +observations with :math:`Y=1`, :math:`n` is the number of observations, and +:math:`\lambda_i` is a shrinkage factor. The shrinkage factor is given by: + +.. math:: + \lambda_i = \frac{n_i}{m + n_i} + +where :math:`m` is a smoothing factor, which is controlled with the `smooth` +parameter in :class:`TargetEncoder`. Large smoothing factors will put more +weight on the global mean. When `smooth="auto"`, the smoothing factor is +computed as an empirical Bayes estimate: :math:`m=\sigma_c^2/\tau^2`, where +:math:`\sigma_i^2` is the variance of `y` with category :math:`i` and +:math:`\tau^2` is the global variance of `y`. + +For continuous targets, the formulation is similar to binary classification: + +.. math:: + S_i = \lambda_i\frac{\sum_{k\in L_i}y_k}{n_i} + (1 - \lambda_i)\frac{\sum_{k=1}^{n}y_k}{n} + +where :math:`L_i` is the set of observations for which :math:`X=X_i` and +:math:`n_i` is the cardinality of :math:`L_i`. + +:meth:`~TargetEncoder.fit_transform` internally relies on a cross validation +scheme to prevent information from the target from leaking into the train-time +representation for non-informative high-cardinality categorical variables and +help prevent the downstream model to overfit spurious correlations. Note that +as a result, `fit(X, y).transform(X)` does not equal `fit_transform(X, y)`. In +:meth:`~TargetEncoder.fit_transform`, the training data is split into multiple +folds and encodes each fold by using the encodings trained on the other folds. +After cross validation is complete in :meth:`~TargetEncoder.fit_transform`, the +target encoder learns one final encoding on the whole training set. This final +encoding is used to encode categories in :meth:`~TargetEncoder.transform`. The +following diagram shows the cross validation scheme in +:meth:`~TargetEncoder.fit_transform` with the default `cv=5`: + +.. image:: ../images/target_encoder_cross_validation.svg + :width: 600 + :align: center + +The :meth:`~TargetEncoder.fit` method does **not** use any cross validation +schemes and learns one encoding on the entire training set, which is used to +encode categories in :meth:`~TargetEncoder.transform`. +:meth:`~TargetEncoder.fit`'s one encoding is the same as the final encoding +learned in :meth:`~TargetEncoder.fit_transform`. + +.. note:: + :class:`TargetEncoder` considers missing values, such as `np.nan` or `None`, + as another category and encodes them like any other category. Categories + that are not seen during `fit` are encoded with the target mean, i.e. + `target_mean_`. + +.. topic:: Examples: + + * :ref:`sphx_glr_auto_examples_preprocessing_plot_target_encoder.py` + +.. topic:: References + + .. [MIC] :doi:`Micci-Barreca, Daniele. "A preprocessing scheme for high-cardinality + categorical attributes in classification and prediction problems" + SIGKDD Explor. Newsl. 3, 1 (July 2001), 27–32. <10.1145/507533.507538>` + + .. [PAR] :doi:`Pargent, F., Pfisterer, F., Thomas, J. et al. "Regularized target + encoding outperforms traditional methods in supervised machine learning with + high cardinality features" Comput Stat 37, 2671–2692 (2022) + <10.1007/s00180-022-01207-6>` + .. _preprocessing_discretization: Discretization diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 439b348ce2610..cf5003d04fbf2 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -322,6 +322,10 @@ Changelog :mod:`sklearn.preprocessing` ............................ +- |MajorFeature| Introduces :class:`preprocessing.TargetEncoder` which is a + categorical encoding based on target mean conditioned on the value of the + category. :pr:`25334` by `Thomas Fan`_. + - |Enhancement| Adds a `feature_name_combiner` parameter to :class:`preprocessing.OneHotEncoder`. This specifies a custom callable to create feature names to be returned by :meth:`get_feature_names_out`. diff --git a/examples/preprocessing/plot_target_encoder.py b/examples/preprocessing/plot_target_encoder.py new file mode 100644 index 0000000000000..a50f0199e5ba8 --- /dev/null +++ b/examples/preprocessing/plot_target_encoder.py @@ -0,0 +1,227 @@ +""" +============================================ +Comparing Target Encoder with Other Encoders +============================================ + +.. currentmodule:: sklearn.preprocessing + +The :class:`TargetEncoder` uses the value of the target to encode each +categorical feature. In this example, we will compare three different approaches +for handling categorical features: :class:`TargetEncoder`, +:class:`OrdinalEncoder`, :class:`OneHotEncoder` and dropping the category. + +.. note:: + `fit(X, y).transform(X)` does not equal `fit_transform(X, y)` because a + cross-validation scheme is used in `fit_transform` for encoding. See the + :ref:`User Guide `. for details. +""" + +# %% +# Loading Data from OpenML +# ======================== +# First, we load the wine reviews dataset, where the target is the points given +# be a reviewer: +from sklearn.datasets import fetch_openml + +wine_reviews = fetch_openml(data_id=42074, as_frame=True, parser="pandas") + +df = wine_reviews.frame +df.head() + +# %% +# For this example, we use the following subset of numerical and categorical +# features in the data. The target are continuous values from 80 to 100: +numerical_features = ["price"] +categorical_features = [ + "country", + "province", + "region_1", + "region_2", + "variety", + "winery", +] +target_name = "points" + +X = df[numerical_features + categorical_features] +y = df[target_name] + +_ = y.hist() + +# %% +# Training and Evaluating Pipelines with Different Encoders +# ========================================================= +# In this section, we will evaluate pipelines with +# :class:`~sklearn.ensemble.HistGradientBoostingRegressor` with different encoding +# strategies. First, we list out the encoders we will be using to preprocess +# the categorical features: +from sklearn.compose import ColumnTransformer +from sklearn.preprocessing import OrdinalEncoder +from sklearn.preprocessing import OneHotEncoder +from sklearn.preprocessing import TargetEncoder + +categorical_preprocessors = [ + ("drop", "drop"), + ("ordinal", OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=-1)), + ( + "one_hot", + OneHotEncoder(handle_unknown="ignore", max_categories=20, sparse_output=False), + ), + ("target", TargetEncoder(target_type="continuous")), +] + +# %% +# Next, we evaluate the models using cross validation and record the results: +from sklearn.pipeline import make_pipeline +from sklearn.model_selection import cross_validate +from sklearn.ensemble import HistGradientBoostingRegressor + +n_cv_folds = 3 +max_iter = 20 +results = [] + + +def evaluate_model_and_store(name, pipe): + result = cross_validate( + pipe, + X, + y, + scoring="neg_root_mean_squared_error", + cv=n_cv_folds, + return_train_score=True, + ) + rmse_test_score = -result["test_score"] + rmse_train_score = -result["train_score"] + results.append( + { + "preprocessor": name, + "rmse_test_mean": rmse_test_score.mean(), + "rmse_test_std": rmse_train_score.std(), + "rmse_train_mean": rmse_train_score.mean(), + "rmse_train_std": rmse_train_score.std(), + } + ) + + +for name, categorical_preprocessor in categorical_preprocessors: + preprocessor = ColumnTransformer( + [ + ("numerical", "passthrough", numerical_features), + ("categorical", categorical_preprocessor, categorical_features), + ] + ) + pipe = make_pipeline( + preprocessor, HistGradientBoostingRegressor(random_state=0, max_iter=max_iter) + ) + evaluate_model_and_store(name, pipe) + + +# %% +# Native Categorical Feature Support +# ================================== +# In this section, we build and evaluate a pipeline that uses native categorical +# feature support in :class:`~sklearn.ensemble.HistGradientBoostingRegressor`, +# which only supports up to 255 unique categories. In our dataset, the most of +# the categorical features have more than 255 unique categories: +n_unique_categories = df[categorical_features].nunique().sort_values(ascending=False) +n_unique_categories + +# %% +# To workaround the limitation above, we group the categorical features into +# low cardinality and high cardinality features. The high cardinality features +# will be target encoded and the low cardinality features will use the native +# categorical feature in gradient boosting. +high_cardinality_features = n_unique_categories[n_unique_categories > 255].index +low_cardinality_features = n_unique_categories[n_unique_categories <= 255].index +mixed_encoded_preprocessor = ColumnTransformer( + [ + ("numerical", "passthrough", numerical_features), + ( + "high_cardinality", + TargetEncoder(target_type="continuous"), + high_cardinality_features, + ), + ( + "low_cardinality", + OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=-1), + low_cardinality_features, + ), + ], + verbose_feature_names_out=False, +) + +# The output of the of the preprocessor must be set to pandas so the +# gradient boosting model can detect the low cardinality features. +mixed_encoded_preprocessor.set_output(transform="pandas") +mixed_pipe = make_pipeline( + mixed_encoded_preprocessor, + HistGradientBoostingRegressor( + random_state=0, max_iter=max_iter, categorical_features=low_cardinality_features + ), +) +mixed_pipe + +# %% +# Finally, we evaluate the pipeline using cross validation and record the results: +evaluate_model_and_store("mixed_target", mixed_pipe) + +# %% +# Plotting the Results +# ==================== +# In this section, we display the results by plotting the test and train scores: +import matplotlib.pyplot as plt +import pandas as pd + +results_df = ( + pd.DataFrame(results).set_index("preprocessor").sort_values("rmse_test_mean") +) + +fig, (ax1, ax2) = plt.subplots( + 1, 2, figsize=(12, 8), sharey=True, constrained_layout=True +) +xticks = range(len(results_df)) +name_to_color = dict( + zip((r["preprocessor"] for r in results), ["C0", "C1", "C2", "C3", "C4"]) +) + +for subset, ax in zip(["test", "train"], [ax1, ax2]): + mean, std = f"rmse_{subset}_mean", f"rmse_{subset}_std" + data = results_df[[mean, std]].sort_values(mean) + ax.bar( + x=xticks, + height=data[mean], + yerr=data[std], + width=0.9, + color=[name_to_color[name] for name in data.index], + ) + ax.set( + title=f"RMSE ({subset.title()})", + xlabel="Encoding Scheme", + xticks=xticks, + xticklabels=data.index, + ) + +# %% +# When evaluating the predictive performance on the test set, dropping the +# categories perform the worst and the target encoders performs the best. This +# can be explained as follows: +# +# - Dropping the categorical features makes the pipeline less expressive and +# underfitting as a result; +# - Due to the high cardinality and to reduce the training time, the one-hot +# encoding scheme uses `max_categories=20` which prevents the features from +# expanding too much, which can result in underfitting. +# - If we had not set `max_categories=20`, the one-hot encoding scheme would have +# likely made the pipeline overfitting as the number of features explodes with rare +# category occurrences that are correlated with the target by chance (on the training +# set only); +# - The ordinal encoding imposes an arbitrary order to the features which are then +# treated as numerical values by the +# :class:`~sklearn.ensemble.HistGradientBoostingRegressor`. Since this +# model groups numerical features in 256 bins per feature, many unrelated categories +# can be grouped together and as a result overall pipeline can underfit; +# - When using the target encoder, the same binning happens, but since the encoded +# values are statistically ordered by marginal association with the target variable, +# the binning use by the :class:`~sklearn.ensemble.HistGradientBoostingRegressor` +# makes sense and leads to good results: the combination of smoothed target +# encoding and binning works as a good regularizing strategy against +# overfitting while not limiting the expressiveness of the pipeline too much. diff --git a/setup.py b/setup.py index 72172408110de..f5522600f623f 100755 --- a/setup.py +++ b/setup.py @@ -295,6 +295,12 @@ def check_package_status(package, min_version): ], "preprocessing": [ {"sources": ["_csr_polynomial_expansion.pyx"], "include_np": True}, + { + "sources": ["_target_encoder_fast.pyx"], + "include_np": True, + "language": "c++", + "extra_compile_args": ["-std=c++11"], + }, ], "neighbors": [ {"sources": ["_ball_tree.pyx"], "include_np": True}, diff --git a/sklearn/preprocessing/__init__.py b/sklearn/preprocessing/__init__.py index ccea91545a467..221c0701cb1d3 100644 --- a/sklearn/preprocessing/__init__.py +++ b/sklearn/preprocessing/__init__.py @@ -26,6 +26,7 @@ from ._encoders import OneHotEncoder from ._encoders import OrdinalEncoder +from ._target_encoder import TargetEncoder from ._label import label_binarize from ._label import LabelBinarizer @@ -56,6 +57,7 @@ "RobustScaler", "SplineTransformer", "StandardScaler", + "TargetEncoder", "add_dummy_feature", "PolynomialFeatures", "binarize", diff --git a/sklearn/preprocessing/_encoders.py b/sklearn/preprocessing/_encoders.py index 53228c7b1f19a..f985a4a4e18b3 100644 --- a/sklearn/preprocessing/_encoders.py +++ b/sklearn/preprocessing/_encoders.py @@ -415,6 +415,7 @@ class OneHotEncoder(_BaseEncoder): -------- OrdinalEncoder : Performs an ordinal (integer) encoding of the categorical features. + TargetEncoder : Encodes categorical features using the target. sklearn.feature_extraction.DictVectorizer : Performs a one-hot encoding of dictionary items (also handles string-valued features). sklearn.feature_extraction.FeatureHasher : Performs an approximate one-hot @@ -1229,7 +1230,12 @@ class OrdinalEncoder(OneToOneFeatureMixin, _BaseEncoder): See Also -------- - OneHotEncoder : Performs a one-hot encoding of categorical features. + OneHotEncoder : Performs a one-hot encoding of categorical features. This encoding + is suitable for low to medium cardinality categorical variables, both in + supervised and unsupervised settings. + TargetEncoder : Encodes categorical features using supervised signal + in a classification or regression pipeline. This encoding is typically + suitable for high cardinality categorical variables. LabelEncoder : Encodes target labels with values between 0 and ``n_classes-1``. diff --git a/sklearn/preprocessing/_target_encoder.py b/sklearn/preprocessing/_target_encoder.py new file mode 100644 index 0000000000000..1ae5102afcd59 --- /dev/null +++ b/sklearn/preprocessing/_target_encoder.py @@ -0,0 +1,341 @@ +import numpy as np + +from numbers import Real, Integral + +from ._encoders import _BaseEncoder +from ..base import OneToOneFeatureMixin +from ._target_encoder_fast import _fit_encoding_fast +from ._target_encoder_fast import _fit_encoding_fast_auto_smooth +from ..utils.validation import _check_y, check_consistent_length +from ..utils.multiclass import type_of_target +from ..utils._param_validation import Interval, StrOptions + + +class TargetEncoder(OneToOneFeatureMixin, _BaseEncoder): + """Target Encoder for regression and classification targets. + + Each category is encoded based on a shrinked estimate of the average target + values for observations belonging to the category. The encoding scheme mixes + the global target mean with the target mean conditioned on the value of the + category. [MIC]_ + + :class:`TargetEncoder` considers missing values, such as `np.nan` or `None`, + as another category and encodes them like any other category. Categories + that are not seen during :meth:`fit` are encoded with the target mean, i.e. + `target_mean_`. + + Read more in the :ref:`User Guide `. + + .. note:: + `fit(X, y).transform(X)` does not equal `fit_transform(X, y)` because a + cross-validation scheme is used in `fit_transform` for encoding. See the + :ref:`User Guide `. for details. + + .. versionadded:: 1.3 + + Parameters + ---------- + categories : "auto" or a list of array-like, default="auto" + Categories (unique values) per feature: + + - `"auto"` : Determine categories automatically from the training data. + - list : `categories[i]` holds the categories expected in the i-th column. The + passed categories should not mix strings and numeric values within a single + feature, and should be sorted in case of numeric values. + + The used categories is stored in the `categories_` fitted attribute. + + target_type : {"auto", "continuous", "binary"}, default="auto" + Type of target. + + - `"auto"` : Type of target is inferred with + :func:`~sklearn.utils.multiclass.type_of_target`. + - `"continuous"` : Continuous target + - `"binary"` : Binary target + + .. note:: + The type of target inferred with `"auto"` may not be the desired target + type used for modeling. For example, if the target consistent of integers + between 0 and 100, then :func:`~sklearn.utils.multiclass.type_of_target` + will infer the target as `"multiclass"`. In this case, setting + `target_type="continuous"` will understand the target as a regression + problem. The `target_type_` attribute gives the target type used by the + encoder. + + smooth : "auto" or float, default="auto" + The amount of mixing of the categorical encoding with the global target mean. A + larger `smooth` value will put more weight on the global target mean. + If `"auto"`, then `smooth` is set to an empirical Bayes estimate. + + cv : int, default=5 + Determines the number of folds in the cross-validation strategy used in + :meth:`fit_transform`. For classification targets, `StratifiedKFold` is used + and for continuous targets, `KFold` is used. + + shuffle : bool, default=True + Whether to shuffle the data in :meth:`fit_transform` before splitting into + batches. Note that the samples within each split will not be shuffled. + + random_state : int, RandomState instance or None, default=None + When `shuffle` is True, `random_state` affects the ordering of the + indices, which controls the randomness of each fold. Otherwise, this + parameter has no effect. + Pass an int for reproducible output across multiple function calls. + See :term:`Glossary `. + + Attributes + ---------- + encodings_ : list of shape (n_features,) of ndarray + For feature `i`, `encodings_[i]` is the encoding matching the + categories listed in `categories_[i]`. + + categories_ : list of shape (n_features,) of ndarray + The categories of each feature determined during fitting + (in order of the features in `X` and corresponding with the output + of :meth:`transform`). + + target_type_ : str + Type of target. + + target_mean_ : float + The overall mean of the target. This value is only used in :meth:`transform` + to encode categories. + + n_features_in_ : int + Number of features seen during :term:`fit`. + + feature_names_in_ : ndarray of shape (`n_features_in_`,) + Names of features seen during :term:`fit`. Defined only when `X` + has feature names that are all strings. + + See Also + -------- + OrdinalEncoder : Performs an ordinal (integer) encoding of the categorical features. + Contrary to TargetEncoder, this encoding is not supervised. Treating the + resulting encoding as a numerical features therefore lead arbitrarily + ordered values and therefore typically lead to lower predictive performance + when used as preprocessing for a classifier or regressor. + OneHotEncoder : Performs a one-hot encoding of categorical features. This + unsupervised encoding is better suited for low cardinality categorical + variables as it generate one new feature per unique category. + + References + ---------- + .. [MIC] :doi:`Micci-Barreca, Daniele. "A preprocessing scheme for high-cardinality + categorical attributes in classification and prediction problems" + SIGKDD Explor. Newsl. 3, 1 (July 2001), 27–32. <10.1145/507533.507538>` + + Examples + -------- + With `smooth="auto"`, the smoothing parameter is set to an empirical Bayes estimate: + + >>> import numpy as np + >>> from sklearn.preprocessing import TargetEncoder + >>> X = np.array([["dog"] * 20 + ["cat"] * 30 + ["snake"] * 38], dtype=object).T + >>> y = [90.3] * 5 + [80.1] * 15 + [20.4] * 5 + [20.1] * 25 + [21.2] * 8 + [49] * 30 + >>> enc_auto = TargetEncoder(smooth="auto") + >>> X_trans = enc_auto.fit_transform(X, y) + + >>> # A high `smooth` parameter puts more weight on global mean on the categorical + >>> # encodings: + >>> enc_high_smooth = TargetEncoder(smooth=5000.0).fit(X, y) + >>> enc_high_smooth.target_mean_ + 44... + >>> enc_high_smooth.encodings_ + [array([44..., 44..., 44...])] + + >>> # On the other hand, a low `smooth` parameter puts more weight on target + >>> # conditioned on the value of the categorical: + >>> enc_low_smooth = TargetEncoder(smooth=1.0).fit(X, y) + >>> enc_low_smooth.encodings_ + [array([20..., 80..., 43...])] + """ + + _parameter_constraints: dict = { + "categories": [StrOptions({"auto"}), list], + "target_type": [StrOptions({"auto", "continuous", "binary"})], + "smooth": [StrOptions({"auto"}), Interval(Real, 0, None, closed="left")], + "cv": [Interval(Integral, 2, None, closed="left")], + "shuffle": ["boolean"], + "random_state": ["random_state"], + } + + def __init__( + self, + categories="auto", + target_type="auto", + smooth="auto", + cv=5, + shuffle=True, + random_state=None, + ): + self.categories = categories + self.smooth = smooth + self.target_type = target_type + self.cv = cv + self.shuffle = shuffle + self.random_state = random_state + + def fit(self, X, y): + """Fit the :class:`TargetEncoder` to X and y. + + Parameters + ---------- + X : array-like of shape (n_samples, n_features) + The data to determine the categories of each feature. + + y : array-like of shape (n_samples,) + The target data used to encode the categories. + + Returns + ------- + self : object + Fitted encoder. + """ + self._validate_params() + self._fit_encodings_all(X, y) + return self + + def fit_transform(self, X, y): + """Fit :class:`TargetEncoder` and transform X with the target encoding. + + .. note:: + `fit(X, y).transform(X)` does not equal `fit_transform(X, y)` because a + cross-validation scheme is used in `fit_transform` for encoding. See the + :ref:`User Guide `. for details. + + Parameters + ---------- + X : array-like of shape (n_samples, n_features) + The data to determine the categories of each feature. + + y : array-like of shape (n_samples,) + The target data used to encode the categories. + + Returns + ------- + X_trans : ndarray of shape (n_samples, n_features) + Transformed input. + """ + from ..model_selection import KFold, StratifiedKFold # avoid circular import + + self._validate_params() + X_ordinal, X_known_mask, y, n_categories = self._fit_encodings_all(X, y) + + # The cv splitter is voluntarily restricted to *KFold to enforce non + # overlapping validation folds, otherwise the fit_transform output will + # not be well-specified. + if self.target_type_ == "continuous": + cv = KFold(self.cv, shuffle=self.shuffle, random_state=self.random_state) + else: + cv = StratifiedKFold( + self.cv, shuffle=self.shuffle, random_state=self.random_state + ) + + X_out = np.empty_like(X_ordinal, dtype=np.float64) + X_unknown_mask = ~X_known_mask + + for train_idx, test_idx in cv.split(X, y): + X_train, y_train = X_ordinal[train_idx, :], y[train_idx] + y_mean = np.mean(y_train) + + if self.smooth == "auto": + y_variance = np.var(y_train) + encodings = _fit_encoding_fast_auto_smooth( + X_train, y_train, n_categories, y_mean, y_variance + ) + else: + encodings = _fit_encoding_fast( + X_train, y_train, n_categories, self.smooth, y_mean + ) + self._transform_X_ordinal( + X_out, X_ordinal, X_unknown_mask, test_idx, encodings, y_mean + ) + return X_out + + def transform(self, X): + """Transform X with the target encoding. + + .. note:: + `fit(X, y).transform(X)` does not equal `fit_transform(X, y)` because a + cross-validation scheme is used in `fit_transform` for encoding. See the + :ref:`User Guide `. for details. + + Parameters + ---------- + X : array-like of shape (n_samples, n_features) + The data to determine the categories of each feature. + + Returns + ------- + X_trans : ndarray of shape (n_samples, n_features) + Transformed input. + """ + X_ordinal, X_valid = self._transform( + X, handle_unknown="ignore", force_all_finite="allow-nan" + ) + X_out = np.empty_like(X_ordinal, dtype=np.float64) + self._transform_X_ordinal( + X_out, + X_ordinal, + ~X_valid, + slice(None), + self.encodings_, + self.target_mean_, + ) + return X_out + + def _fit_encodings_all(self, X, y): + """Fit a target encoding with all the data.""" + from ..preprocessing import LabelEncoder # avoid circular import + + check_consistent_length(X, y) + self._fit(X, handle_unknown="ignore", force_all_finite="allow-nan") + + if self.target_type == "auto": + accepted_target_types = ("binary", "continuous") + inferred_type_of_target = type_of_target(y, input_name="y") + if inferred_type_of_target not in accepted_target_types: + raise ValueError( + f"Target type was inferred to be {inferred_type_of_target!r}. Only" + f" {accepted_target_types} are supported." + ) + self.target_type_ = inferred_type_of_target + else: + self.target_type_ = self.target_type + + if self.target_type_ == "binary": + y = LabelEncoder().fit_transform(y) + else: # continuous + y = _check_y(y, y_numeric=True, estimator=self) + + self.target_mean_ = np.mean(y) + + X_ordinal, X_known_mask = self._transform( + X, handle_unknown="ignore", force_all_finite="allow-nan" + ) + n_categories = np.fromiter( + (len(category_for_feature) for category_for_feature in self.categories_), + dtype=np.int64, + count=len(self.categories_), + ) + if self.smooth == "auto": + y_variance = np.var(y) + self.encodings_ = _fit_encoding_fast_auto_smooth( + X_ordinal, y, n_categories, self.target_mean_, y_variance + ) + else: + self.encodings_ = _fit_encoding_fast( + X_ordinal, y, n_categories, self.smooth, self.target_mean_ + ) + + return X_ordinal, X_known_mask, y, n_categories + + @staticmethod + def _transform_X_ordinal( + X_out, X_ordinal, X_unknown_mask, indices, encodings, y_mean + ): + """Transform X_ordinal using encodings.""" + for f_idx, encoding in enumerate(encodings): + X_out[indices, f_idx] = encoding[X_ordinal[indices, f_idx]] + X_out[X_unknown_mask[:, f_idx], f_idx] = y_mean diff --git a/sklearn/preprocessing/_target_encoder_fast.pyx b/sklearn/preprocessing/_target_encoder_fast.pyx new file mode 100644 index 0000000000000..66f20dd1febf3 --- /dev/null +++ b/sklearn/preprocessing/_target_encoder_fast.pyx @@ -0,0 +1,168 @@ +cimport cython +from libc.math cimport isnan +from libc.string cimport memset +from libcpp.vector cimport vector + +cimport numpy as cnp +import numpy as np + +cnp.import_array() + +ctypedef fused INT_DTYPE: + cnp.int64_t + cnp.int32_t + +ctypedef fused Y_DTYPE: + cnp.int64_t + cnp.int32_t + cnp.float64_t + cnp.float32_t + +def _fit_encoding_fast( + INT_DTYPE[:, ::1] X_int, + Y_DTYPE[:] y, + cnp.int64_t[::1] n_categories, + double smooth, + double y_mean, +): + """Fit a target encoding on X_int and y. + + This implementation uses Eq 7 from [1] to compute the encoding. + As stated in the paper, Eq 7 is the same as Eq 3. + + [1]: Micci-Barreca, Daniele. "A preprocessing scheme for high-cardinality + categorical attributes in classification and prediction problems" + """ + cdef: + cnp.int64_t sample_idx, feat_idx, cat_idx, n_cats + INT_DTYPE X_int_tmp + int n_samples = X_int.shape[0] + int n_features = X_int.shape[1] + double smooth_sum = smooth * y_mean + cnp.int64_t max_n_cats = np.max(n_categories) + double[::1] sums = np.empty(max_n_cats, dtype=np.float64) + double[::1] counts = np.empty(max_n_cats, dtype=np.float64) + list encodings = [] + double[::1] current_encoding + # Gives access to encodings without gil + vector[double*] encoding_vec + + encoding_vec.resize(n_features) + for feat_idx in range(n_features): + current_encoding = np.empty(shape=n_categories[feat_idx], dtype=np.float64) + encoding_vec[feat_idx] = ¤t_encoding[0] + encodings.append(np.asarray(current_encoding)) + + with nogil: + for feat_idx in range(n_features): + n_cats = n_categories[feat_idx] + + for cat_idx in range(n_cats): + sums[cat_idx] = smooth_sum + counts[cat_idx] = smooth + + for sample_idx in range(n_samples): + X_int_tmp = X_int[sample_idx, feat_idx] + # -1 are unknown categories, which are not counted + if X_int_tmp == -1: + continue + sums[X_int_tmp] += y[sample_idx] + counts[X_int_tmp] += 1.0 + + for cat_idx in range(n_cats): + if counts[cat_idx] == 0: + encoding_vec[feat_idx][cat_idx] = y_mean + else: + encoding_vec[feat_idx][cat_idx] = sums[cat_idx] / counts[cat_idx] + + return encodings + + +def _fit_encoding_fast_auto_smooth( + INT_DTYPE[:, ::1] X_int, + Y_DTYPE[:] y, + cnp.int64_t[::1] n_categories, + double y_mean, + double y_variance, +): + """Fit a target encoding on X_int and y with auto smoothing. + + This implementation uses Eq 5 and 6 from [1]. + + [1]: Micci-Barreca, Daniele. "A preprocessing scheme for high-cardinality + categorical attributes in classification and prediction problems" + """ + cdef: + cnp.int64_t sample_idx, feat_idx, cat_idx, n_cats + INT_DTYPE X_int_tmp + double diff + int n_samples = X_int.shape[0] + int n_features = X_int.shape[1] + cnp.int64_t max_n_cats = np.max(n_categories) + double[::1] means = np.empty(max_n_cats, dtype=np.float64) + cnp.int64_t[::1] counts = np.empty(max_n_cats, dtype=np.int64) + double[::1] sum_of_squared_diffs = np.empty(max_n_cats, dtype=np.float64) + double lambda_ + list encodings = [] + double[::1] current_encoding + # Gives access to encodings without gil + vector[double*] encoding_vec + + encoding_vec.resize(n_features) + for feat_idx in range(n_features): + current_encoding = np.empty(shape=n_categories[feat_idx], dtype=np.float64) + encoding_vec[feat_idx] = ¤t_encoding[0] + encodings.append(np.asarray(current_encoding)) + + # TODO: parallelize this with OpenMP prange. When n_features >= n_threads, it's + # probably good to parallelize the outer loop. When n_features is too small, + # then it would probably better to parallelize the nested loops on n_samples and + # n_cats, but the code to handle thread-local temporary variables might be + # significantly more complex. + with nogil: + for feat_idx in range(n_features): + n_cats = n_categories[feat_idx] + + for cat_idx in range(n_cats): + means[cat_idx] = 0.0 + counts[cat_idx] = 0 + sum_of_squared_diffs[cat_idx] = 0.0 + + # first pass to compute the mean + for sample_idx in range(n_samples): + X_int_tmp = X_int[sample_idx, feat_idx] + + # -1 are unknown categories, which are not counted + if X_int_tmp == -1: + continue + counts[X_int_tmp] += 1 + means[X_int_tmp] += y[sample_idx] + + for cat_idx in range(n_cats): + means[cat_idx] /= counts[cat_idx] + + # second pass to compute the sum of squared differences + for sample_idx in range(n_samples): + X_int_tmp = X_int[sample_idx, feat_idx] + if X_int_tmp == -1: + continue + diff = y[sample_idx] - means[X_int_tmp] + sum_of_squared_diffs[X_int_tmp] += diff * diff + + for cat_idx in range(n_cats): + lambda_ = ( + y_variance * counts[cat_idx] / + (y_variance * counts[cat_idx] + sum_of_squared_diffs[cat_idx] / + counts[cat_idx]) + ) + if isnan(lambda_): + # A nan can happen when: + # 1. counts[cat_idx] == 0 + # 2. y_variance == 0 and sum_of_squared_diffs[cat_idx] == 0 + encoding_vec[feat_idx][cat_idx] = y_mean + else: + encoding_vec[feat_idx][cat_idx] = ( + lambda_ * means[cat_idx] + (1 - lambda_) * y_mean + ) + + return encodings diff --git a/sklearn/preprocessing/tests/test_target_encoder.py b/sklearn/preprocessing/tests/test_target_encoder.py new file mode 100644 index 0000000000000..41dadb8759b90 --- /dev/null +++ b/sklearn/preprocessing/tests/test_target_encoder.py @@ -0,0 +1,549 @@ +import numpy as np +from numpy.testing import assert_allclose +from numpy.testing import assert_array_equal +import pytest + +from sklearn.preprocessing import ( + TargetEncoder, + LabelEncoder, + KBinsDiscretizer, +) +from sklearn.model_selection import KFold +from sklearn.model_selection import StratifiedKFold +from sklearn.model_selection import ShuffleSplit +from sklearn.model_selection import cross_val_score +from sklearn.model_selection import train_test_split +from sklearn.ensemble import RandomForestRegressor +from sklearn.linear_model import Ridge +from sklearn.pipeline import make_pipeline + + +def _encode_target(X_ordinal, y_int, n_categories, smooth): + """Simple Python implementation of target encoding.""" + cur_encodings = np.zeros(n_categories, dtype=np.float64) + y_mean = np.mean(y_int) + + if smooth == "auto": + y_variance = np.var(y_int) + for c in range(n_categories): + y_subset = y_int[X_ordinal == c] + n_i = y_subset.shape[0] + + if n_i == 0: + cur_encodings[c] = y_mean + continue + + y_subset_variance = np.var(y_subset) + m = y_subset_variance / y_variance + lambda_ = n_i / (n_i + m) + + cur_encodings[c] = lambda_ * np.mean(y_subset) + (1 - lambda_) * y_mean + return cur_encodings + else: # float + for c in range(n_categories): + y_subset = y_int[X_ordinal == c] + current_sum = np.sum(y_subset) + y_mean * smooth + current_cnt = y_subset.shape[0] + smooth + cur_encodings[c] = current_sum / current_cnt + return cur_encodings + + +@pytest.mark.parametrize( + "categories, unknown_value", + [ + ([np.array([0, 1, 2], dtype=np.int64)], 4), + ([np.array([1.0, 3.0, np.nan], dtype=np.float64)], 6.0), + ([np.array(["cat", "dog", "snake"], dtype=object)], "bear"), + ("auto", 3), + ], +) +@pytest.mark.parametrize("smooth", [5.0, "auto"]) +@pytest.mark.parametrize("target_type", ["binary", "continuous"]) +def test_encoding(categories, unknown_value, global_random_seed, smooth, target_type): + """Check encoding for binary and continuous targets.""" + + X_train_array = np.array([[0] * 20 + [1] * 30 + [2] * 40], dtype=np.int64).T + X_test_array = np.array([[0, 1, 2]], dtype=np.int64).T + n_categories = 3 + n_samples = X_train_array.shape[0] + + if categories == "auto": + X_train = X_train_array + else: + X_train = categories[0][X_train_array] + + if categories == "auto": + X_test = X_test_array + else: + X_test = categories[0][X_test_array] + X_test = np.concatenate((X_test, [[unknown_value]])) + + rng = np.random.RandomState(global_random_seed) + + if target_type == "binary": + y_int = rng.randint(low=0, high=2, size=n_samples) + target_names = np.array(["cat", "dog"], dtype=object) + y_train = target_names[y_int] + cv = StratifiedKFold(n_splits=3, random_state=0, shuffle=True) + else: # target_type == continuous + y_int = rng.uniform(low=-10, high=20, size=n_samples) + y_train = y_int + cv = KFold(n_splits=3, random_state=0, shuffle=True) + + shuffled_idx = rng.permutation(n_samples) + X_train_array = X_train_array[shuffled_idx] + X_train = X_train[shuffled_idx] + y_train = y_train[shuffled_idx] + y_int = y_int[shuffled_idx] + + # Get encodings for cv splits to validate `fit_transform` + expected_X_fit_transform = np.empty_like(X_train_array, dtype=np.float64) + + for train_idx, test_idx in cv.split(X_train_array, y_train): + X_, y_ = X_train_array[train_idx, 0], y_int[train_idx] + cur_encodings = _encode_target(X_, y_, n_categories, smooth) + expected_X_fit_transform[test_idx, 0] = cur_encodings[ + X_train_array[test_idx, 0] + ] + + target_encoder = TargetEncoder( + smooth=smooth, categories=categories, cv=3, random_state=0 + ) + + X_fit_transform = target_encoder.fit_transform(X_train, y_train) + + assert target_encoder.target_type_ == target_type + assert_allclose(X_fit_transform, expected_X_fit_transform) + assert len(target_encoder.encodings_) == 1 + + # compute encodings for all data to validate `transform` + y_mean = np.mean(y_int) + expected_encodings = _encode_target( + X_train_array[:, 0], y_int, n_categories, smooth + ) + assert_allclose(target_encoder.encodings_[0], expected_encodings) + assert target_encoder.target_mean_ == pytest.approx(y_mean) + + # Transform on test data, the last value is unknown is it is encoded as the target + # mean + expected_X_test_transform = np.concatenate( + (expected_encodings, np.array([y_mean])) + ).reshape(-1, 1) + + X_test_transform = target_encoder.transform(X_test) + assert_allclose(X_test_transform, expected_X_test_transform) + + +@pytest.mark.parametrize( + "X, categories", + [ + ( + np.array([[0] * 10 + [1] * 10 + [3]], dtype=np.int64).T, # 3 is unknown + [[0, 1, 2]], + ), + ( + np.array( + [["cat"] * 10 + ["dog"] * 10 + ["snake"]], dtype=object + ).T, # snake is unknown + [["dog", "cat", "cow"]], + ), + ], +) +@pytest.mark.parametrize("smooth", [4.0, "auto"]) +def test_custom_categories(X, categories, smooth): + """Custom categories with unknown categories that are not in training data.""" + rng = np.random.RandomState(0) + y = rng.uniform(low=-10, high=20, size=X.shape[0]) + enc = TargetEncoder(categories=categories, smooth=smooth, random_state=0).fit(X, y) + + # The last element is unknown and encoded as the mean + y_mean = y.mean() + X_trans = enc.transform(X[-1:]) + assert X_trans[0, 0] == pytest.approx(y_mean) + + assert len(enc.encodings_) == 1 + # custom category that is not in training data + assert enc.encodings_[0][-1] == pytest.approx(y_mean) + + +@pytest.mark.parametrize( + "y, msg", + [ + ([1, 2, 0, 1], "Found input variables with inconsistent"), + ( + np.array([[1, 2, 0], [1, 2, 3]]).T, + "Target type was inferred to be 'multiclass-multioutput'", + ), + (["cat", "dog", "bear"], "Target type was inferred to be 'multiclass'"), + ], +) +def test_errors(y, msg): + """Check invalidate input.""" + X = np.array([[1, 0, 1]]).T + + enc = TargetEncoder() + with pytest.raises(ValueError, match=msg): + enc.fit_transform(X, y) + + +def test_use_regression_target(): + """Custom target_type to avoid inferring the target type.""" + X = np.array([[0, 1, 0, 1, 0, 1]]).T + + # XXX: When multiclass is supported, then the following `y` + # is considered a multiclass problem and `TargetEncoder` will not error. + # type_of_target would be 'multiclass' + y = np.array([1.0, 2.0, 3.0, 2.0, 3.0, 4.0]) + enc = TargetEncoder() + msg = "Target type was inferred to be 'multiclass'" + with pytest.raises(ValueError, match=msg): + enc.fit_transform(X, y) + + enc = TargetEncoder(target_type="continuous") + enc.fit_transform(X, y) + assert enc.target_type_ == "continuous" + + +def test_feature_names_out_set_output(): + """Check TargetEncoder works with set_output.""" + pd = pytest.importorskip("pandas") + + X_df = pd.DataFrame({"A": ["a", "b"] * 10, "B": [1, 2] * 10}) + y = [1, 2] * 10 + + enc_default = TargetEncoder(cv=2, smooth=3.0, random_state=0) + enc_default.set_output(transform="default") + enc_pandas = TargetEncoder(cv=2, smooth=3.0, random_state=0) + enc_pandas.set_output(transform="pandas") + + X_default = enc_default.fit_transform(X_df, y) + X_pandas = enc_pandas.fit_transform(X_df, y) + + assert_allclose(X_pandas.to_numpy(), X_default) + assert_array_equal(enc_pandas.get_feature_names_out(), ["A", "B"]) + assert_array_equal(enc_pandas.get_feature_names_out(), X_pandas.columns) + + +@pytest.mark.parametrize("to_pandas", [True, False]) +@pytest.mark.parametrize("smooth", [1.0, "auto"]) +@pytest.mark.parametrize("target_type", ["binary-ints", "binary-str", "continuous"]) +def test_multiple_features_quick(to_pandas, smooth, target_type): + """Check target encoder with multiple features.""" + X_ordinal = np.array( + [[1, 1], [0, 1], [1, 1], [2, 1], [1, 0], [0, 1], [1, 0], [0, 0]], dtype=np.int64 + ) + if target_type == "binary-str": + y_train = np.array(["a", "b", "a", "a", "b", "b", "a", "b"]) + y_integer = LabelEncoder().fit_transform(y_train) + cv = StratifiedKFold(2, random_state=0, shuffle=True) + elif target_type == "binary-ints": + y_train = np.array([3, 4, 3, 3, 3, 4, 4, 4]) + y_integer = LabelEncoder().fit_transform(y_train) + cv = StratifiedKFold(2, random_state=0, shuffle=True) + else: + y_train = np.array([3.0, 5.1, 2.4, 3.5, 4.1, 5.5, 10.3, 7.3], dtype=np.float32) + y_integer = y_train + cv = KFold(2, random_state=0, shuffle=True) + y_mean = np.mean(y_integer) + categories = [[0, 1, 2], [0, 1]] + + X_test = np.array( + [ + [0, 1], + [3, 0], # 3 is unknown + [1, 10], # 10 is unknown + ], + dtype=np.int64, + ) + + if to_pandas: + pd = pytest.importorskip("pandas") + # convert second feature to an object + X_train = pd.DataFrame( + { + "feat0": X_ordinal[:, 0], + "feat1": np.array(["cat", "dog"], dtype=object)[X_ordinal[:, 1]], + } + ) + # "snake" is unknown + X_test = pd.DataFrame({"feat0": X_test[:, 0], "feat1": ["dog", "cat", "snake"]}) + else: + X_train = X_ordinal + + # manually compute encoding for fit_transform + expected_X_fit_transform = np.empty_like(X_ordinal, dtype=np.float64) + for f_idx, cats in enumerate(categories): + for train_idx, test_idx in cv.split(X_ordinal, y_integer): + X_, y_ = X_ordinal[train_idx, f_idx], y_integer[train_idx] + current_encoding = _encode_target(X_, y_, len(cats), smooth) + expected_X_fit_transform[test_idx, f_idx] = current_encoding[ + X_ordinal[test_idx, f_idx] + ] + + # manually compute encoding for transform + expected_encodings = [] + for f_idx, cats in enumerate(categories): + current_encoding = _encode_target( + X_ordinal[:, f_idx], y_integer, len(cats), smooth + ) + expected_encodings.append(current_encoding) + + expected_X_test_transform = np.array( + [ + [expected_encodings[0][0], expected_encodings[1][1]], + [y_mean, expected_encodings[1][0]], + [expected_encodings[0][1], y_mean], + ], + dtype=np.float64, + ) + + enc = TargetEncoder(smooth=smooth, cv=2, random_state=0) + X_fit_transform = enc.fit_transform(X_train, y_train) + assert_allclose(X_fit_transform, expected_X_fit_transform) + + assert len(enc.encodings_) == 2 + for i in range(2): + assert_allclose(enc.encodings_[i], expected_encodings[i]) + + X_test_transform = enc.transform(X_test) + assert_allclose(X_test_transform, expected_X_test_transform) + + +@pytest.mark.parametrize( + "y, y_mean", + [ + (np.array([3.4] * 20), 3.4), + (np.array([0] * 20), 0), + (np.array(["a"] * 20, dtype=object), 0), + ], + ids=["continuous", "binary", "binary-string"], +) +@pytest.mark.parametrize("smooth", ["auto", 4.0, 0.0]) +def test_constant_target_and_feature(y, y_mean, smooth): + """Check edge case where feature and target is constant.""" + X = np.array([[1] * 20]).T + n_samples = X.shape[0] + + enc = TargetEncoder(cv=2, smooth=smooth, random_state=0) + X_trans = enc.fit_transform(X, y) + assert_allclose(X_trans, np.repeat([[y_mean]], n_samples, axis=0)) + assert enc.encodings_[0][0] == pytest.approx(y_mean) + assert enc.target_mean_ == pytest.approx(y_mean) + + X_test = np.array([[1], [0]]) + X_test_trans = enc.transform(X_test) + assert_allclose(X_test_trans, np.repeat([[y_mean]], 2, axis=0)) + + +def test_fit_transform_not_associated_with_y_if_ordinal_categorical_is_not( + global_random_seed, +): + cardinality = 30 # not too large, otherwise we need a very large n_samples + n_samples = 3000 + rng = np.random.RandomState(global_random_seed) + y_train = rng.normal(size=n_samples) + X_train = rng.randint(0, cardinality, size=n_samples).reshape(-1, 1) + + # Sort by y_train to attempt to cause a leak + y_sorted_indices = y_train.argsort() + y_train = y_train[y_sorted_indices] + X_train = X_train[y_sorted_indices] + + target_encoder = TargetEncoder(shuffle=True, random_state=global_random_seed) + X_encoded_train_shuffled = target_encoder.fit_transform(X_train, y_train) + + target_encoder = TargetEncoder(shuffle=False) + X_encoded_train_no_shuffled = target_encoder.fit_transform(X_train, y_train) + + # Check that no information about y_train has leaked into X_train: + regressor = RandomForestRegressor( + n_estimators=10, min_samples_leaf=20, random_state=global_random_seed + ) + + # It's impossible to learn a good predictive model on the training set when + # using the original representation X_train or the target encoded + # representation with shuffled inner CV. For the latter, no information + # about y_train has inadvertently leaked into the prior used to generate + # `X_encoded_train_shuffled`: + cv = ShuffleSplit(n_splits=50, random_state=global_random_seed) + assert cross_val_score(regressor, X_train, y_train, cv=cv).mean() < 0.1 + assert ( + cross_val_score(regressor, X_encoded_train_shuffled, y_train, cv=cv).mean() + < 0.1 + ) + + # Without the inner CV shuffling, a lot of information about y_train goes into the + # the per-fold y_train.mean() priors: shrinkage is no longer effective in this + # case and would no longer be able to prevent downstream over-fitting. + assert ( + cross_val_score(regressor, X_encoded_train_no_shuffled, y_train, cv=cv).mean() + > 0.5 + ) + + +def test_smooth_zero(): + """Check edge case with zero smoothing and cv does not contain category.""" + X = np.array([[0, 0, 0, 0, 0, 1, 1, 1, 1, 1]]).T + y = np.array([2.1, 4.3, 1.2, 3.1, 1.0, 9.0, 10.3, 14.2, 13.3, 15.0]) + + enc = TargetEncoder(smooth=0.0, shuffle=False, cv=2) + X_trans = enc.fit_transform(X, y) + + # With cv = 2, category 0 does not exist in the second half, thus + # it will be encoded as the mean of the second half + assert_allclose(X_trans[0], np.mean(y[5:])) + + # category 1 does nto exist in the first half, thus it will be encoded as + # the mean of the first half + assert_allclose(X_trans[-1], np.mean(y[:5])) + + +@pytest.mark.parametrize("smooth", [0.0, 1e3, "auto"]) +def test_invariance_of_encoding_under_label_permutation(smooth, global_random_seed): + # Check that the encoding does not depend on the integer of the value of + # the integer labels. This is quite of a trivial property but it is helpful + # to understand the following test. + rng = np.random.RandomState(global_random_seed) + + # Random y and informative categorical X to make the test non-trivial when + # using smoothing. + y = rng.normal(size=1000) + n_categories = 30 + X = KBinsDiscretizer(n_bins=n_categories, encode="ordinal").fit_transform( + y.reshape(-1, 1) + ) + + X_train, X_test, y_train, y_test = train_test_split( + X, y, random_state=global_random_seed + ) + + # Shuffle the labels to make sure that the encoding is invariant to the + # permutation of the labels + permutated_labels = rng.permutation(n_categories) + X_train_permuted = permutated_labels[X_train.astype(np.int32)] + X_test_permuted = permutated_labels[X_test.astype(np.int32)] + + target_encoder = TargetEncoder(smooth=smooth, random_state=global_random_seed) + X_train_encoded = target_encoder.fit_transform(X_train, y_train) + X_test_encoded = target_encoder.transform(X_test) + + X_train_permuted_encoded = target_encoder.fit_transform(X_train_permuted, y_train) + X_test_permuted_encoded = target_encoder.transform(X_test_permuted) + + assert_allclose(X_train_encoded, X_train_permuted_encoded) + assert_allclose(X_test_encoded, X_test_permuted_encoded) + + +@pytest.mark.parametrize("smooth", [0.0, "auto"]) +def test_target_encoding_for_linear_regression(smooth, global_random_seed): + # Check some expected statistical properties when fitting a linear + # regression model on target encoded features depending on there relation + # with that target. + + # In this test, we use the Ridge class with the "lsqr" solver and a little + # bit of regularization to implement a linear regression model that + # converges quickly for large `n_samples` and robustly in case of + # correlated features. Since we will fit this model on a mean centered + # target, we do not need to fit an intercept and this will help simplify + # the analysis with respect to the expected coefficients. + linear_regression = Ridge(alpha=1e-6, solver="lsqr", fit_intercept=False) + + # Construct a random target variable. We need a large number of samples for + # this test to be stable accross all values of the random seed. + n_samples = 50_000 + rng = np.random.RandomState(global_random_seed) + y = rng.randn(n_samples) + + # Generate a single informative ordinal feature with medium cardinality. + # Inject some irreducible noise to make it harder for a multivariate model + # to identify the informative feature from other pure noise features. + noise = 0.8 * rng.randn(n_samples) + n_categories = 100 + X_informative = KBinsDiscretizer( + n_bins=n_categories, + encode="ordinal", + strategy="uniform", + random_state=rng, + ).fit_transform((y + noise).reshape(-1, 1)) + + # Let's permute the labels to hide the fact that this feature is + # informative to naive linear regression model trained on the raw ordinal + # values. As highlighed in the previous test, the target encoding should be + # invariant to such a permutation. + permutated_labels = rng.permutation(n_categories) + X_informative = permutated_labels[X_informative.astype(np.int32)] + + # Generate a shuffled copy of the informative feature to destroy the + # relationship with the target. + X_shuffled = rng.permutation(X_informative) + + # Also include a very high cardinality categorical feature that is by + # itself independent of the target variable: target encoding such a feature + # without internal cross-validation should cause catastrophic overfitting + # for the downstream regressor, even with shrinkage. This kind of features + # typically represents near unique idenfiers of samples. In general they + # should be removed from a machine learning datasets but here we want to + # study the ability of the default behavor of TargetEncoder to mitigate + # them automatically. + X_near_unique_categories = rng.choice( + int(0.9 * n_samples), size=n_samples, replace=True + ).reshape(-1, 1) + + # Assemble the dataset and do a train-test split: + X = np.concatenate( + [X_informative, X_shuffled, X_near_unique_categories], + axis=1, + ) + X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0) + + # Let's first check that a linear regression model trained on the raw + # features underfits because of the meaning-less ordinal encoding of the + # labels. + raw_model = linear_regression.fit(X_train, y_train) + assert raw_model.score(X_train, y_train) < 0.1 + assert raw_model.score(X_test, y_test) < 0.1 + + # Now do the same with target encoding using the internal CV mechanism + # implemented when using fit_transform. + model_with_cv = make_pipeline( + TargetEncoder(smooth=smooth, random_state=rng), linear_regression + ).fit(X_train, y_train) + + # This model should be able to fit the data well and also generalise to the + # test data (assuming that the binning is fine-grained enough). The R2 + # scores are not perfect because of the noise injected during the + # generation of the unique informative feature. + coef = model_with_cv[-1].coef_ + assert model_with_cv.score(X_train, y_train) > 0.5, coef + assert model_with_cv.score(X_test, y_test) > 0.5, coef + + # The target encoder recovers the linear relationship with slope 1 between + # the target encoded unique informative predictor and the target. Since the + # target encoding of the 2 other features is not informative thanks to the + # use of internal cross-validation, the multivariate linear regressor + # assigns a coef of 1 to the first feature and 0 to the other 2. + assert coef[0] == pytest.approx(1, abs=1e-2) + assert (np.abs(coef[1:]) < 0.2).all() + + # Let's now disable the internal cross-validation by calling fit and then + # transform separately on the training set: + target_encoder = TargetEncoder(smooth=smooth, random_state=rng).fit( + X_train, y_train + ) + X_enc_no_cv_train = target_encoder.transform(X_train) + X_enc_no_cv_test = target_encoder.transform(X_test) + model_no_cv = linear_regression.fit(X_enc_no_cv_train, y_train) + + # The linear regression model should always overfit because it assigns + # too much weight to the extremely high cardinality feature relatively to + # the informative feature. Note that this is the case even when using + # the empirical Bayes smoothing which is not enough to prevent such + # overfitting alone. + coef = model_no_cv.coef_ + assert model_no_cv.score(X_enc_no_cv_train, y_train) > 0.7, coef + assert model_no_cv.score(X_enc_no_cv_test, y_test) < 0.5, coef + + # The model overfits because it assigns too much weight to the high + # cardinality yet non-informative feature instead of the lower + # cardinality yet informative feature: + assert abs(coef[0]) < abs(coef[2]) From c3dd68c82c0ec265ecc7c7600e7771b424772f8a Mon Sep 17 00:00:00 2001 From: Olivier Grisel Date: Thu, 16 Mar 2023 20:36:46 +0100 Subject: [PATCH 058/230] CI make it possible to cancel running Azure jobs (#25876) --- azure-pipelines.yml | 12 ++++++++---- build_tools/azure/posix.yml | 5 +++-- build_tools/azure/windows.yml | 5 +++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 353a893f43ef3..af25f0e09862f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -169,9 +169,10 @@ jobs: name: Linux vmImage: ubuntu-20.04 dependsOn: [linting, git_commit, Ubuntu_Jammy_Jellyfish] + # Runs when dependencies succeeded or skipped condition: | and( - in(dependencies['Ubuntu_Jammy_Jellyfish']['result'], 'Succeeded', 'Skipped'), + not(or(failed(), canceled())), not(contains(dependencies['git_commit']['outputs']['commit.message'], '[ci skip]')) ) matrix: @@ -204,9 +205,10 @@ jobs: name: Linux_Docker vmImage: ubuntu-20.04 dependsOn: [linting, git_commit, Ubuntu_Jammy_Jellyfish] + # Runs when dependencies succeeded or skipped condition: | and( - in(dependencies['Ubuntu_Jammy_Jellyfish']['result'], 'Succeeded', 'Skipped'), + not(or(failed(), canceled())), not(contains(dependencies['git_commit']['outputs']['commit.message'], '[ci skip]')) ) matrix: @@ -223,9 +225,10 @@ jobs: name: macOS vmImage: macOS-11 dependsOn: [linting, git_commit, Ubuntu_Jammy_Jellyfish] + # Runs when dependencies succeeded or skipped condition: | and( - in(dependencies['Ubuntu_Jammy_Jellyfish']['result'], 'Succeeded', 'Skipped'), + not(or(failed(), canceled())), not(contains(dependencies['git_commit']['outputs']['commit.message'], '[ci skip]')) ) matrix: @@ -245,9 +248,10 @@ jobs: name: Windows vmImage: windows-latest dependsOn: [linting, git_commit, Ubuntu_Jammy_Jellyfish] + # Runs when dependencies succeeded or skipped condition: | and( - in(dependencies['Ubuntu_Jammy_Jellyfish']['result'], 'Succeeded', 'Skipped'), + not(or(failed(), canceled())), not(contains(dependencies['git_commit']['outputs']['commit.message'], '[ci skip]')) ) matrix: diff --git a/build_tools/azure/posix.yml b/build_tools/azure/posix.yml index 5469e8d145bdf..6c32ad2f6e76d 100644 --- a/build_tools/azure/posix.yml +++ b/build_tools/azure/posix.yml @@ -63,11 +63,12 @@ jobs: - script: | build_tools/azure/test_docs.sh displayName: 'Test Docs' - condition: eq(variables['SELECTED_TESTS'], '') + condition: and(succeeded(), eq(variables['SELECTED_TESTS'], '')) - script: | build_tools/azure/test_pytest_soft_dependency.sh displayName: 'Test Soft Dependency' - condition: and(eq(variables['CHECK_PYTEST_SOFT_DEPENDENCY'], 'true'), + condition: and(succeeded(), + eq(variables['CHECK_PYTEST_SOFT_DEPENDENCY'], 'true'), eq(variables['SELECTED_TESTS'], '')) - task: PublishTestResults@2 inputs: diff --git a/build_tools/azure/windows.yml b/build_tools/azure/windows.yml index ea97b7eb5eaf0..4c93e00901cb8 100644 --- a/build_tools/azure/windows.yml +++ b/build_tools/azure/windows.yml @@ -37,13 +37,14 @@ jobs: addToPath: true architecture: 'x86' displayName: Use 32 bit System Python - condition: eq(variables['PYTHON_ARCH'], '32') + condition: and(succeeded(), eq(variables['PYTHON_ARCH'], '32')) - bash: ./build_tools/azure/install_win.sh displayName: 'Install' - bash: ./build_tools/azure/test_script.sh displayName: 'Test Library' - bash: ./build_tools/azure/upload_codecov.sh - condition: and(succeeded(), eq(variables['COVERAGE'], 'true'), + condition: and(succeeded(), + eq(variables['COVERAGE'], 'true'), eq(variables['SELECTED_TESTS'], '')) displayName: 'Upload To Codecov' env: From 5eed9faaec8edf0f15f2720881ae14a192bdc09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Thu, 16 Mar 2023 22:13:03 +0100 Subject: [PATCH 059/230] MAINT Clean-up deprecated if_delegate_has_method for 1.3 (#25879) --- doc/modules/classes.rst | 9 -- sklearn/utils/estimator_checks.py | 2 +- sklearn/utils/metaestimators.py | 82 +--------------- sklearn/utils/tests/test_metaestimators.py | 109 --------------------- sklearn/utils/tests/test_testing.py | 62 +----------- 5 files changed, 6 insertions(+), 258 deletions(-) diff --git a/doc/modules/classes.rst b/doc/modules/classes.rst index ed934d3a9fb84..1e61ac5aac08a 100644 --- a/doc/modules/classes.rst +++ b/doc/modules/classes.rst @@ -1681,12 +1681,3 @@ Utilities from joblib: Recently deprecated =================== - -To be removed in 1.3 --------------------- - -.. autosummary:: - :toctree: generated/ - :template: function.rst - - utils.metaestimators.if_delegate_has_method diff --git a/sklearn/utils/estimator_checks.py b/sklearn/utils/estimator_checks.py index d38473693efd0..8a220966b3b86 100644 --- a/sklearn/utils/estimator_checks.py +++ b/sklearn/utils/estimator_checks.py @@ -1716,7 +1716,7 @@ def check_fit_score_takes_y(name, estimator_orig): func(X, y) args = [p.name for p in signature(func).parameters.values()] if args[0] == "self": - # if_delegate_has_method makes methods into functions + # available_if makes methods into functions # with an explicit "self", so need to shift arguments args = args[1:] assert args[1] in ["y", "Y"], ( diff --git a/sklearn/utils/metaestimators.py b/sklearn/utils/metaestimators.py index 53566e2d2c125..405edeae0a55d 100644 --- a/sklearn/utils/metaestimators.py +++ b/sklearn/utils/metaestimators.py @@ -3,19 +3,17 @@ # Andreas Mueller # License: BSD from typing import List, Any -import warnings from abc import ABCMeta, abstractmethod -from operator import attrgetter import numpy as np from contextlib import suppress from ..utils import _safe_indexing from ..utils._tags import _safe_tags from ..base import BaseEstimator -from ._available_if import available_if, _AvailableIfDescriptor +from ._available_if import available_if -__all__ = ["available_if", "if_delegate_has_method"] +__all__ = ["available_if"] class _BaseComposition(BaseEstimator, metaclass=ABCMeta): @@ -96,82 +94,6 @@ def _validate_names(self, names): ) -# TODO(1.3) remove -class _IffHasAttrDescriptor(_AvailableIfDescriptor): - """Implements a conditional property using the descriptor protocol. - - Using this class to create a decorator will raise an ``AttributeError`` - if none of the delegates (specified in ``delegate_names``) is an attribute - of the base object or the first found delegate does not have an attribute - ``attribute_name``. - - This allows ducktyping of the decorated method based on - ``delegate.attribute_name``. Here ``delegate`` is the first item in - ``delegate_names`` for which ``hasattr(object, delegate) is True``. - - See https://docs.python.org/3/howto/descriptor.html for an explanation of - descriptors. - """ - - def __init__(self, fn, delegate_names, attribute_name): - super().__init__(fn, self._check, attribute_name) - self.delegate_names = delegate_names - - def _check(self, obj): - warnings.warn( - "if_delegate_has_method was deprecated in version 1.1 and will be " - "removed in version 1.3. Use available_if instead.", - FutureWarning, - ) - - delegate = None - for delegate_name in self.delegate_names: - try: - delegate = attrgetter(delegate_name)(obj) - break - except AttributeError: - continue - - if delegate is None: - return False - # raise original AttributeError - getattr(delegate, self.attribute_name) - - return True - - -# TODO(1.3) remove -def if_delegate_has_method(delegate): - """Create a decorator for methods that are delegated to a sub-estimator. - - .. deprecated:: 1.3 - `if_delegate_has_method` is deprecated in version 1.1 and will be removed in - version 1.3. Use `available_if` instead. - - This enables ducktyping by hasattr returning True according to the - sub-estimator. - - Parameters - ---------- - delegate : str, list of str or tuple of str - Name of the sub-estimator that can be accessed as an attribute of the - base object. If a list or a tuple of names are provided, the first - sub-estimator that is an attribute of the base object will be used. - - Returns - ------- - callable - Callable makes the decorated method available if the delegate - has a method with the same name as the decorated method. - """ - if isinstance(delegate, list): - delegate = tuple(delegate) - if not isinstance(delegate, tuple): - delegate = (delegate,) - - return lambda fn: _IffHasAttrDescriptor(fn, delegate, attribute_name=fn.__name__) - - def _safe_split(estimator, X, y, indices, train_indices=None): """Create subset of dataset and properly handle kernels. diff --git a/sklearn/utils/tests/test_metaestimators.py b/sklearn/utils/tests/test_metaestimators.py index 2a75ab387df60..33ee937f34371 100644 --- a/sklearn/utils/tests/test_metaestimators.py +++ b/sklearn/utils/tests/test_metaestimators.py @@ -1,96 +1,10 @@ -import numpy as np import pytest -import warnings import pickle -from sklearn.utils.metaestimators import if_delegate_has_method from sklearn.utils.metaestimators import available_if -class Prefix: - def func(self): - pass - - -class MockMetaEstimator: - """This is a mock meta estimator""" - - a_prefix = Prefix() - - @if_delegate_has_method(delegate="a_prefix") - def func(self): - """This is a mock delegated function""" - pass - - -@pytest.mark.filterwarnings("ignore:if_delegate_has_method was deprecated") -def test_delegated_docstring(): - assert "This is a mock delegated function" in str( - MockMetaEstimator.__dict__["func"].__doc__ - ) - assert "This is a mock delegated function" in str(MockMetaEstimator.func.__doc__) - assert "This is a mock delegated function" in str(MockMetaEstimator().func.__doc__) - - -class MetaEst: - """A mock meta estimator""" - - def __init__(self, sub_est, better_sub_est=None): - self.sub_est = sub_est - self.better_sub_est = better_sub_est - - @if_delegate_has_method(delegate="sub_est") - def predict(self): - pass - - -class MetaEstTestTuple(MetaEst): - """A mock meta estimator to test passing a tuple of delegates""" - - @if_delegate_has_method(delegate=("sub_est", "better_sub_est")) - def predict(self): - pass - - -class MetaEstTestList(MetaEst): - """A mock meta estimator to test passing a list of delegates""" - - @if_delegate_has_method(delegate=["sub_est", "better_sub_est"]) - def predict(self): - pass - - -class HasPredict: - """A mock sub-estimator with predict method""" - - def predict(self): - pass - - -class HasNoPredict: - """A mock sub-estimator with no predict method""" - - pass - - -class HasPredictAsNDArray: - """A mock sub-estimator where predict is a NumPy array""" - - predict = np.ones((10, 2), dtype=np.int64) - - -@pytest.mark.filterwarnings("ignore:if_delegate_has_method was deprecated") -def test_if_delegate_has_method(): - assert hasattr(MetaEst(HasPredict()), "predict") - assert not hasattr(MetaEst(HasNoPredict()), "predict") - assert not hasattr(MetaEstTestTuple(HasNoPredict(), HasNoPredict()), "predict") - assert hasattr(MetaEstTestTuple(HasPredict(), HasNoPredict()), "predict") - assert not hasattr(MetaEstTestTuple(HasNoPredict(), HasPredict()), "predict") - assert not hasattr(MetaEstTestList(HasNoPredict(), HasPredict()), "predict") - assert hasattr(MetaEstTestList(HasPredict(), HasPredict()), "predict") - - class AvailableParameterEstimator: """This estimator's `available` parameter toggles the presence of a method""" @@ -137,29 +51,6 @@ def test_available_if_unbound_method(): AvailableParameterEstimator.available_func(est) -@pytest.mark.filterwarnings("ignore:if_delegate_has_method was deprecated") -def test_if_delegate_has_method_numpy_array(): - """Check that we can check for an attribute that is a NumPy array. - - This is a non-regression test for: - https://github.com/scikit-learn/scikit-learn/issues/21144 - """ - estimator = MetaEst(HasPredictAsNDArray()) - assert hasattr(estimator, "predict") - - -def test_if_delegate_has_method_deprecated(): - """Check the deprecation warning of if_delegate_has_method""" - # don't warn when creating the decorator - with warnings.catch_warnings(): - warnings.simplefilter("error", FutureWarning) - _ = if_delegate_has_method(delegate="predict") - - # Only when calling it - with pytest.warns(FutureWarning, match="if_delegate_has_method was deprecated"): - hasattr(MetaEst(HasPredict()), "predict") - - def test_available_if_methods_can_be_pickled(): """Check that available_if methods can be pickled. diff --git a/sklearn/utils/tests/test_testing.py b/sklearn/utils/tests/test_testing.py index ab959c75350ff..70cb3257c26d5 100644 --- a/sklearn/utils/tests/test_testing.py +++ b/sklearn/utils/tests/test_testing.py @@ -10,7 +10,7 @@ import pytest from sklearn.utils.deprecation import deprecated -from sklearn.utils.metaestimators import available_if, if_delegate_has_method +from sklearn.utils.metaestimators import available_if from sklearn.utils._testing import ( assert_raises, assert_no_warnings, @@ -430,64 +430,7 @@ def fit(self, X, y): """Incorrect docstring but should not be tested""" -class MockMetaEstimatorDeprecatedDelegation: - def __init__(self, delegate): - """MetaEstimator to check if doctest on delegated methods work. - - Parameters - --------- - delegate : estimator - Delegated estimator. - """ - self.delegate = delegate - - @if_delegate_has_method(delegate="delegate") - def predict(self, X): - """This is available only if delegate has predict. - - Parameters - ---------- - y : ndarray - Parameter y - """ - return self.delegate.predict(X) - - @if_delegate_has_method(delegate="delegate") - @deprecated("Testing a deprecated delegated method") - def score(self, X): - """This is available only if delegate has score. - - Parameters - --------- - y : ndarray - Parameter y - """ - - @if_delegate_has_method(delegate="delegate") - def predict_proba(self, X): - """This is available only if delegate has predict_proba. - - Parameters - --------- - X : ndarray - Parameter X - """ - return X - - @deprecated("Testing deprecated function with wrong params") - def fit(self, X, y): - """Incorrect docstring but should not be tested""" - - -@pytest.mark.filterwarnings("ignore:if_delegate_has_method was deprecated") -@pytest.mark.parametrize( - "mock_meta", - [ - MockMetaEstimator(delegate=MockEst()), - MockMetaEstimatorDeprecatedDelegation(delegate=MockEst()), - ], -) -def test_check_docstring_parameters(mock_meta): +def test_check_docstring_parameters(): pytest.importorskip( "numpydoc", reason="numpydoc is required to test the docstrings", @@ -506,6 +449,7 @@ def test_check_docstring_parameters(mock_meta): check_docstring_parameters(Klass.f_bad_sections) incorrect = check_docstring_parameters(f_check_param_definition) + mock_meta = MockMetaEstimator(delegate=MockEst()) mock_meta_name = mock_meta.__class__.__name__ assert incorrect == [ "sklearn.utils.tests.test_testing.f_check_param_definition There " From 6571f8f05a4a660a12ce55bd14c00d1f97408091 Mon Sep 17 00:00:00 2001 From: Nishu Choudhary <51842539+choudharynishu@users.noreply.github.com> Date: Fri, 17 Mar 2023 05:41:01 -0400 Subject: [PATCH 060/230] MAINT Parameter validation for tree.export_text (#25867) --- sklearn/tests/test_public_functions.py | 1 + sklearn/tree/_export.py | 24 ++++++++++++++---------- sklearn/tree/tests/test_export.py | 10 ---------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 2fa93fdfb6adf..7477d614da4c7 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -191,6 +191,7 @@ def _check_function_param_validation( "sklearn.model_selection.train_test_split", "sklearn.random_projection.johnson_lindenstrauss_min_dim", "sklearn.svm.l1_min_c", + "sklearn.tree.export_text", "sklearn.utils.gen_batches", ] diff --git a/sklearn/tree/_export.py b/sklearn/tree/_export.py index 3e65c4a2b0dc5..c7bc0dd04c08f 100644 --- a/sklearn/tree/_export.py +++ b/sklearn/tree/_export.py @@ -17,12 +17,14 @@ import numpy as np from ..utils.validation import check_is_fitted +from ..utils._param_validation import Interval, validate_params + from ..base import is_classifier from . import _criterion from . import _tree from ._reingold_tilford import buchheim, Tree -from . import DecisionTreeClassifier +from . import DecisionTreeClassifier, DecisionTreeRegressor def _color_brew(n): @@ -919,6 +921,17 @@ def compute_depth_( return max(depths) +@validate_params( + { + "decision_tree": [DecisionTreeClassifier, DecisionTreeRegressor], + "feature_names": [list, None], + "class_names": [list, None], + "max_depth": [Interval(Integral, 0, None, closed="left"), None], + "spacing": [Interval(Integral, 1, None, closed="left"), None], + "decimals": [Interval(Integral, 0, None, closed="left"), None], + "show_weights": ["boolean"], + } +) def export_text( decision_tree, *, @@ -1011,21 +1024,12 @@ def export_text( left_child_fmt = "{} {} > {}\n" truncation_fmt = "{} {}\n" - if max_depth < 0: - raise ValueError("max_depth bust be >= 0, given %d" % max_depth) - if feature_names is not None and len(feature_names) != tree_.n_features: raise ValueError( "feature_names must contain %d elements, got %d" % (tree_.n_features, len(feature_names)) ) - if spacing <= 0: - raise ValueError("spacing must be > 0, given %d" % spacing) - - if decimals < 0: - raise ValueError("decimals must be >= 0, given %d" % decimals) - if isinstance(decision_tree, DecisionTreeClassifier): value_fmt = "{}{} weights: {}\n" if not show_weights: diff --git a/sklearn/tree/tests/test_export.py b/sklearn/tree/tests/test_export.py index 8865cb724a02a..5b4d581951cac 100644 --- a/sklearn/tree/tests/test_export.py +++ b/sklearn/tree/tests/test_export.py @@ -350,10 +350,6 @@ def test_precision(): def test_export_text_errors(): clf = DecisionTreeClassifier(max_depth=2, random_state=0) clf.fit(X, y) - - err_msg = "max_depth bust be >= 0, given -1" - with pytest.raises(ValueError, match=err_msg): - export_text(clf, max_depth=-1) err_msg = "feature_names must contain 2 elements, got 1" with pytest.raises(ValueError, match=err_msg): export_text(clf, feature_names=["a"]) @@ -364,12 +360,6 @@ def test_export_text_errors(): ) with pytest.raises(ValueError, match=err_msg): export_text(clf, class_names=["a"]) - err_msg = "decimals must be >= 0, given -1" - with pytest.raises(ValueError, match=err_msg): - export_text(clf, decimals=-1) - err_msg = "spacing must be > 0, given 0" - with pytest.raises(ValueError, match=err_msg): - export_text(clf, spacing=0) def test_export_text(): From 13149ab4f4a6b14c65e900411372753fd5d47d49 Mon Sep 17 00:00:00 2001 From: Rahil Parikh <75483881+rprkh@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:41:32 +0530 Subject: [PATCH 061/230] DOC impact of `tol` for solvers in RidgeClassifier (#25530) --- sklearn/linear_model/_ridge.py | 38 ++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/sklearn/linear_model/_ridge.py b/sklearn/linear_model/_ridge.py index fef5025bf5479..18f9f8aa5ee43 100644 --- a/sklearn/linear_model/_ridge.py +++ b/sklearn/linear_model/_ridge.py @@ -962,8 +962,23 @@ class Ridge(MultiOutputMixin, RegressorMixin, _BaseRidge): For 'lbfgs' solver, the default value is 15000. tol : float, default=1e-4 - Precision of the solution. Note that `tol` has no effect for solvers 'svd' and - 'cholesky'. + The precision of the solution (`coef_`) is determined by `tol` which + specifies a different convergence criterion for each solver: + + - 'svd': `tol` has no impact. + + - 'cholesky': `tol` has no impact. + + - 'sparse_cg': norm of residuals smaller than `tol`. + + - 'lsqr': `tol` is set as atol and btol of scipy.sparse.linalg.lsqr, + which control the norm of the residual vector in terms of the norms of + matrix and coefficients. + + - 'sag' and 'saga': relative change of coef smaller than `tol`. + + - 'lbfgs': maximum of the absolute (projected) gradient=max|residuals| + smaller than `tol`. .. versionchanged:: 1.2 Default value changed from 1e-3 to 1e-4 for consistency with other linear @@ -1252,8 +1267,23 @@ class RidgeClassifier(_RidgeClassifierMixin, _BaseRidge): The default value is determined by scipy.sparse.linalg. tol : float, default=1e-4 - Precision of the solution. Note that `tol` has no effect for solvers 'svd' and - 'cholesky'. + The precision of the solution (`coef_`) is determined by `tol` which + specifies a different convergence criterion for each solver: + + - 'svd': `tol` has no impact. + + - 'cholesky': `tol` has no impact. + + - 'sparse_cg': norm of residuals smaller than `tol`. + + - 'lsqr': `tol` is set as atol and btol of scipy.sparse.linalg.lsqr, + which control the norm of the residual vector in terms of the norms of + matrix and coefficients. + + - 'sag' and 'saga': relative change of coef smaller than `tol`. + + - 'lbfgs': maximum of the absolute (projected) gradient=max|residuals| + smaller than `tol`. .. versionchanged:: 1.2 Default value changed from 1e-3 to 1e-4 for consistency with other linear From 1f4b8821d4574df5c559ad986ffaaa9ad05da283 Mon Sep 17 00:00:00 2001 From: Bharat Raghunathan Date: Fri, 17 Mar 2023 17:46:46 +0530 Subject: [PATCH 062/230] MAINT Parameters validation for metrics.hinge_loss (#25880) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/metrics/_classification.py | 12 ++++++++++-- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/sklearn/metrics/_classification.py b/sklearn/metrics/_classification.py index 187863e44515f..50425bb082d39 100644 --- a/sklearn/metrics/_classification.py +++ b/sklearn/metrics/_classification.py @@ -2864,6 +2864,14 @@ def log_loss( return _weighted_sum(loss, sample_weight, normalize) +@validate_params( + { + "y_true": ["array-like"], + "pred_decision": ["array-like"], + "labels": ["array-like", None], + "sample_weight": ["array-like", None], + } +) def hinge_loss(y_true, pred_decision, *, labels=None, sample_weight=None): """Average hinge loss (non-regularized). @@ -2883,11 +2891,11 @@ def hinge_loss(y_true, pred_decision, *, labels=None, sample_weight=None): Parameters ---------- - y_true : array of shape (n_samples,) + y_true : array-like of shape (n_samples,) True target, consisting of integers of two values. The positive label must be greater than the negative label. - pred_decision : array of shape (n_samples,) or (n_samples, n_classes) + pred_decision : array-like of shape (n_samples,) or (n_samples, n_classes) Predicted decisions, as output by decision_function (floats). labels : array-like, default=None diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 7477d614da4c7..1cdc2ea9e85a2 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -163,6 +163,7 @@ def _check_function_param_validation( "sklearn.metrics.fbeta_score", "sklearn.metrics.get_scorer", "sklearn.metrics.hamming_loss", + "sklearn.metrics.hinge_loss", "sklearn.metrics.jaccard_score", "sklearn.metrics.label_ranking_average_precision_score", "sklearn.metrics.label_ranking_loss", From 88eedab87c29fb8d581f8d27a73b77129a4c5cd1 Mon Sep 17 00:00:00 2001 From: Sortofamudkip Date: Fri, 17 Mar 2023 13:20:27 +0100 Subject: [PATCH 063/230] MAINT Parameters validation for metrics.ndcg_score (#25885) --- sklearn/metrics/_ranking.py | 15 ++++++++++++--- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sklearn/metrics/_ranking.py b/sklearn/metrics/_ranking.py index d5e2d3442259f..ec7e68bde764a 100644 --- a/sklearn/metrics/_ranking.py +++ b/sklearn/metrics/_ranking.py @@ -1620,6 +1620,15 @@ def _ndcg_sample_scores(y_true, y_score, k=None, ignore_ties=False): return gain +@validate_params( + { + "y_true": ["array-like"], + "y_score": ["array-like"], + "k": [Interval(Integral, 1, None, closed="left"), None], + "sample_weight": ["array-like", None], + "ignore_ties": ["boolean"], + } +) def ndcg_score(y_true, y_score, *, k=None, sample_weight=None, ignore_ties=False): """Compute Normalized Discounted Cumulative Gain. @@ -1633,7 +1642,7 @@ def ndcg_score(y_true, y_score, *, k=None, sample_weight=None, ignore_ties=False Parameters ---------- - y_true : ndarray of shape (n_samples, n_labels) + y_true : array-like of shape (n_samples, n_labels) True targets of multilabel classification, or true scores of entities to be ranked. Negative values in `y_true` may result in an output that is not between 0 and 1. @@ -1641,7 +1650,7 @@ def ndcg_score(y_true, y_score, *, k=None, sample_weight=None, ignore_ties=False .. versionchanged:: 1.2 These negative values are deprecated, and will raise an error in v1.4. - y_score : ndarray of shape (n_samples, n_labels) + y_score : array-like of shape (n_samples, n_labels) Target scores, can either be probability estimates, confidence values, or non-thresholded measure of decisions (as returned by "decision_function" on some classifiers). @@ -1650,7 +1659,7 @@ def ndcg_score(y_true, y_score, *, k=None, sample_weight=None, ignore_ties=False Only consider the highest k scores in the ranking. If `None`, use all outputs. - sample_weight : ndarray of shape (n_samples,), default=None + sample_weight : array-like of shape (n_samples,), default=None Sample weights. If `None`, all samples are given the same weight. ignore_ties : bool, default=False diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 1cdc2ea9e85a2..f72d622e53902 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -180,6 +180,7 @@ def _check_function_param_validation( "sklearn.metrics.median_absolute_error", "sklearn.metrics.multilabel_confusion_matrix", "sklearn.metrics.mutual_info_score", + "sklearn.metrics.ndcg_score", "sklearn.metrics.pairwise.additive_chi2_kernel", "sklearn.metrics.precision_recall_curve", "sklearn.metrics.precision_recall_fscore_support", From 6dd9f5beb68446341222f725f1f9163d2fdffcfc Mon Sep 17 00:00:00 2001 From: Gleb Levitski <36483986+glevv@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:26:09 +0300 Subject: [PATCH 064/230] ENH KMeans initialization account for sample weights (#25752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: jeremiedbb Co-authored-by: Guillaume Lemaitre Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- doc/whats_new/v1.3.rst | 20 +++- sklearn/cluster/_bicluster.py | 2 +- sklearn/cluster/_bisect_k_means.py | 26 +++-- sklearn/cluster/_kmeans.py | 95 ++++++++++++++----- sklearn/cluster/tests/test_bisect_k_means.py | 29 +++--- sklearn/cluster/tests/test_k_means.py | 65 +++++++++++++ .../manifold/tests/test_spectral_embedding.py | 2 +- 7 files changed, 189 insertions(+), 50 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index cf5003d04fbf2..00f0275bae8b8 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -34,6 +34,15 @@ random sampling procedures. :class:`decomposition.MiniBatchNMF` which can produce different results than previous versions. :pr:`25438` by :user:`Yotam Avidar-Constantini `. +- |Enhancement| The `sample_weight` parameter now will be used in centroids + initialization for :class:`cluster.KMeans`, :class:`cluster.BisectingKMeans` + and :class:`cluster.MiniBatchKMeans`. + This change will break backward compatibility, since numbers generated + from same random seeds will be different. + :pr:`25752` by :user:`Gleb Levitski `, + :user:`Jérémie du Boisberranger `, + :user:`Guillaume Lemaitre `. + Changes impacting all modules ----------------------------- @@ -154,9 +163,18 @@ Changelog - |API| The `sample_weight` parameter in `predict` for :meth:`cluster.KMeans.predict` and :meth:`cluster.MiniBatchKMeans.predict` - is now deprecated and will be removed in v1.5. + is now deprecated and will be removed in v1.5. :pr:`25251` by :user:`Gleb Levitski `. +- |Enhancement| The `sample_weight` parameter now will be used in centroids + initialization for :class:`cluster.KMeans`, :class:`cluster.BisectingKMeans` + and :class:`cluster.MiniBatchKMeans`. + This change will break backward compatibility, since numbers generated + from same random seeds will be different. + :pr:`25752` by :user:`Gleb Levitski `, + :user:`Jérémie du Boisberranger `, + :user:`Guillaume Lemaitre `. + :mod:`sklearn.datasets` ....................... diff --git a/sklearn/cluster/_bicluster.py b/sklearn/cluster/_bicluster.py index 73cb1c3529016..ba837bacc99d5 100644 --- a/sklearn/cluster/_bicluster.py +++ b/sklearn/cluster/_bicluster.py @@ -487,7 +487,7 @@ class SpectralBiclustering(BaseSpectral): >>> clustering.row_labels_ array([1, 1, 1, 0, 0, 0], dtype=int32) >>> clustering.column_labels_ - array([0, 1], dtype=int32) + array([1, 0], dtype=int32) >>> clustering SpectralBiclustering(n_clusters=2, random_state=0) """ diff --git a/sklearn/cluster/_bisect_k_means.py b/sklearn/cluster/_bisect_k_means.py index b860596c03540..d6c419a1f650d 100644 --- a/sklearn/cluster/_bisect_k_means.py +++ b/sklearn/cluster/_bisect_k_means.py @@ -190,18 +190,18 @@ class BisectingKMeans(_BaseKMeans): -------- >>> from sklearn.cluster import BisectingKMeans >>> import numpy as np - >>> X = np.array([[1, 2], [1, 4], [1, 0], - ... [10, 2], [10, 4], [10, 0], - ... [10, 6], [10, 8], [10, 10]]) + >>> X = np.array([[1, 1], [10, 1], [3, 1], + ... [10, 0], [2, 1], [10, 2], + ... [10, 8], [10, 9], [10, 10]]) >>> bisect_means = BisectingKMeans(n_clusters=3, random_state=0).fit(X) >>> bisect_means.labels_ - array([2, 2, 2, 0, 0, 0, 1, 1, 1], dtype=int32) + array([0, 2, 0, 2, 0, 2, 1, 1, 1], dtype=int32) >>> bisect_means.predict([[0, 0], [12, 3]]) - array([2, 0], dtype=int32) + array([0, 2], dtype=int32) >>> bisect_means.cluster_centers_ - array([[10., 2.], - [10., 8.], - [ 1., 2.]]) + array([[ 2., 1.], + [10., 9.], + [10., 1.]]) """ _parameter_constraints: dict = { @@ -309,7 +309,12 @@ def _bisect(self, X, x_squared_norms, sample_weight, cluster_to_bisect): # Repeating `n_init` times to obtain best clusters for _ in range(self.n_init): centers_init = self._init_centroids( - X, x_squared_norms, self.init, self._random_state, n_centroids=2 + X, + x_squared_norms=x_squared_norms, + init=self.init, + random_state=self._random_state, + n_centroids=2, + sample_weight=sample_weight, ) labels, inertia, centers, _ = self._kmeans_single( @@ -361,7 +366,8 @@ def fit(self, X, y=None, sample_weight=None): sample_weight : array-like of shape (n_samples,), default=None The weights for each observation in X. If None, all observations - are assigned equal weight. + are assigned equal weight. `sample_weight` is not used during + initialization if `init` is a callable. Returns ------- diff --git a/sklearn/cluster/_kmeans.py b/sklearn/cluster/_kmeans.py index 11d2b81cd552f..42aafcf3ce733 100644 --- a/sklearn/cluster/_kmeans.py +++ b/sklearn/cluster/_kmeans.py @@ -63,13 +63,20 @@ { "X": ["array-like", "sparse matrix"], "n_clusters": [Interval(Integral, 1, None, closed="left")], + "sample_weight": ["array-like", None], "x_squared_norms": ["array-like", None], "random_state": ["random_state"], "n_local_trials": [Interval(Integral, 1, None, closed="left"), None], } ) def kmeans_plusplus( - X, n_clusters, *, x_squared_norms=None, random_state=None, n_local_trials=None + X, + n_clusters, + *, + sample_weight=None, + x_squared_norms=None, + random_state=None, + n_local_trials=None, ): """Init n_clusters seeds according to k-means++. @@ -83,6 +90,13 @@ def kmeans_plusplus( n_clusters : int The number of centroids to initialize. + sample_weight : array-like of shape (n_samples,), default=None + The weights for each observation in `X`. If `None`, all observations + are assigned equal weight. `sample_weight` is ignored if `init` + is a callable or a user provided array. + + .. versionadded:: 1.3 + x_squared_norms : array-like of shape (n_samples,), default=None Squared Euclidean norm of each data point. @@ -125,13 +139,14 @@ def kmeans_plusplus( ... [10, 2], [10, 4], [10, 0]]) >>> centers, indices = kmeans_plusplus(X, n_clusters=2, random_state=0) >>> centers - array([[10, 4], + array([[10, 2], [ 1, 0]]) >>> indices - array([4, 2]) + array([3, 2]) """ # Check data check_array(X, accept_sparse="csr", dtype=[np.float64, np.float32]) + sample_weight = _check_sample_weight(sample_weight, X, dtype=X.dtype) if X.shape[0] < n_clusters: raise ValueError( @@ -154,13 +169,15 @@ def kmeans_plusplus( # Call private k-means++ centers, indices = _kmeans_plusplus( - X, n_clusters, x_squared_norms, random_state, n_local_trials + X, n_clusters, x_squared_norms, sample_weight, random_state, n_local_trials ) return centers, indices -def _kmeans_plusplus(X, n_clusters, x_squared_norms, random_state, n_local_trials=None): +def _kmeans_plusplus( + X, n_clusters, x_squared_norms, sample_weight, random_state, n_local_trials=None +): """Computational component for initialization of n_clusters by k-means++. Prior validation of data is assumed. @@ -172,6 +189,9 @@ def _kmeans_plusplus(X, n_clusters, x_squared_norms, random_state, n_local_trial n_clusters : int The number of seeds to choose. + sample_weight : ndarray of shape (n_samples,) + The weights for each observation in `X`. + x_squared_norms : ndarray of shape (n_samples,) Squared Euclidean norm of each data point. @@ -206,7 +226,7 @@ def _kmeans_plusplus(X, n_clusters, x_squared_norms, random_state, n_local_trial n_local_trials = 2 + int(np.log(n_clusters)) # Pick first center randomly and track index of point - center_id = random_state.randint(n_samples) + center_id = random_state.choice(n_samples, p=sample_weight / sample_weight.sum()) indices = np.full(n_clusters, -1, dtype=int) if sp.issparse(X): centers[0] = X[center_id].toarray() @@ -218,14 +238,16 @@ def _kmeans_plusplus(X, n_clusters, x_squared_norms, random_state, n_local_trial closest_dist_sq = _euclidean_distances( centers[0, np.newaxis], X, Y_norm_squared=x_squared_norms, squared=True ) - current_pot = closest_dist_sq.sum() + current_pot = closest_dist_sq @ sample_weight # Pick the remaining n_clusters-1 points for c in range(1, n_clusters): # Choose center candidates by sampling with probability proportional # to the squared distance to the closest existing center rand_vals = random_state.uniform(size=n_local_trials) * current_pot - candidate_ids = np.searchsorted(stable_cumsum(closest_dist_sq), rand_vals) + candidate_ids = np.searchsorted( + stable_cumsum(sample_weight * closest_dist_sq), rand_vals + ) # XXX: numerical imprecision can result in a candidate_id out of range np.clip(candidate_ids, None, closest_dist_sq.size - 1, out=candidate_ids) @@ -236,7 +258,7 @@ def _kmeans_plusplus(X, n_clusters, x_squared_norms, random_state, n_local_trial # update closest distances squared and potential for each candidate np.minimum(closest_dist_sq, distance_to_candidates, out=distance_to_candidates) - candidates_pot = distance_to_candidates.sum(axis=1) + candidates_pot = distance_to_candidates @ sample_weight.reshape(-1, 1) # Decide which candidate is the best best_candidate = np.argmin(candidates_pot) @@ -323,7 +345,8 @@ def k_means( sample_weight : array-like of shape (n_samples,), default=None The weights for each observation in `X`. If `None`, all observations - are assigned equal weight. + are assigned equal weight. `sample_weight` is not used during + initialization if `init` is a callable or a user provided array. init : {'k-means++', 'random'}, callable or array-like of shape \ (n_clusters, n_features), default='k-means++' @@ -939,7 +962,14 @@ def _check_test_data(self, X): return X def _init_centroids( - self, X, x_squared_norms, init, random_state, init_size=None, n_centroids=None + self, + X, + x_squared_norms, + init, + random_state, + init_size=None, + n_centroids=None, + sample_weight=None, ): """Compute the initial centroids. @@ -969,6 +999,11 @@ def _init_centroids( If left to 'None' the number of centroids will be equal to number of clusters to form (self.n_clusters) + sample_weight : ndarray of shape (n_samples,), default=None + The weights for each observation in X. If None, all observations + are assigned equal weight. `sample_weight` is not used during + initialization if `init` is a callable or a user provided array. + Returns ------- centers : ndarray of shape (n_clusters, n_features) @@ -981,6 +1016,7 @@ def _init_centroids( X = X[init_indices] x_squared_norms = x_squared_norms[init_indices] n_samples = X.shape[0] + sample_weight = sample_weight[init_indices] if isinstance(init, str) and init == "k-means++": centers, _ = _kmeans_plusplus( @@ -988,9 +1024,15 @@ def _init_centroids( n_clusters, random_state=random_state, x_squared_norms=x_squared_norms, + sample_weight=sample_weight, ) elif isinstance(init, str) and init == "random": - seeds = random_state.permutation(n_samples)[:n_clusters] + seeds = random_state.choice( + n_samples, + size=n_clusters, + replace=False, + p=sample_weight / sample_weight.sum(), + ) centers = X[seeds] elif _is_arraylike_not_scalar(self.init): centers = init @@ -1412,7 +1454,8 @@ def fit(self, X, y=None, sample_weight=None): sample_weight : array-like of shape (n_samples,), default=None The weights for each observation in X. If None, all observations - are assigned equal weight. + are assigned equal weight. `sample_weight` is not used during + initialization if `init` is a callable or a user provided array. .. versionadded:: 0.20 @@ -1468,7 +1511,11 @@ def fit(self, X, y=None, sample_weight=None): for i in range(self._n_init): # Initialize centers centers_init = self._init_centroids( - X, x_squared_norms=x_squared_norms, init=init, random_state=random_state + X, + x_squared_norms=x_squared_norms, + init=init, + random_state=random_state, + sample_weight=sample_weight, ) if self.verbose: print("Initialization complete") @@ -1545,7 +1592,7 @@ def _mini_batch_step( Squared euclidean norm of each data point. sample_weight : ndarray of shape (n_samples,) - The weights for each observation in X. + The weights for each observation in `X`. centers : ndarray of shape (n_clusters, n_features) The cluster centers before the current iteration @@ -1818,10 +1865,10 @@ class MiniBatchKMeans(_BaseKMeans): >>> kmeans = kmeans.partial_fit(X[0:6,:]) >>> kmeans = kmeans.partial_fit(X[6:12,:]) >>> kmeans.cluster_centers_ - array([[2. , 1. ], - [3.5, 4.5]]) + array([[3.375, 3. ], + [0.75 , 0.5 ]]) >>> kmeans.predict([[0, 0], [4, 4]]) - array([0, 1], dtype=int32) + array([1, 0], dtype=int32) >>> # fit on the whole data >>> kmeans = MiniBatchKMeans(n_clusters=2, ... random_state=0, @@ -1829,8 +1876,8 @@ class MiniBatchKMeans(_BaseKMeans): ... max_iter=10, ... n_init="auto").fit(X) >>> kmeans.cluster_centers_ - array([[3.97727273, 2.43181818], - [1.125 , 1.6 ]]) + array([[3.55102041, 2.48979592], + [1.06896552, 1. ]]) >>> kmeans.predict([[0, 0], [4, 4]]) array([1, 0], dtype=int32) """ @@ -2015,7 +2062,8 @@ def fit(self, X, y=None, sample_weight=None): sample_weight : array-like of shape (n_samples,), default=None The weights for each observation in X. If None, all observations - are assigned equal weight. + are assigned equal weight. `sample_weight` is not used during + initialization if `init` is a callable or a user provided array. .. versionadded:: 0.20 @@ -2070,6 +2118,7 @@ def fit(self, X, y=None, sample_weight=None): init=init, random_state=random_state, init_size=self._init_size, + sample_weight=sample_weight, ) # Compute inertia on a validation set. @@ -2170,7 +2219,8 @@ def partial_fit(self, X, y=None, sample_weight=None): sample_weight : array-like of shape (n_samples,), default=None The weights for each observation in X. If None, all observations - are assigned equal weight. + are assigned equal weight. `sample_weight` is not used during + initialization if `init` is a callable or a user provided array. Returns ------- @@ -2220,6 +2270,7 @@ def partial_fit(self, X, y=None, sample_weight=None): init=init, random_state=self._random_state, init_size=self._init_size, + sample_weight=sample_weight, ) # Initialize counts diff --git a/sklearn/cluster/tests/test_bisect_k_means.py b/sklearn/cluster/tests/test_bisect_k_means.py index 5f69ac1353a39..c79cd0bcca3e8 100644 --- a/sklearn/cluster/tests/test_bisect_k_means.py +++ b/sklearn/cluster/tests/test_bisect_k_means.py @@ -4,34 +4,33 @@ from sklearn.utils._testing import assert_array_equal, assert_allclose from sklearn.cluster import BisectingKMeans +from sklearn.metrics import v_measure_score @pytest.mark.parametrize("bisecting_strategy", ["biggest_inertia", "largest_cluster"]) -def test_three_clusters(bisecting_strategy): +@pytest.mark.parametrize("init", ["k-means++", "random"]) +def test_three_clusters(bisecting_strategy, init): """Tries to perform bisect k-means for three clusters to check if splitting data is performed correctly. """ - - # X = np.array([[1, 2], [1, 4], [1, 0], - # [10, 2], [10, 4], [10, 0], - # [10, 6], [10, 8], [10, 10]]) - - # X[0][1] swapped with X[1][1] intentionally for checking labeling X = np.array( - [[1, 2], [10, 4], [1, 0], [10, 2], [1, 4], [10, 0], [10, 6], [10, 8], [10, 10]] + [[1, 1], [10, 1], [3, 1], [10, 0], [2, 1], [10, 2], [10, 8], [10, 9], [10, 10]] ) bisect_means = BisectingKMeans( - n_clusters=3, random_state=0, bisecting_strategy=bisecting_strategy + n_clusters=3, + random_state=0, + bisecting_strategy=bisecting_strategy, + init=init, ) bisect_means.fit(X) - expected_centers = [[10, 2], [10, 8], [1, 2]] - expected_predict = [2, 0] - expected_labels = [2, 0, 2, 0, 2, 0, 1, 1, 1] + expected_centers = [[2, 1], [10, 1], [10, 9]] + expected_labels = [0, 1, 0, 1, 0, 1, 2, 2, 2] - assert_allclose(expected_centers, bisect_means.cluster_centers_) - assert_array_equal(expected_predict, bisect_means.predict([[0, 0], [12, 3]])) - assert_array_equal(expected_labels, bisect_means.labels_) + assert_allclose( + sorted(expected_centers), sorted(bisect_means.cluster_centers_.tolist()) + ) + assert_allclose(v_measure_score(expected_labels, bisect_means.labels_), 1.0) def test_sparse(): diff --git a/sklearn/cluster/tests/test_k_means.py b/sklearn/cluster/tests/test_k_means.py index 9ae7510c45dba..c11d5dd3165c0 100644 --- a/sklearn/cluster/tests/test_k_means.py +++ b/sklearn/cluster/tests/test_k_means.py @@ -17,6 +17,7 @@ from sklearn.utils.extmath import row_norms from sklearn.metrics import pairwise_distances from sklearn.metrics import pairwise_distances_argmin +from sklearn.metrics.pairwise import euclidean_distances from sklearn.metrics.cluster import v_measure_score from sklearn.cluster import KMeans, k_means, kmeans_plusplus from sklearn.cluster import MiniBatchKMeans @@ -1276,3 +1277,67 @@ def test_predict_does_not_change_cluster_centers(is_sparse): y_pred2 = kmeans.predict(X) assert_array_equal(y_pred1, y_pred2) + + +@pytest.mark.parametrize("init", ["k-means++", "random"]) +def test_sample_weight_init(init, global_random_seed): + """Check that sample weight is used during init. + + `_init_centroids` is shared across all classes inheriting from _BaseKMeans so + it's enough to check for KMeans. + """ + rng = np.random.RandomState(global_random_seed) + X, _ = make_blobs( + n_samples=200, n_features=10, centers=10, random_state=global_random_seed + ) + x_squared_norms = row_norms(X, squared=True) + + kmeans = KMeans() + clusters_weighted = kmeans._init_centroids( + X=X, + x_squared_norms=x_squared_norms, + init=init, + sample_weight=rng.uniform(size=X.shape[0]), + n_centroids=5, + random_state=np.random.RandomState(global_random_seed), + ) + clusters = kmeans._init_centroids( + X=X, + x_squared_norms=x_squared_norms, + init=init, + sample_weight=np.ones(X.shape[0]), + n_centroids=5, + random_state=np.random.RandomState(global_random_seed), + ) + with pytest.raises(AssertionError): + assert_allclose(clusters_weighted, clusters) + + +@pytest.mark.parametrize("init", ["k-means++", "random"]) +def test_sample_weight_zero(init, global_random_seed): + """Check that if sample weight is 0, this sample won't be chosen. + + `_init_centroids` is shared across all classes inheriting from _BaseKMeans so + it's enough to check for KMeans. + """ + rng = np.random.RandomState(global_random_seed) + X, _ = make_blobs( + n_samples=100, n_features=5, centers=5, random_state=global_random_seed + ) + sample_weight = rng.uniform(size=X.shape[0]) + sample_weight[::2] = 0 + x_squared_norms = row_norms(X, squared=True) + + kmeans = KMeans() + clusters_weighted = kmeans._init_centroids( + X=X, + x_squared_norms=x_squared_norms, + init=init, + sample_weight=sample_weight, + n_centroids=10, + random_state=np.random.RandomState(global_random_seed), + ) + # No center should be one of the 0 sample weight point + # (i.e. be at a distance=0 from it) + d = euclidean_distances(X[::2], clusters_weighted) + assert not np.any(np.isclose(d, 0)) diff --git a/sklearn/manifold/tests/test_spectral_embedding.py b/sklearn/manifold/tests/test_spectral_embedding.py index 7de5688e8afa0..2fb833b67f99f 100644 --- a/sklearn/manifold/tests/test_spectral_embedding.py +++ b/sklearn/manifold/tests/test_spectral_embedding.py @@ -336,7 +336,7 @@ def test_pipeline_spectral_clustering(seed=36): random_state=random_state, ) for se in [se_rbf, se_knn]: - km = KMeans(n_clusters=n_clusters, random_state=random_state, n_init="auto") + km = KMeans(n_clusters=n_clusters, random_state=random_state, n_init=10) km.fit(se.fit_transform(S)) assert_array_almost_equal( normalized_mutual_info_score(km.labels_, true_labels), 1.0, 2 From d294c721bb961df5b7eafd49db2e9fcbce738cd4 Mon Sep 17 00:00:00 2001 From: Sortofamudkip Date: Fri, 17 Mar 2023 17:06:28 +0100 Subject: [PATCH 065/230] TST use global_random_seed in sklearn/tests/test_dummy.py (#25884) --- sklearn/tests/test_dummy.py | 74 +++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/sklearn/tests/test_dummy.py b/sklearn/tests/test_dummy.py index 546fba1a8a3a3..1beabe15d5ff9 100644 --- a/sklearn/tests/test_dummy.py +++ b/sklearn/tests/test_dummy.py @@ -124,10 +124,10 @@ def test_most_frequent_and_prior_strategy_multioutput(): _check_behavior_2d(clf) -def test_stratified_strategy(): +def test_stratified_strategy(global_random_seed): X = [[0]] * 5 # ignored y = [1, 2, 1, 1, 2] - clf = DummyClassifier(strategy="stratified", random_state=0) + clf = DummyClassifier(strategy="stratified", random_state=global_random_seed) clf.fit(X, y) X = [[0]] * 500 @@ -138,11 +138,11 @@ def test_stratified_strategy(): _check_predict_proba(clf, X, y) -def test_stratified_strategy_multioutput(): +def test_stratified_strategy_multioutput(global_random_seed): X = [[0]] * 5 # ignored y = np.array([[2, 1], [2, 2], [1, 1], [1, 2], [1, 1]]) - clf = DummyClassifier(strategy="stratified", random_state=0) + clf = DummyClassifier(strategy="stratified", random_state=global_random_seed) clf.fit(X, y) X = [[0]] * 500 @@ -157,10 +157,10 @@ def test_stratified_strategy_multioutput(): _check_behavior_2d(clf) -def test_uniform_strategy(): +def test_uniform_strategy(global_random_seed): X = [[0]] * 4 # ignored y = [1, 2, 1, 1] - clf = DummyClassifier(strategy="uniform", random_state=0) + clf = DummyClassifier(strategy="uniform", random_state=global_random_seed) clf.fit(X, y) X = [[0]] * 500 @@ -171,10 +171,10 @@ def test_uniform_strategy(): _check_predict_proba(clf, X, y) -def test_uniform_strategy_multioutput(): +def test_uniform_strategy_multioutput(global_random_seed): X = [[0]] * 4 # ignored y = np.array([[2, 1], [2, 2], [1, 2], [1, 1]]) - clf = DummyClassifier(strategy="uniform", random_state=0) + clf = DummyClassifier(strategy="uniform", random_state=global_random_seed) clf.fit(X, y) X = [[0]] * 500 @@ -216,24 +216,28 @@ def test_classifier_score_with_None(y, y_test): @pytest.mark.parametrize( "strategy", ["stratified", "most_frequent", "prior", "uniform", "constant"] ) -def test_classifier_prediction_independent_of_X(strategy): +def test_classifier_prediction_independent_of_X(strategy, global_random_seed): y = [0, 2, 1, 1] X1 = [[0]] * 4 - clf1 = DummyClassifier(strategy=strategy, random_state=0, constant=0) + clf1 = DummyClassifier( + strategy=strategy, random_state=global_random_seed, constant=0 + ) clf1.fit(X1, y) predictions1 = clf1.predict(X1) X2 = [[1]] * 4 - clf2 = DummyClassifier(strategy=strategy, random_state=0, constant=0) + clf2 = DummyClassifier( + strategy=strategy, random_state=global_random_seed, constant=0 + ) clf2.fit(X2, y) predictions2 = clf2.predict(X2) assert_array_equal(predictions1, predictions2) -def test_mean_strategy_regressor(): +def test_mean_strategy_regressor(global_random_seed): - random_state = np.random.RandomState(seed=1) + random_state = np.random.RandomState(seed=global_random_seed) X = [[0]] * 4 # ignored y = random_state.randn(4) @@ -243,9 +247,9 @@ def test_mean_strategy_regressor(): assert_array_equal(reg.predict(X), [np.mean(y)] * len(X)) -def test_mean_strategy_multioutput_regressor(): +def test_mean_strategy_multioutput_regressor(global_random_seed): - random_state = np.random.RandomState(seed=1) + random_state = np.random.RandomState(seed=global_random_seed) X_learn = random_state.randn(10, 10) y_learn = random_state.randn(10, 5) @@ -271,9 +275,9 @@ def test_regressor_exceptions(): reg.predict([]) -def test_median_strategy_regressor(): +def test_median_strategy_regressor(global_random_seed): - random_state = np.random.RandomState(seed=1) + random_state = np.random.RandomState(seed=global_random_seed) X = [[0]] * 5 # ignored y = random_state.randn(5) @@ -283,9 +287,9 @@ def test_median_strategy_regressor(): assert_array_equal(reg.predict(X), [np.median(y)] * len(X)) -def test_median_strategy_multioutput_regressor(): +def test_median_strategy_multioutput_regressor(global_random_seed): - random_state = np.random.RandomState(seed=1) + random_state = np.random.RandomState(seed=global_random_seed) X_learn = random_state.randn(10, 10) y_learn = random_state.randn(10, 5) @@ -305,9 +309,9 @@ def test_median_strategy_multioutput_regressor(): _check_behavior_2d(est) -def test_quantile_strategy_regressor(): +def test_quantile_strategy_regressor(global_random_seed): - random_state = np.random.RandomState(seed=1) + random_state = np.random.RandomState(seed=global_random_seed) X = [[0]] * 5 # ignored y = random_state.randn(5) @@ -329,9 +333,9 @@ def test_quantile_strategy_regressor(): assert_array_equal(reg.predict(X), [np.percentile(y, q=30)] * len(X)) -def test_quantile_strategy_multioutput_regressor(): +def test_quantile_strategy_multioutput_regressor(global_random_seed): - random_state = np.random.RandomState(seed=1) + random_state = np.random.RandomState(seed=global_random_seed) X_learn = random_state.randn(10, 10) y_learn = random_state.randn(10, 5) @@ -382,9 +386,9 @@ def test_quantile_strategy_empty_train(): est.fit([], []) -def test_constant_strategy_regressor(): +def test_constant_strategy_regressor(global_random_seed): - random_state = np.random.RandomState(seed=1) + random_state = np.random.RandomState(seed=global_random_seed) X = [[0]] * 5 # ignored y = random_state.randn(5) @@ -401,9 +405,9 @@ def test_constant_strategy_regressor(): assert not isinstance(reg.constant, np.ndarray) -def test_constant_strategy_multioutput_regressor(): +def test_constant_strategy_multioutput_regressor(global_random_seed): - random_state = np.random.RandomState(seed=1) + random_state = np.random.RandomState(seed=global_random_seed) X_learn = random_state.randn(10, 10) y_learn = random_state.randn(10, 5) @@ -444,8 +448,8 @@ def test_constants_not_specified_regressor(): est.fit(X, y) -def test_constant_size_multioutput_regressor(): - random_state = np.random.RandomState(seed=1) +def test_constant_size_multioutput_regressor(global_random_seed): + random_state = np.random.RandomState(seed=global_random_seed) X = random_state.randn(10, 10) y = random_state.randn(10, 5) @@ -547,11 +551,11 @@ def test_constant_strategy_sparse_target(): ) -def test_uniform_strategy_sparse_target_warning(): +def test_uniform_strategy_sparse_target_warning(global_random_seed): X = [[0]] * 5 # ignored y = sp.csc_matrix(np.array([[2, 1], [2, 2], [1, 4], [4, 2], [1, 1]])) - clf = DummyClassifier(strategy="uniform", random_state=0) + clf = DummyClassifier(strategy="uniform", random_state=global_random_seed) with pytest.warns(UserWarning, match="the uniform strategy would not save memory"): clf.fit(X, y) @@ -565,11 +569,11 @@ def test_uniform_strategy_sparse_target_warning(): assert_almost_equal(p[4], 1 / 3, decimal=1) -def test_stratified_strategy_sparse_target(): +def test_stratified_strategy_sparse_target(global_random_seed): X = [[0]] * 5 # ignored y = sp.csc_matrix(np.array([[4, 1], [0, 0], [1, 1], [1, 4], [1, 1]])) - clf = DummyClassifier(strategy="stratified", random_state=0) + clf = DummyClassifier(strategy="stratified", random_state=global_random_seed) clf.fit(X, y) X = [[0]] * 500 @@ -599,8 +603,8 @@ def test_most_frequent_and_prior_strategy_sparse_target(): assert_array_equal(y_pred.toarray(), y_expected) -def test_dummy_regressor_sample_weight(n_samples=10): - random_state = np.random.RandomState(seed=1) +def test_dummy_regressor_sample_weight(global_random_seed, n_samples=10): + random_state = np.random.RandomState(seed=global_random_seed) X = [[0]] * n_samples y = random_state.rand(n_samples) From bebe3b4dba598dce6d481cf1ab0eec17d37f7862 Mon Sep 17 00:00:00 2001 From: Christian Lorentzen Date: Fri, 17 Mar 2023 17:09:58 +0100 Subject: [PATCH 066/230] DOC improve calibration user guide (#25687) --- doc/modules/calibration.rst | 76 +++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/doc/modules/calibration.rst b/doc/modules/calibration.rst index 1fcd1d501d100..e35a4a12cbb8a 100644 --- a/doc/modules/calibration.rst +++ b/doc/modules/calibration.rst @@ -30,16 +30,20 @@ approximately 80% actually belong to the positive class. Calibration curves ------------------ -Calibration curves (also known as reliability diagrams) compare how well the -probabilistic predictions of a binary classifier are calibrated. It plots -the true frequency of the positive label against its predicted probability, -for binned predictions. -The x axis represents the average predicted probability in each bin. The -y axis is the *fraction of positives*, i.e. the proportion of samples whose -class is the positive class (in each bin). The top calibration curve plot -is created with :func:`CalibrationDisplay.from_estimators`, which uses -:func:`calibration_curve` to calculate the per bin average predicted -probabilities and fraction of positives. +Calibration curves, also referred to as *reliability diagrams* (Wilks 1995 [2]_), +compare how well the probabilistic predictions of a binary classifier are calibrated. +It plots the frequency of the positive label (to be more precise, an estimation of the +*conditional event probability* :math:`P(Y=1|\text{predict\_proba})`) on the y-axis +against the predicted probability :term:`predict_proba` of a model on the x-axis. +The tricky part is to get values for the y-axis. +In scikit-learn, this is accomplished by binning the predictions such that the x-axis +represents the average predicted probability in each bin. +The y-axis is then the *fraction of positives* given the predictions of that bin, i.e. +the proportion of samples whose class is the positive class (in each bin). + +The top calibration curve plot is created with +:func:`CalibrationDisplay.from_estimator`, which uses :func:`calibration_curve` to +calculate the per bin average predicted probabilities and fraction of positives. :func:`CalibrationDisplay.from_estimator` takes as input a fitted classifier, which is used to calculate the predicted probabilities. The classifier thus must have :term:`predict_proba` method. For @@ -56,13 +60,16 @@ by showing the number of samples in each predicted probability bin. .. currentmodule:: sklearn.linear_model -:class:`LogisticRegression` returns well calibrated predictions by default as it directly -optimizes :ref:`log_loss`. In contrast, the other methods return biased probabilities; -with different biases per method: +:class:`LogisticRegression` returns well calibrated predictions by default as it has a +canonical link function for its loss, i.e. the logit-link for the :ref:`log_loss`. +This leads to the so-called **balance property**, see [7]_ and +:ref:`Logistic_regression`. +In contrast to that, the other shown models return biased probabilities; with +different biases per model. .. currentmodule:: sklearn.naive_bayes -:class:`GaussianNB` tends to push probabilities to 0 or 1 (note the counts +:class:`GaussianNB` (Naive Bayes) tends to push probabilities to 0 or 1 (note the counts in the histograms). This is mainly because it makes the assumption that features are conditionally independent given the class, which is not the case in this dataset which contains 2 redundant features. @@ -70,7 +77,7 @@ case in this dataset which contains 2 redundant features. .. currentmodule:: sklearn.ensemble :class:`RandomForestClassifier` shows the opposite behavior: the histograms -show peaks at approximately 0.2 and 0.9 probability, while probabilities +show peaks at probabilities approximately 0.2 and 0.9, while probabilities close to 0 or 1 are very rare. An explanation for this is given by Niculescu-Mizil and Caruana [1]_: "Methods such as bagging and random forests that average predictions from a base set of models can have @@ -85,18 +92,16 @@ predict values larger than 0 for this case, thus moving the average prediction of the bagged ensemble away from 0. We observe this effect most strongly with random forests because the base-level trees trained with random forests have relatively high variance due to feature subsetting." As -a result, the calibration curve also referred to as the reliability diagram -(Wilks 1995 [2]_) shows a characteristic sigmoid shape, indicating that the -classifier could trust its "intuition" more and return probabilities closer +a result, the calibration curve shows a characteristic sigmoid shape, indicating that +the classifier could trust its "intuition" more and return probabilities closer to 0 or 1 typically. .. currentmodule:: sklearn.svm -Linear Support Vector Classification (:class:`LinearSVC`) shows an even more -sigmoid curve than :class:`~sklearn.ensemble.RandomForestClassifier`, which is -typical for maximum-margin methods (compare Niculescu-Mizil and Caruana [1]_), -which focus on difficult to classify samples that are close to the decision -boundary (the support vectors). +:class:`LinearSVC` (SVC) shows an even more sigmoid curve than the random forest, which +is typical for maximum-margin methods (compare Niculescu-Mizil and Caruana [1]_), which +focus on difficult to classify samples that are close to the decision boundary (the +support vectors). Calibrating a classifier ------------------------ @@ -107,10 +112,11 @@ Calibrating a classifier consists of fitting a regressor (called a *calibrator*) that maps the output of the classifier (as given by :term:`decision_function` or :term:`predict_proba`) to a calibrated probability in [0, 1]. Denoting the output of the classifier for a given sample by :math:`f_i`, -the calibrator tries to predict :math:`p(y_i = 1 | f_i)`. +the calibrator tries to predict the conditional event probability +:math:`P(y_i = 1 | f_i)`. -The samples that are used to fit the calibrator should not be the same -samples used to fit the classifier, as this would introduce bias. +Ideally, the calibrator is fit on a dataset independent of the training data used to +fit the classifier in the first place. This is because performance of the classifier on its training data would be better than for novel data. Using the classifier output of training data to fit the calibrator would thus result in a biased calibrator that maps to @@ -200,22 +206,21 @@ the classifier output for each binary class is normally distributed with the same variance [6]_. This can be a problem for highly imbalanced classification problems, where outputs do not have equal variance. -In general this method is most effective when the un-calibrated model is -under-confident and has similar calibration errors for both high and low -outputs. +In general this method is most effective for small sample sizes or when the +un-calibrated model is under-confident and has similar calibration errors for both +high and low outputs. Isotonic ^^^^^^^^ The 'isotonic' method fits a non-parametric isotonic regressor, which outputs -a step-wise non-decreasing function (see :mod:`sklearn.isotonic`). It -minimizes: +a step-wise non-decreasing function, see :mod:`sklearn.isotonic`. It minimizes: .. math:: \sum_{i=1}^{n} (y_i - \hat{f}_i)^2 -subject to :math:`\hat{f}_i >= \hat{f}_j` whenever -:math:`f_i >= f_j`. :math:`y_i` is the true +subject to :math:`\hat{f}_i \geq \hat{f}_j` whenever +:math:`f_i \geq f_j`. :math:`y_i` is the true label of sample :math:`i` and :math:`\hat{f}_i` is the output of the calibrated classifier for sample :math:`i` (i.e., the calibrated probability). This method is more general when compared to 'sigmoid' as the only restriction @@ -277,3 +282,8 @@ one, a postprocessing is performed to normalize them. binary classifiers with beta calibration `_ Kull, M., Silva Filho, T. M., & Flach, P. (2017). + + .. [7] Mario V. Wüthrich, Michael Merz (2023). + :doi:`"Statistical Foundations of Actuarial Learning and its Applications" + <10.1007/978-3-031-12409-9>` + Springer Actuarial From 3377338d8787c520c08eb250f6295e043733e079 Mon Sep 17 00:00:00 2001 From: Ashwin Mathur <97467100+awinml@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:17:42 +0530 Subject: [PATCH 067/230] ENH Support for sparse matrices added to `sklearn.metrics.silhouette_samples` (#24677) Co-authored-by: Sahil Gupta Co-authored-by: Thomas J. Fan Co-authored-by: Guillaume Lemaitre --- doc/whats_new/v1.3.rst | 5 ++ sklearn/metrics/cluster/_unsupervised.py | 69 +++++++++++++------ .../cluster/tests/test_unsupervised.py | 55 +++++++++++++-- 3 files changed, 102 insertions(+), 27 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 00f0275bae8b8..477ce9ac9063a 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -282,6 +282,11 @@ Changelog - |Fix| :func:`metric.manhattan_distances` now supports readonly sparse datasets. :pr:`25432` by :user:`Julien Jerphanion `. +- |Enhancement| :class:`metrics.silhouette_samples` nows accepts a sparse + matrix of pairwise distances between samples, or a feature array. + :pr:`18723` by :user:`Sahil Gupta ` and + :pr:`24677` by :user:`Ashwin Mathur `. + - |Fix| :func:`log_loss` raises a warning if the values of the parameter `y_pred` are not normalized, instead of actually normalizing them in the metric. Starting from 1.5 this will raise an error. :pr:`25299` by :user:`Omar Salman `_ """ - X, labels = check_X_y(X, labels, accept_sparse=["csc", "csr"]) + X, labels = check_X_y(X, labels, accept_sparse=["csr"]) # Check for non-zero diagonal entries in precomputed distance matrix if metric == "precomputed": @@ -219,10 +244,10 @@ def silhouette_samples(X, labels, *, metric="euclidean", **kwds): ) if X.dtype.kind == "f": atol = np.finfo(X.dtype).eps * 100 - if np.any(np.abs(np.diagonal(X)) > atol): - raise ValueError(error_msg) - elif np.any(np.diagonal(X) != 0): # integral dtype - raise ValueError(error_msg) + if np.any(np.abs(X.diagonal()) > atol): + raise error_msg + elif np.any(X.diagonal() != 0): # integral dtype + raise error_msg le = LabelEncoder() labels = le.fit_transform(labels) diff --git a/sklearn/metrics/cluster/tests/test_unsupervised.py b/sklearn/metrics/cluster/tests/test_unsupervised.py index 22dd1a1bf1557..8be2fe5cdae99 100644 --- a/sklearn/metrics/cluster/tests/test_unsupervised.py +++ b/sklearn/metrics/cluster/tests/test_unsupervised.py @@ -1,14 +1,17 @@ import warnings import numpy as np -import scipy.sparse as sp import pytest -from scipy.sparse import csr_matrix + +from numpy.testing import assert_allclose +from scipy.sparse import csr_matrix, csc_matrix, dok_matrix, lil_matrix +from scipy.sparse import issparse from sklearn import datasets from sklearn.utils._testing import assert_array_equal from sklearn.metrics.cluster import silhouette_score from sklearn.metrics.cluster import silhouette_samples +from sklearn.metrics.cluster._unsupervised import _silhouette_reduce from sklearn.metrics import pairwise_distances from sklearn.metrics.cluster import calinski_harabasz_score from sklearn.metrics.cluster import davies_bouldin_score @@ -19,11 +22,12 @@ def test_silhouette(): dataset = datasets.load_iris() X_dense = dataset.data X_csr = csr_matrix(X_dense) - X_dok = sp.dok_matrix(X_dense) - X_lil = sp.lil_matrix(X_dense) + X_csc = csc_matrix(X_dense) + X_dok = dok_matrix(X_dense) + X_lil = lil_matrix(X_dense) y = dataset.target - for X in [X_dense, X_csr, X_dok, X_lil]: + for X in [X_dense, X_csr, X_csc, X_dok, X_lil]: D = pairwise_distances(X, metric="euclidean") # Given that the actual labels are used, we can assume that S would be # positive. @@ -282,6 +286,47 @@ def test_silhouette_nonzero_diag(dtype): silhouette_samples(dists, labels, metric="precomputed") +@pytest.mark.parametrize("to_sparse", (csr_matrix, csc_matrix, dok_matrix, lil_matrix)) +def test_silhouette_samples_precomputed_sparse(to_sparse): + """Check that silhouette_samples works for sparse matrices correctly.""" + X = np.array([[0.2, 0.1, 0.1, 0.2, 0.1, 1.6, 0.2, 0.1]], dtype=np.float32).T + y = [0, 0, 0, 0, 1, 1, 1, 1] + pdist_dense = pairwise_distances(X) + pdist_sparse = to_sparse(pdist_dense) + assert issparse(pdist_sparse) + output_with_sparse_input = silhouette_samples(pdist_sparse, y, metric="precomputed") + output_with_dense_input = silhouette_samples(pdist_dense, y, metric="precomputed") + assert_allclose(output_with_sparse_input, output_with_dense_input) + + +@pytest.mark.parametrize("to_sparse", (csr_matrix, csc_matrix, dok_matrix, lil_matrix)) +def test_silhouette_samples_euclidean_sparse(to_sparse): + """Check that silhouette_samples works for sparse matrices correctly.""" + X = np.array([[0.2, 0.1, 0.1, 0.2, 0.1, 1.6, 0.2, 0.1]], dtype=np.float32).T + y = [0, 0, 0, 0, 1, 1, 1, 1] + pdist_dense = pairwise_distances(X) + pdist_sparse = to_sparse(pdist_dense) + assert issparse(pdist_sparse) + output_with_sparse_input = silhouette_samples(pdist_sparse, y) + output_with_dense_input = silhouette_samples(pdist_dense, y) + assert_allclose(output_with_sparse_input, output_with_dense_input) + + +@pytest.mark.parametrize("to_non_csr_sparse", (csc_matrix, dok_matrix, lil_matrix)) +def test_silhouette_reduce(to_non_csr_sparse): + """Check for non-CSR input to private method `_silhouette_reduce`.""" + X = np.array([[0.2, 0.1, 0.1, 0.2, 0.1, 1.6, 0.2, 0.1]], dtype=np.float32).T + pdist_dense = pairwise_distances(X) + pdist_sparse = to_non_csr_sparse(pdist_dense) + y = [0, 0, 0, 0, 1, 1, 1, 1] + label_freqs = np.bincount(y) + with pytest.raises( + TypeError, + match="Expected CSR matrix. Please pass sparse matrix in CSR format.", + ): + _silhouette_reduce(pdist_sparse, start=0, labels=y, label_freqs=label_freqs) + + def assert_raises_on_only_one_label(func): """Assert message when there is only one label""" rng = np.random.RandomState(seed=0) From 59f3b32452b660706c53d0638dcaa7622892489f Mon Sep 17 00:00:00 2001 From: Veghit Date: Mon, 20 Mar 2023 11:11:30 +0200 Subject: [PATCH 068/230] MAINT validate_params for plot_tree (#25882) Co-authored-by: Itay --- sklearn/tests/test_public_functions.py | 1 + sklearn/tree/_export.py | 33 ++++++++++++++------------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index f72d622e53902..cf830c79ad0f7 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -194,6 +194,7 @@ def _check_function_param_validation( "sklearn.random_projection.johnson_lindenstrauss_min_dim", "sklearn.svm.l1_min_c", "sklearn.tree.export_text", + "sklearn.tree.plot_tree", "sklearn.utils.gen_batches", ] diff --git a/sklearn/tree/_export.py b/sklearn/tree/_export.py index c7bc0dd04c08f..3671c1a92334b 100644 --- a/sklearn/tree/_export.py +++ b/sklearn/tree/_export.py @@ -17,7 +17,7 @@ import numpy as np from ..utils.validation import check_is_fitted -from ..utils._param_validation import Interval, validate_params +from ..utils._param_validation import Interval, validate_params, StrOptions from ..base import is_classifier @@ -77,6 +77,23 @@ def __repr__(self): SENTINEL = Sentinel() +@validate_params( + { + "decision_tree": [DecisionTreeClassifier, DecisionTreeRegressor], + "max_depth": [Interval(Integral, 0, None, closed="left"), None], + "feature_names": [list, None], + "class_names": [list, None], + "label": [StrOptions({"all", "root", "none"})], + "filled": ["boolean"], + "impurity": ["boolean"], + "node_ids": ["boolean"], + "proportion": ["boolean"], + "rounded": ["boolean"], + "precision": [Interval(Integral, 0, None, closed="left"), None], + "ax": "no_validation", # delegate validation to matplotlib + "fontsize": [Interval(Integral, 0, None, closed="left"), None], + } +) def plot_tree( decision_tree, *, @@ -601,20 +618,6 @@ def __init__( ) self.fontsize = fontsize - # validate - if isinstance(precision, Integral): - if precision < 0: - raise ValueError( - "'precision' should be greater or equal to 0." - " Got {} instead.".format(precision) - ) - else: - raise ValueError( - "'precision' should be an integer. Got {} instead.".format( - type(precision) - ) - ) - # The depth of each node for plotting with 'leaf' option self.ranks = {"leaves": []} # The colors to render each node with From 41e211ca4ab2a4c6aca538eabbef9aa7d76d69fe Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Mon, 20 Mar 2023 12:18:52 +0100 Subject: [PATCH 069/230] MAINT add missing space in error message in SVM (#25913) --- sklearn/svm/_base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sklearn/svm/_base.py b/sklearn/svm/_base.py index 3fb213f5ea20d..a66dfce695871 100644 --- a/sklearn/svm/_base.py +++ b/sklearn/svm/_base.py @@ -268,9 +268,9 @@ def fit(self, X, y, sample_weight=None): dual_coef_finiteness = np.isfinite(dual_coef).all() if not (intercept_finiteness and dual_coef_finiteness): raise ValueError( - "The dual coefficients or intercepts are not finite. " - "The input data may contain large values and need to be" - "preprocessed." + "The dual coefficients or intercepts are not finite." + " The input data may contain large values and need to be" + " preprocessed." ) # Since, in the case of SVC and NuSVC, the number of models optimized by From 8198995cf99c4d248d76e6501da77d772a019fdd Mon Sep 17 00:00:00 2001 From: "Thomas J. Fan" Date: Mon, 20 Mar 2023 12:15:30 -0400 Subject: [PATCH 070/230] FIX Adds requires_y tag to TargetEncoder (#25917) --- sklearn/preprocessing/_target_encoder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sklearn/preprocessing/_target_encoder.py b/sklearn/preprocessing/_target_encoder.py index 1ae5102afcd59..078a308d7fe6e 100644 --- a/sklearn/preprocessing/_target_encoder.py +++ b/sklearn/preprocessing/_target_encoder.py @@ -339,3 +339,6 @@ def _transform_X_ordinal( for f_idx, encoding in enumerate(encodings): X_out[indices, f_idx] = encoding[X_ordinal[indices, f_idx]] X_out[X_unknown_mask[:, f_idx], f_idx] = y_mean + + def _more_tags(self): + return {"requires_y": True} From deaec61fb4d22b83f653ba5c992f21b433c1921b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Mon, 20 Mar 2023 17:20:46 +0100 Subject: [PATCH 071/230] MAINT Consistent cython types continued (#25810) --- sklearn/feature_extraction/_hashing_fast.pyx | 10 +- .../_argkmin.pxd.tp | 19 +- .../_argkmin.pyx.tp | 150 +++-- .../_argkmin_classmode.pyx.tp | 62 +- .../_base.pxd.tp | 78 ++- .../_base.pyx.tp | 138 ++--- .../_radius_neighbors.pxd.tp | 36 +- .../_radius_neighbors.pyx.tp | 124 ++-- sklearn/neighbors/_ball_tree.pyx | 78 +-- sklearn/neighbors/_binary_tree.pxi | 550 +++++++++--------- sklearn/neighbors/_kd_tree.pyx | 88 +-- sklearn/neighbors/_kde.py | 8 +- sklearn/neighbors/_partition_nodes.pxd | 14 +- sklearn/neighbors/_partition_nodes.pyx | 12 +- .../neighbors/tests/test_neighbors_tree.py | 12 +- sklearn/utils/_heap.pxd | 8 +- sklearn/utils/_heap.pyx | 10 +- sklearn/utils/_sorting.pxd | 6 +- sklearn/utils/_sorting.pyx | 14 +- sklearn/utils/_typedefs.pxd | 8 +- sklearn/utils/_typedefs.pyx | 8 - sklearn/utils/_vector_sentinel.pxd | 10 +- sklearn/utils/_vector_sentinel.pyx | 34 +- 23 files changed, 709 insertions(+), 768 deletions(-) diff --git a/sklearn/feature_extraction/_hashing_fast.pyx b/sklearn/feature_extraction/_hashing_fast.pyx index 8917c1139e5f5..93e7ac7e88540 100644 --- a/sklearn/feature_extraction/_hashing_fast.pyx +++ b/sklearn/feature_extraction/_hashing_fast.pyx @@ -6,7 +6,7 @@ from libcpp.vector cimport vector cimport numpy as cnp import numpy as np -from ..utils._typedefs cimport INT32TYPE_t, INT64TYPE_t +from ..utils._typedefs cimport int32_t, int64_t from ..utils.murmurhash cimport murmurhash3_bytes_s32 from ..utils._vector_sentinel cimport vector_to_nd_array @@ -24,17 +24,17 @@ def transform(raw_X, Py_ssize_t n_features, dtype, For constructing a scipy.sparse.csr_matrix. """ - cdef INT32TYPE_t h + cdef int32_t h cdef double value - cdef vector[INT32TYPE_t] indices - cdef vector[INT64TYPE_t] indptr + cdef vector[int32_t] indices + cdef vector[int64_t] indptr indptr.push_back(0) # Since Python array does not understand Numpy dtypes, we grow the indices # and values arrays ourselves. Use a Py_ssize_t capacity for safety. cdef Py_ssize_t capacity = 8192 # arbitrary - cdef cnp.int64_t size = 0 + cdef int64_t size = 0 cdef cnp.ndarray values = np.empty(capacity, dtype=dtype) for x in raw_X: diff --git a/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pxd.tp b/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pxd.tp index 2bbe9e53518b3..f3a9ce96e64c0 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pxd.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pxd.tp @@ -1,7 +1,4 @@ -cimport numpy as cnp -from ...utils._typedefs cimport ITYPE_t, DTYPE_t - -cnp.import_array() +from ...utils._typedefs cimport intp_t, float64_t {{for name_suffix in ['64', '32']}} @@ -12,22 +9,22 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): """float{{name_suffix}} implementation of the ArgKmin.""" cdef: - ITYPE_t k + intp_t k - ITYPE_t[:, ::1] argkmin_indices - DTYPE_t[:, ::1] argkmin_distances + intp_t[:, ::1] argkmin_indices + float64_t[:, ::1] argkmin_distances # Used as array of pointers to private datastructures used in threads. - DTYPE_t ** heaps_r_distances_chunks - ITYPE_t ** heaps_indices_chunks + float64_t ** heaps_r_distances_chunks + intp_t ** heaps_indices_chunks cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): """EuclideanDistance-specialisation of ArgKmin{{name_suffix}}.""" cdef: MiddleTermComputer{{name_suffix}} middle_term_computer - const DTYPE_t[::1] X_norm_squared - const DTYPE_t[::1] Y_norm_squared + const float64_t[::1] X_norm_squared + const float64_t[::1] Y_norm_squared bint use_squared_distances diff --git a/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx.tp index 7caf5e0680dea..7edc64c59a050 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_argkmin.pyx.tp @@ -1,5 +1,3 @@ -cimport numpy as cnp - from libc.stdlib cimport free, malloc from libc.float cimport DBL_MAX from cython cimport final @@ -7,7 +5,7 @@ from cython.parallel cimport parallel, prange from ...utils._heap cimport heap_push from ...utils._sorting cimport simultaneous_sort -from ...utils._typedefs cimport ITYPE_t, DTYPE_t +from ...utils._typedefs cimport intp_t, float64_t import numpy as np import warnings @@ -16,10 +14,6 @@ from numbers import Integral from scipy.sparse import issparse from ...utils import check_array, check_scalar, _in_unstable_openblas_configuration from ...utils.fixes import threadpool_limits -from ...utils._typedefs import ITYPE, DTYPE - - -cnp.import_array() {{for name_suffix in ['64', '32']}} @@ -41,7 +35,7 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): cls, X, Y, - ITYPE_t k, + intp_t k, str metric="euclidean", chunk_size=None, dict metric_kwargs=None, @@ -104,7 +98,7 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): DatasetsPair{{name_suffix}} datasets_pair, chunk_size=None, strategy=None, - ITYPE_t k=1, + intp_t k=1, ): super().__init__( datasets_pair=datasets_pair, @@ -122,16 +116,16 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): # - when parallelizing on Y, the pointers of those heaps are referencing # small heaps which are thread-wise-allocated and whose content will be # merged with the main heaps'. - self.heaps_r_distances_chunks = malloc( - sizeof(DTYPE_t *) * self.chunks_n_threads + self.heaps_r_distances_chunks = malloc( + sizeof(float64_t *) * self.chunks_n_threads ) - self.heaps_indices_chunks = malloc( - sizeof(ITYPE_t *) * self.chunks_n_threads + self.heaps_indices_chunks = malloc( + sizeof(intp_t *) * self.chunks_n_threads ) # Main heaps which will be returned as results by `ArgKmin{{name_suffix}}.compute`. - self.argkmin_indices = np.full((self.n_samples_X, self.k), 0, dtype=ITYPE) - self.argkmin_distances = np.full((self.n_samples_X, self.k), DBL_MAX, dtype=DTYPE) + self.argkmin_indices = np.full((self.n_samples_X, self.k), 0, dtype=np.intp) + self.argkmin_distances = np.full((self.n_samples_X, self.k), DBL_MAX, dtype=np.float64) def __dealloc__(self): if self.heaps_indices_chunks is not NULL: @@ -142,18 +136,18 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): cdef void _compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: cdef: - ITYPE_t i, j - ITYPE_t n_samples_X = X_end - X_start - ITYPE_t n_samples_Y = Y_end - Y_start - DTYPE_t *heaps_r_distances = self.heaps_r_distances_chunks[thread_num] - ITYPE_t *heaps_indices = self.heaps_indices_chunks[thread_num] + intp_t i, j + intp_t n_samples_X = X_end - X_start + intp_t n_samples_Y = Y_end - Y_start + float64_t *heaps_r_distances = self.heaps_r_distances_chunks[thread_num] + intp_t *heaps_indices = self.heaps_indices_chunks[thread_num] # Pushing the distances and their associated indices on a heap # which by construction will keep track of the argkmin. @@ -169,9 +163,9 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: # As this strategy is embarrassingly parallel, we can set each # thread's heaps pointer to the proper position on the main heaps. @@ -180,12 +174,12 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): cdef void _parallel_on_X_prange_iter_finalize( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: cdef: - ITYPE_t idx + intp_t idx # Sorting the main heaps portion associated to `X[X_start:X_end]` # in ascending order w.r.t the distances. @@ -201,8 +195,8 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): ) noexcept nogil: cdef: # Maximum number of scalar elements (the last chunks can be smaller) - ITYPE_t heaps_size = self.X_n_samples_chunk * self.k - ITYPE_t thread_num + intp_t heaps_size = self.X_n_samples_chunk * self.k + intp_t thread_num # The allocation is done in parallel for data locality purposes: this way # the heaps used in each threads are allocated in pages which are closer @@ -214,18 +208,18 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): # As chunks of X are shared across threads, so must their # heaps. To solve this, each thread has its own heaps # which are then synchronised back in the main ones. - self.heaps_r_distances_chunks[thread_num] = malloc( - heaps_size * sizeof(DTYPE_t) + self.heaps_r_distances_chunks[thread_num] = malloc( + heaps_size * sizeof(float64_t) ) - self.heaps_indices_chunks[thread_num] = malloc( - heaps_size * sizeof(ITYPE_t) + self.heaps_indices_chunks[thread_num] = malloc( + heaps_size * sizeof(intp_t) ) cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: # Initialising heaps (memset can't be used here) for idx in range(self.X_n_samples_chunk * self.k): @@ -235,11 +229,11 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): @final cdef void _parallel_on_Y_synchronize( self, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t X_start, + intp_t X_end, ) noexcept nogil: cdef: - ITYPE_t idx, jdx, thread_num + intp_t idx, jdx, thread_num with nogil, parallel(num_threads=self.effective_n_threads): # Synchronising the thread heaps with the main heaps. # This is done in parallel sample-wise (no need for locks). @@ -263,7 +257,7 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): self, ) noexcept nogil: cdef: - ITYPE_t idx, thread_num + intp_t idx, thread_num with nogil, parallel(num_threads=self.chunks_n_threads): # Deallocating temporary datastructures @@ -283,8 +277,8 @@ cdef class ArgKmin{{name_suffix}}(BaseDistancesReduction{{name_suffix}}): cdef void compute_exact_distances(self) noexcept nogil: cdef: - ITYPE_t i, j - DTYPE_t[:, ::1] distances = self.argkmin_distances + intp_t i, j + float64_t[:, ::1] distances = self.argkmin_distances for i in prange(self.n_samples_X, schedule='static', nogil=True, num_threads=self.effective_n_threads): for j in range(self.k): @@ -319,7 +313,7 @@ cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): self, X, Y, - ITYPE_t k, + intp_t k, bint use_squared_distances=False, chunk_size=None, strategy=None, @@ -344,7 +338,7 @@ cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): k=k, ) cdef: - ITYPE_t dist_middle_terms_chunks_size = self.Y_n_samples_chunk * self.X_n_samples_chunk + intp_t dist_middle_terms_chunks_size = self.Y_n_samples_chunk * self.X_n_samples_chunk self.middle_term_computer = MiddleTermComputer{{name_suffix}}.get_for( X, @@ -396,7 +390,7 @@ cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): @final cdef void _parallel_on_X_parallel_init( self, - ITYPE_t thread_num, + intp_t thread_num, ) noexcept nogil: ArgKmin{{name_suffix}}._parallel_on_X_parallel_init(self, thread_num) self.middle_term_computer._parallel_on_X_parallel_init(thread_num) @@ -404,9 +398,9 @@ cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): @final cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: ArgKmin{{name_suffix}}._parallel_on_X_init_chunk(self, thread_num, X_start, X_end) self.middle_term_computer._parallel_on_X_init_chunk(thread_num, X_start, X_end) @@ -414,11 +408,11 @@ cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): @final cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: ArgKmin{{name_suffix}}._parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, @@ -440,9 +434,9 @@ cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): @final cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: ArgKmin{{name_suffix}}._parallel_on_Y_parallel_init(self, thread_num, X_start, X_end) self.middle_term_computer._parallel_on_Y_parallel_init(thread_num, X_start, X_end) @@ -450,11 +444,11 @@ cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): @final cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: ArgKmin{{name_suffix}}._parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, @@ -469,22 +463,22 @@ cdef class EuclideanArgKmin{{name_suffix}}(ArgKmin{{name_suffix}}): @final cdef void _compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: cdef: - ITYPE_t i, j - DTYPE_t sqeuclidean_dist_i_j - ITYPE_t n_X = X_end - X_start - ITYPE_t n_Y = Y_end - Y_start - DTYPE_t * dist_middle_terms = self.middle_term_computer._compute_dist_middle_terms( + intp_t i, j + float64_t sqeuclidean_dist_i_j + intp_t n_X = X_end - X_start + intp_t n_Y = Y_end - Y_start + float64_t * dist_middle_terms = self.middle_term_computer._compute_dist_middle_terms( X_start, X_end, Y_start, Y_end, thread_num ) - DTYPE_t * heaps_r_distances = self.heaps_r_distances_chunks[thread_num] - ITYPE_t * heaps_indices = self.heaps_indices_chunks[thread_num] + float64_t * heaps_r_distances = self.heaps_r_distances_chunks[thread_num] + intp_t * heaps_indices = self.heaps_indices_chunks[thread_num] # Pushing the distance and their associated indices on heaps # which keep tracks of the argkmin. diff --git a/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp index 95577e5754e64..a7744ab6e6b8f 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp @@ -1,19 +1,3 @@ -{{py: - -implementation_specific_values = [ - # Values are the following ones: - # - # name_suffix, INPUT_DTYPE_t, INPUT_DTYPE - # - # We also use the float64 dtype and C-type names as defined in - # `sklearn.utils._typedefs` to maintain consistency. - # - ('64', 'DTYPE_t', 'DTYPE'), - ('32', 'cnp.float32_t', 'np.float32') -] - -}} - from cython cimport floating, integral from cython.parallel cimport parallel, prange from libcpp.map cimport map as cpp_map, pair as cpp_pair @@ -23,8 +7,8 @@ cimport numpy as cnp cnp.import_array() -from ...utils._typedefs cimport ITYPE_t, DTYPE_t -from ...utils._typedefs import ITYPE, DTYPE +from ...utils._typedefs cimport intp_t, float64_t + import numpy as np from scipy.sparse import issparse from sklearn.utils.fixes import threadpool_limits @@ -36,7 +20,7 @@ cpdef enum WeightingStrategy: distance = 1 callable = 2 -{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}} +{{for name_suffix in ["32", "64"]}} from ._argkmin cimport ArgKmin{{name_suffix}} from ._datasets_pair cimport DatasetsPair{{name_suffix}} @@ -45,10 +29,10 @@ cdef class ArgKminClassMode{{name_suffix}}(ArgKmin{{name_suffix}}): {{name_suffix}}bit implementation of ArgKminClassMode. """ cdef: - const ITYPE_t[:] class_membership, - const ITYPE_t[:] unique_labels - DTYPE_t[:, :] class_scores - cpp_map[ITYPE_t, ITYPE_t] labels_to_index + const intp_t[:] class_membership, + const intp_t[:] unique_labels + float64_t[:, :] class_scores + cpp_map[intp_t, intp_t] labels_to_index WeightingStrategy weight_type @classmethod @@ -56,7 +40,7 @@ cdef class ArgKminClassMode{{name_suffix}}(ArgKmin{{name_suffix}}): cls, X, Y, - ITYPE_t k, + intp_t k, weights, class_membership, unique_labels, @@ -103,11 +87,11 @@ cdef class ArgKminClassMode{{name_suffix}}(ArgKmin{{name_suffix}}): def __init__( self, DatasetsPair{{name_suffix}} datasets_pair, - const ITYPE_t[:] class_membership, - const ITYPE_t[:] unique_labels, + const intp_t[:] class_membership, + const intp_t[:] unique_labels, chunk_size=None, strategy=None, - ITYPE_t k=1, + intp_t k=1, weights=None, ): super().__init__( @@ -127,11 +111,11 @@ cdef class ArgKminClassMode{{name_suffix}}(ArgKmin{{name_suffix}}): self.unique_labels = unique_labels - cdef ITYPE_t idx, neighbor_class_idx + cdef intp_t idx, neighbor_class_idx # Map from set of unique labels to their indices in `class_scores` # Buffer used in building a histogram for one-pass weighted mode self.class_scores = np.zeros( - (self.n_samples_X, unique_labels.shape[0]), dtype=DTYPE, + (self.n_samples_X, unique_labels.shape[0]), dtype=np.float64, ) def _finalize_results(self): @@ -141,13 +125,13 @@ cdef class ArgKminClassMode{{name_suffix}}(ArgKmin{{name_suffix}}): cdef inline void weighted_histogram_mode( self, - ITYPE_t sample_index, - ITYPE_t* indices, - DTYPE_t* distances, + intp_t sample_index, + intp_t* indices, + float64_t* distances, ) noexcept nogil: cdef: - ITYPE_t neighbor_idx, neighbor_class_idx, label_index, multi_output_index - DTYPE_t score_incr = 1 + intp_t neighbor_idx, neighbor_class_idx, label_index, multi_output_index + float64_t score_incr = 1 # TODO: Implement other WeightingStrategy values bint use_distance_weighting = ( self.weight_type == WeightingStrategy.distance @@ -168,12 +152,12 @@ cdef class ArgKminClassMode{{name_suffix}}(ArgKmin{{name_suffix}}): cdef void _parallel_on_X_prange_iter_finalize( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: cdef: - ITYPE_t idx, sample_index + intp_t idx, sample_index for idx in range(X_end - X_start): # One-pass top-one weighted mode # Compute the absolute index in [0, n_samples_X) @@ -189,7 +173,7 @@ cdef class ArgKminClassMode{{name_suffix}}(ArgKmin{{name_suffix}}): self, ) noexcept nogil: cdef: - ITYPE_t sample_index, thread_num + intp_t sample_index, thread_num with nogil, parallel(num_threads=self.chunks_n_threads): # Deallocating temporary datastructures diff --git a/sklearn/metrics/_pairwise_distances_reduction/_base.pxd.tp b/sklearn/metrics/_pairwise_distances_reduction/_base.pxd.tp index 4ce12e6a8f6df..9578129993c37 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_base.pxd.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_base.pxd.tp @@ -1,19 +1,15 @@ -cimport numpy as cnp - from cython cimport final -from ...utils._typedefs cimport ITYPE_t, DTYPE_t, SPARSE_INDEX_TYPE_t - -cnp.import_array() +from ...utils._typedefs cimport intp_t, float64_t -{{for name_suffix, INPUT_DTYPE_t in [('64', 'DTYPE_t'), ('32', 'cnp.float32_t')]}} +{{for name_suffix in ['64', '32']}} from ._datasets_pair cimport DatasetsPair{{name_suffix}} -cpdef DTYPE_t[::1] _sqeuclidean_row_norms{{name_suffix}}( +cpdef float64_t[::1] _sqeuclidean_row_norms{{name_suffix}}( X, - ITYPE_t num_threads, + intp_t num_threads, ) cdef class BaseDistancesReduction{{name_suffix}}: @@ -42,13 +38,13 @@ cdef class BaseDistancesReduction{{name_suffix}}: # # chunks_n_threads <= effective_n_threads # - ITYPE_t effective_n_threads - ITYPE_t chunks_n_threads + intp_t effective_n_threads + intp_t chunks_n_threads - ITYPE_t n_samples_chunk, chunk_size + intp_t n_samples_chunk, chunk_size - ITYPE_t n_samples_X, X_n_samples_chunk, X_n_chunks, X_n_samples_last_chunk - ITYPE_t n_samples_Y, Y_n_samples_chunk, Y_n_chunks, Y_n_samples_last_chunk + intp_t n_samples_X, X_n_samples_chunk, X_n_chunks, X_n_samples_last_chunk + intp_t n_samples_Y, Y_n_samples_chunk, Y_n_chunks, Y_n_samples_last_chunk bint execute_in_parallel_on_Y @@ -62,11 +58,11 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil @@ -76,35 +72,35 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _parallel_on_X_parallel_init( self, - ITYPE_t thread_num, + intp_t thread_num, ) noexcept nogil cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil cdef void _parallel_on_X_prange_iter_finalize( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil cdef void _parallel_on_X_parallel_finalize( self, - ITYPE_t thread_num + intp_t thread_num ) noexcept nogil cdef void _parallel_on_Y_init( @@ -113,24 +109,24 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil cdef void _parallel_on_Y_synchronize( self, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t X_start, + intp_t X_end, ) noexcept nogil cdef void _parallel_on_Y_finalize( diff --git a/sklearn/metrics/_pairwise_distances_reduction/_base.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_base.pyx.tp index bab9952e22e2d..5ed0f8edcfddf 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_base.pyx.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_base.pyx.tp @@ -1,20 +1,3 @@ -{{py: - -implementation_specific_values = [ - # Values are the following ones: - # - # name_suffix, INPUT_DTYPE_t, INPUT_DTYPE - # - # We also use the float64 dtype and C-type names as defined in - # `sklearn.utils._typedefs` to maintain consistency. - # - ('64', 'DTYPE_t', 'DTYPE'), - ('32', 'cnp.float32_t', 'np.float32') -] - -}} -cimport numpy as cnp - from cython cimport final from cython.operator cimport dereference as deref from cython.parallel cimport parallel, prange @@ -22,7 +5,7 @@ from libcpp.vector cimport vector from ...utils._cython_blas cimport _dot from ...utils._openmp_helpers cimport omp_get_thread_num -from ...utils._typedefs cimport ITYPE_t, DTYPE_t +from ...utils._typedefs cimport intp_t, float32_t, float64_t import numpy as np @@ -31,16 +14,13 @@ from numbers import Integral from sklearn import get_config from sklearn.utils import check_scalar from ...utils._openmp_helpers import _openmp_effective_n_threads -from ...utils._typedefs import DTYPE, SPARSE_INDEX_TYPE from ...utils.sparsefuncs_fast import _sqeuclidean_row_norms_sparse -cnp.import_array() - ##################### -cdef DTYPE_t[::1] _sqeuclidean_row_norms64_dense( - const DTYPE_t[:, ::1] X, - ITYPE_t num_threads, +cdef float64_t[::1] _sqeuclidean_row_norms64_dense( + const float64_t[:, ::1] X, + intp_t num_threads, ): """Compute the squared euclidean norm of the rows of X in parallel. @@ -51,11 +31,11 @@ cdef DTYPE_t[::1] _sqeuclidean_row_norms64_dense( # exposed via scipy.linalg.cython_blas aren't reflecting the arguments' # const qualifier. # See: https://github.com/scipy/scipy/issues/14262 - DTYPE_t * X_ptr = &X[0, 0] - ITYPE_t idx = 0 - ITYPE_t n = X.shape[0] - ITYPE_t d = X.shape[1] - DTYPE_t[::1] squared_row_norms = np.empty(n, dtype=DTYPE) + float64_t * X_ptr = &X[0, 0] + intp_t idx = 0 + intp_t n = X.shape[0] + intp_t d = X.shape[1] + float64_t[::1] squared_row_norms = np.empty(n, dtype=np.float64) for idx in prange(n, schedule='static', nogil=True, num_threads=num_threads): squared_row_norms[idx] = _dot(d, X_ptr + idx * d, 1, X_ptr + idx * d, 1) @@ -63,9 +43,9 @@ cdef DTYPE_t[::1] _sqeuclidean_row_norms64_dense( return squared_row_norms -cdef DTYPE_t[::1] _sqeuclidean_row_norms32_dense( - const cnp.float32_t[:, ::1] X, - ITYPE_t num_threads, +cdef float64_t[::1] _sqeuclidean_row_norms32_dense( + const float32_t[:, ::1] X, + intp_t num_threads, ): """Compute the squared euclidean norm of the rows of X in parallel. @@ -76,16 +56,16 @@ cdef DTYPE_t[::1] _sqeuclidean_row_norms32_dense( # exposed via scipy.linalg.cython_blas aren't reflecting the arguments' # const qualifier. # See: https://github.com/scipy/scipy/issues/14262 - cnp.float32_t * X_ptr = &X[0, 0] - ITYPE_t i = 0, j = 0 - ITYPE_t thread_num - ITYPE_t n = X.shape[0] - ITYPE_t d = X.shape[1] - DTYPE_t[::1] squared_row_norms = np.empty(n, dtype=DTYPE) + float32_t * X_ptr = &X[0, 0] + intp_t i = 0, j = 0 + intp_t thread_num + intp_t n = X.shape[0] + intp_t d = X.shape[1] + float64_t[::1] squared_row_norms = np.empty(n, dtype=np.float64) # To upcast the i-th row of X from float32 to float64 - vector[vector[DTYPE_t]] X_i_upcast = vector[vector[DTYPE_t]]( - num_threads, vector[DTYPE_t](d) + vector[vector[float64_t]] X_i_upcast = vector[vector[float64_t]]( + num_threads, vector[float64_t](d) ) with nogil, parallel(num_threads=num_threads): @@ -94,7 +74,7 @@ cdef DTYPE_t[::1] _sqeuclidean_row_norms32_dense( for i in prange(n, schedule='static'): # Upcasting the i-th row of X from float32 to float64 for j in range(d): - X_i_upcast[thread_num][j] = deref(X_ptr + i * d + j) + X_i_upcast[thread_num][j] = deref(X_ptr + i * d + j) squared_row_norms[i] = _dot( d, X_i_upcast[thread_num].data(), 1, @@ -104,20 +84,20 @@ cdef DTYPE_t[::1] _sqeuclidean_row_norms32_dense( return squared_row_norms -{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}} +{{for name_suffix in ["64", "32"]}} from ._datasets_pair cimport DatasetsPair{{name_suffix}} -cpdef DTYPE_t[::1] _sqeuclidean_row_norms{{name_suffix}}( +cpdef float64_t[::1] _sqeuclidean_row_norms{{name_suffix}}( X, - ITYPE_t num_threads, + intp_t num_threads, ): if issparse(X): # TODO: remove this instruction which is a cast in the float32 case # by moving squared row norms computations in MiddleTermComputer. - X_data = np.asarray(X.data, dtype=DTYPE) - X_indptr = np.asarray(X.indptr, dtype=SPARSE_INDEX_TYPE) + X_data = np.asarray(X.data, dtype=np.float64) + X_indptr = np.asarray(X.indptr, dtype=np.int32) return _sqeuclidean_row_norms_sparse(X_data, X_indptr, num_threads) else: return _sqeuclidean_row_norms{{name_suffix}}_dense(X, num_threads) @@ -140,7 +120,7 @@ cdef class BaseDistancesReduction{{name_suffix}}: strategy=None, ): cdef: - ITYPE_t X_n_full_chunks, Y_n_full_chunks + intp_t X_n_full_chunks, Y_n_full_chunks if chunk_size is None: chunk_size = get_config().get("pairwise_dist_chunk_size", 256) @@ -225,8 +205,8 @@ cdef class BaseDistancesReduction{{name_suffix}}: interact with those datastructures at various stages. """ cdef: - ITYPE_t Y_start, Y_end, X_start, X_end, X_chunk_idx, Y_chunk_idx - ITYPE_t thread_num + intp_t Y_start, Y_end, X_start, X_end, X_chunk_idx, Y_chunk_idx + intp_t thread_num with nogil, parallel(num_threads=self.chunks_n_threads): thread_num = omp_get_thread_num() @@ -294,8 +274,8 @@ cdef class BaseDistancesReduction{{name_suffix}}: interact with those datastructures at various stages. """ cdef: - ITYPE_t Y_start, Y_end, X_start, X_end, X_chunk_idx, Y_chunk_idx - ITYPE_t thread_num + intp_t Y_start, Y_end, X_start, X_end, X_chunk_idx, Y_chunk_idx + intp_t thread_num # Allocating datastructures shared by all threads self._parallel_on_Y_init() @@ -347,11 +327,11 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: """Compute the pairwise distances on two chunks of X and Y and reduce them. @@ -376,16 +356,16 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _parallel_on_X_parallel_init( self, - ITYPE_t thread_num, + intp_t thread_num, ) noexcept nogil: """Allocate datastructures used in a thread given its number.""" return cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: """Initialize datastructures used in a thread given its number. @@ -404,11 +384,11 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: """Initialize datastructures just before the _compute_and_reduce_distances_on_chunks. @@ -427,16 +407,16 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _parallel_on_X_prange_iter_finalize( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: """Interact with datastructures after a reduction on chunks.""" return cdef void _parallel_on_X_parallel_finalize( self, - ITYPE_t thread_num + intp_t thread_num ) noexcept nogil: """Interact with datastructures after executing all the reductions.""" return @@ -449,9 +429,9 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: """Initialize datastructures used in a thread given its number. @@ -470,11 +450,11 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: """Initialize datastructures just before the _compute_and_reduce_distances_on_chunks. @@ -493,8 +473,8 @@ cdef class BaseDistancesReduction{{name_suffix}}: cdef void _parallel_on_Y_synchronize( self, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t X_start, + intp_t X_end, ) noexcept nogil: """Update thread datastructures before leaving a parallel region.""" return diff --git a/sklearn/metrics/_pairwise_distances_reduction/_radius_neighbors.pxd.tp b/sklearn/metrics/_pairwise_distances_reduction/_radius_neighbors.pxd.tp index 4f333327a6c52..809a80a68c5b0 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_radius_neighbors.pxd.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_radius_neighbors.pxd.tp @@ -4,7 +4,7 @@ from libcpp.memory cimport shared_ptr from libcpp.vector cimport vector from cython cimport final -from ...utils._typedefs cimport ITYPE_t, DTYPE_t +from ...utils._typedefs cimport intp_t, float64_t cnp.import_array() @@ -12,17 +12,17 @@ cnp.import_array() ## std::vector to np.ndarray coercion # As type covariance is not supported for C++ containers via Cython, # we need to redefine fused types. -ctypedef fused vector_DITYPE_t: - vector[ITYPE_t] - vector[DTYPE_t] +ctypedef fused vector_double_intp_t: + vector[intp_t] + vector[float64_t] -ctypedef fused vector_vector_DITYPE_t: - vector[vector[ITYPE_t]] - vector[vector[DTYPE_t]] +ctypedef fused vector_vector_double_intp_t: + vector[vector[intp_t]] + vector[vector[float64_t]] cdef cnp.ndarray[object, ndim=1] coerce_vectors_to_nd_arrays( - shared_ptr[vector_vector_DITYPE_t] vecs + shared_ptr[vector_vector_double_intp_t] vecs ) ##################### @@ -35,13 +35,13 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) """float{{name_suffix}} implementation of the RadiusNeighbors.""" cdef: - DTYPE_t radius + float64_t radius # DistanceMetric{{name_suffix}} compute rank-preserving surrogate distance via rdist # which are proxies necessitating less computations. # We get the equivalent for the radius to be able to compare it against # vectors' rank-preserving surrogate distances. - DTYPE_t r_radius + float64_t r_radius # Neighbors indices and distances are returned as np.ndarrays of np.ndarrays. # @@ -61,20 +61,20 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) # Shared pointers (defined via shared_ptr) are use for safer memory management. # Unique pointers (defined via unique_ptr) can't be used as datastructures # are shared across threads for parallel_on_X; see _parallel_on_X_init_chunk. - shared_ptr[vector[vector[ITYPE_t]]] neigh_indices - shared_ptr[vector[vector[DTYPE_t]]] neigh_distances + shared_ptr[vector[vector[intp_t]]] neigh_indices + shared_ptr[vector[vector[float64_t]]] neigh_distances # Used as array of pointers to private datastructures used in threads. - vector[shared_ptr[vector[vector[ITYPE_t]]]] neigh_indices_chunks - vector[shared_ptr[vector[vector[DTYPE_t]]]] neigh_distances_chunks + vector[shared_ptr[vector[vector[intp_t]]]] neigh_indices_chunks + vector[shared_ptr[vector[vector[float64_t]]]] neigh_distances_chunks bint sort_results @final cdef void _merge_vectors( self, - ITYPE_t idx, - ITYPE_t num_threads, + intp_t idx, + intp_t num_threads, ) noexcept nogil @@ -82,8 +82,8 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} """EuclideanDistance-specialisation of RadiusNeighbors{{name_suffix}}.""" cdef: MiddleTermComputer{{name_suffix}} middle_term_computer - const DTYPE_t[::1] X_norm_squared - const DTYPE_t[::1] Y_norm_squared + const float64_t[::1] X_norm_squared + const float64_t[::1] Y_norm_squared bint use_squared_distances diff --git a/sklearn/metrics/_pairwise_distances_reduction/_radius_neighbors.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_radius_neighbors.pyx.tp index 6b9492e6a81f1..1defa30b6325e 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_radius_neighbors.pyx.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_radius_neighbors.pyx.tp @@ -9,7 +9,7 @@ from cython.operator cimport dereference as deref from cython.parallel cimport parallel, prange from ...utils._sorting cimport simultaneous_sort -from ...utils._typedefs cimport ITYPE_t, DTYPE_t +from ...utils._typedefs cimport intp_t, float64_t from ...utils._vector_sentinel cimport vector_to_nd_array from numbers import Real @@ -28,11 +28,11 @@ cdef extern from "" namespace "std" nogil: ###################### cdef cnp.ndarray[object, ndim=1] coerce_vectors_to_nd_arrays( - shared_ptr[vector_vector_DITYPE_t] vecs + shared_ptr[vector_vector_double_intp_t] vecs ): """Coerce a std::vector of std::vector to a ndarray of ndarray.""" cdef: - ITYPE_t n = deref(vecs).size() + intp_t n = deref(vecs).size() cnp.ndarray[object, ndim=1] nd_arrays_of_nd_arrays = np.empty(n, dtype=np.ndarray) for i in range(n): @@ -61,7 +61,7 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) cls, X, Y, - DTYPE_t radius, + float64_t radius, str metric="euclidean", chunk_size=None, dict metric_kwargs=None, @@ -126,7 +126,7 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) def __init__( self, DatasetsPair{{name_suffix}} datasets_pair, - DTYPE_t radius, + float64_t radius, chunk_size=None, strategy=None, sort_results=False, @@ -150,29 +150,29 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) # - when parallelizing on Y, the pointers of those heaps are referencing # std::vectors of std::vectors which are thread-wise-allocated and whose # content will be merged into self.neigh_distances and self.neigh_indices. - self.neigh_distances_chunks = vector[shared_ptr[vector[vector[DTYPE_t]]]]( + self.neigh_distances_chunks = vector[shared_ptr[vector[vector[float64_t]]]]( self.chunks_n_threads ) - self.neigh_indices_chunks = vector[shared_ptr[vector[vector[ITYPE_t]]]]( + self.neigh_indices_chunks = vector[shared_ptr[vector[vector[intp_t]]]]( self.chunks_n_threads ) # Temporary datastructures which will be coerced to numpy arrays on before # RadiusNeighbors.compute "return" and will be then freed. - self.neigh_distances = make_shared[vector[vector[DTYPE_t]]](self.n_samples_X) - self.neigh_indices = make_shared[vector[vector[ITYPE_t]]](self.n_samples_X) + self.neigh_distances = make_shared[vector[vector[float64_t]]](self.n_samples_X) + self.neigh_indices = make_shared[vector[vector[intp_t]]](self.n_samples_X) cdef void _compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: cdef: - ITYPE_t i, j - DTYPE_t r_dist_i_j + intp_t i, j + float64_t r_dist_i_j for i in range(X_start, X_end): for j in range(Y_start, Y_end): @@ -195,9 +195,9 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: # As this strategy is embarrassingly parallel, we can set the @@ -208,12 +208,12 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) @final cdef void _parallel_on_X_prange_iter_finalize( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: cdef: - ITYPE_t idx + intp_t idx # Sorting neighbors for each query vector of X if self.sort_results: @@ -228,24 +228,24 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) self, ) noexcept nogil: cdef: - ITYPE_t thread_num + intp_t thread_num # As chunks of X are shared across threads, so must datastructures to avoid race # conditions: each thread has its own vectors of n_samples_X vectors which are # then merged back in the main n_samples_X vectors. for thread_num in range(self.chunks_n_threads): - self.neigh_distances_chunks[thread_num] = make_shared[vector[vector[DTYPE_t]]](self.n_samples_X) - self.neigh_indices_chunks[thread_num] = make_shared[vector[vector[ITYPE_t]]](self.n_samples_X) + self.neigh_distances_chunks[thread_num] = make_shared[vector[vector[float64_t]]](self.n_samples_X) + self.neigh_indices_chunks[thread_num] = make_shared[vector[vector[intp_t]]](self.n_samples_X) @final cdef void _merge_vectors( self, - ITYPE_t idx, - ITYPE_t num_threads, + intp_t idx, + intp_t num_threads, ) noexcept nogil: cdef: - ITYPE_t thread_num - ITYPE_t idx_n_elements = 0 - ITYPE_t last_element_idx = deref(self.neigh_indices)[idx].size() + intp_t thread_num + intp_t idx_n_elements = 0 + intp_t last_element_idx = deref(self.neigh_indices)[idx].size() # Resizing buffers only once for the given number of elements. for thread_num in range(num_threads): @@ -273,7 +273,7 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) self, ) noexcept nogil: cdef: - ITYPE_t idx + intp_t idx with nogil, parallel(num_threads=self.effective_n_threads): # Merge vectors used in threads into the main ones. @@ -300,7 +300,7 @@ cdef class RadiusNeighbors{{name_suffix}}(BaseDistancesReduction{{name_suffix}}) cdef void compute_exact_distances(self) noexcept nogil: """Convert rank-preserving distances to pairwise distances in parallel.""" cdef: - ITYPE_t i, j + intp_t i, j for i in prange(self.n_samples_X, nogil=True, schedule='static', num_threads=self.effective_n_threads): @@ -325,7 +325,7 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} self, X, Y, - DTYPE_t radius, + float64_t radius, bint use_squared_distances=False, chunk_size=None, strategy=None, @@ -352,7 +352,7 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} sort_results=sort_results, ) cdef: - ITYPE_t dist_middle_terms_chunks_size = self.Y_n_samples_chunk * self.X_n_samples_chunk + intp_t dist_middle_terms_chunks_size = self.Y_n_samples_chunk * self.X_n_samples_chunk self.middle_term_computer = MiddleTermComputer{{name_suffix}}.get_for( X, @@ -404,7 +404,7 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} @final cdef void _parallel_on_X_parallel_init( self, - ITYPE_t thread_num, + intp_t thread_num, ) noexcept nogil: RadiusNeighbors{{name_suffix}}._parallel_on_X_parallel_init(self, thread_num) self.middle_term_computer._parallel_on_X_parallel_init(thread_num) @@ -412,9 +412,9 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} @final cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: RadiusNeighbors{{name_suffix}}._parallel_on_X_init_chunk(self, thread_num, X_start, X_end) self.middle_term_computer._parallel_on_X_init_chunk(thread_num, X_start, X_end) @@ -422,11 +422,11 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} @final cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: RadiusNeighbors{{name_suffix}}._parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, @@ -448,9 +448,9 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} @final cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: RadiusNeighbors{{name_suffix}}._parallel_on_Y_parallel_init(self, thread_num, X_start, X_end) self.middle_term_computer._parallel_on_Y_parallel_init(thread_num, X_start, X_end) @@ -458,11 +458,11 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} @final cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: RadiusNeighbors{{name_suffix}}._parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, @@ -482,18 +482,18 @@ cdef class EuclideanRadiusNeighbors{{name_suffix}}(RadiusNeighbors{{name_suffix} @final cdef void _compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: cdef: - ITYPE_t i, j - DTYPE_t sqeuclidean_dist_i_j - ITYPE_t n_X = X_end - X_start - ITYPE_t n_Y = Y_end - Y_start - DTYPE_t *dist_middle_terms = self.middle_term_computer._compute_dist_middle_terms( + intp_t i, j + float64_t sqeuclidean_dist_i_j + intp_t n_X = X_end - X_start + intp_t n_Y = Y_end - Y_start + float64_t *dist_middle_terms = self.middle_term_computer._compute_dist_middle_terms( X_start, X_end, Y_start, Y_end, thread_num ) diff --git a/sklearn/neighbors/_ball_tree.pyx b/sklearn/neighbors/_ball_tree.pyx index 30b8376be9146..f3bf7cd100571 100644 --- a/sklearn/neighbors/_ball_tree.pyx +++ b/sklearn/neighbors/_ball_tree.pyx @@ -35,30 +35,30 @@ cdef class BallTree(BinaryTree): # distance for the Euclidean metric is the squared-euclidean distance. # For some metrics, the reduced distance is simply the distance. -cdef int allocate_data(BinaryTree tree, ITYPE_t n_nodes, - ITYPE_t n_features) except -1: +cdef int allocate_data(BinaryTree tree, intp_t n_nodes, + intp_t n_features) except -1: """Allocate arrays needed for the KD Tree""" - tree.node_bounds = np.zeros((1, n_nodes, n_features), dtype=DTYPE) + tree.node_bounds = np.zeros((1, n_nodes, n_features), dtype=np.float64) return 0 -cdef int init_node(BinaryTree tree, NodeData_t[::1] node_data, ITYPE_t i_node, - ITYPE_t idx_start, ITYPE_t idx_end) except -1: +cdef int init_node(BinaryTree tree, NodeData_t[::1] node_data, intp_t i_node, + intp_t idx_start, intp_t idx_end) except -1: """Initialize the node for the dataset stored in tree.data""" - cdef ITYPE_t n_features = tree.data.shape[1] - cdef ITYPE_t n_points = idx_end - idx_start + cdef intp_t n_features = tree.data.shape[1] + cdef intp_t n_points = idx_end - idx_start - cdef ITYPE_t i, j - cdef DTYPE_t radius - cdef DTYPE_t *this_pt + cdef intp_t i, j + cdef float64_t radius + cdef float64_t *this_pt - cdef ITYPE_t* idx_array = &tree.idx_array[0] - cdef DTYPE_t* data = &tree.data[0, 0] - cdef DTYPE_t* centroid = &tree.node_bounds[0, i_node, 0] + cdef intp_t* idx_array = &tree.idx_array[0] + cdef float64_t* data = &tree.data[0, 0] + cdef float64_t* centroid = &tree.node_bounds[0, i_node, 0] cdef bint with_sample_weight = tree.sample_weight is not None - cdef DTYPE_t* sample_weight - cdef DTYPE_t sum_weight_node + cdef float64_t* sample_weight + cdef float64_t sum_weight_node if with_sample_weight: sample_weight = &tree.sample_weight[0] @@ -99,35 +99,35 @@ cdef int init_node(BinaryTree tree, NodeData_t[::1] node_data, ITYPE_t i_node, return 0 -cdef inline DTYPE_t min_dist(BinaryTree tree, ITYPE_t i_node, - DTYPE_t* pt) except -1 nogil: +cdef inline float64_t min_dist(BinaryTree tree, intp_t i_node, + float64_t* pt) except -1 nogil: """Compute the minimum distance between a point and a node""" - cdef DTYPE_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0], + cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0], tree.data.shape[1]) return fmax(0, dist_pt - tree.node_data[i_node].radius) -cdef inline DTYPE_t max_dist(BinaryTree tree, ITYPE_t i_node, - DTYPE_t* pt) except -1: +cdef inline float64_t max_dist(BinaryTree tree, intp_t i_node, + float64_t* pt) except -1: """Compute the maximum distance between a point and a node""" - cdef DTYPE_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0], + cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0], tree.data.shape[1]) return dist_pt + tree.node_data[i_node].radius -cdef inline int min_max_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt, - DTYPE_t* min_dist, DTYPE_t* max_dist) except -1 nogil: +cdef inline int min_max_dist(BinaryTree tree, intp_t i_node, float64_t* pt, + float64_t* min_dist, float64_t* max_dist) except -1 nogil: """Compute the minimum and maximum distance between a point and a node""" - cdef DTYPE_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0], + cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0], tree.data.shape[1]) - cdef DTYPE_t rad = tree.node_data[i_node].radius + cdef float64_t rad = tree.node_data[i_node].radius min_dist[0] = fmax(0, dist_pt - rad) max_dist[0] = dist_pt + rad return 0 -cdef inline DTYPE_t min_rdist(BinaryTree tree, ITYPE_t i_node, - DTYPE_t* pt) except -1 nogil: +cdef inline float64_t min_rdist(BinaryTree tree, intp_t i_node, + float64_t* pt) except -1 nogil: """Compute the minimum reduced-distance between a point and a node""" if tree.euclidean: return euclidean_dist_to_rdist(min_dist(tree, i_node, pt)) @@ -135,8 +135,8 @@ cdef inline DTYPE_t min_rdist(BinaryTree tree, ITYPE_t i_node, return tree.dist_metric._dist_to_rdist(min_dist(tree, i_node, pt)) -cdef inline DTYPE_t max_rdist(BinaryTree tree, ITYPE_t i_node, - DTYPE_t* pt) except -1: +cdef inline float64_t max_rdist(BinaryTree tree, intp_t i_node, + float64_t* pt) except -1: """Compute the maximum reduced-distance between a point and a node""" if tree.euclidean: return euclidean_dist_to_rdist(max_dist(tree, i_node, pt)) @@ -144,28 +144,28 @@ cdef inline DTYPE_t max_rdist(BinaryTree tree, ITYPE_t i_node, return tree.dist_metric._dist_to_rdist(max_dist(tree, i_node, pt)) -cdef inline DTYPE_t min_dist_dual(BinaryTree tree1, ITYPE_t i_node1, - BinaryTree tree2, ITYPE_t i_node2) except -1: +cdef inline float64_t min_dist_dual(BinaryTree tree1, intp_t i_node1, + BinaryTree tree2, intp_t i_node2) except -1: """compute the minimum distance between two nodes""" - cdef DTYPE_t dist_pt = tree1.dist(&tree2.node_bounds[0, i_node2, 0], + cdef float64_t dist_pt = tree1.dist(&tree2.node_bounds[0, i_node2, 0], &tree1.node_bounds[0, i_node1, 0], tree1.data.shape[1]) return fmax(0, (dist_pt - tree1.node_data[i_node1].radius - tree2.node_data[i_node2].radius)) -cdef inline DTYPE_t max_dist_dual(BinaryTree tree1, ITYPE_t i_node1, - BinaryTree tree2, ITYPE_t i_node2) except -1: +cdef inline float64_t max_dist_dual(BinaryTree tree1, intp_t i_node1, + BinaryTree tree2, intp_t i_node2) except -1: """compute the maximum distance between two nodes""" - cdef DTYPE_t dist_pt = tree1.dist(&tree2.node_bounds[0, i_node2, 0], + cdef float64_t dist_pt = tree1.dist(&tree2.node_bounds[0, i_node2, 0], &tree1.node_bounds[0, i_node1, 0], tree1.data.shape[1]) return (dist_pt + tree1.node_data[i_node1].radius + tree2.node_data[i_node2].radius) -cdef inline DTYPE_t min_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, - BinaryTree tree2, ITYPE_t i_node2) except -1: +cdef inline float64_t min_rdist_dual(BinaryTree tree1, intp_t i_node1, + BinaryTree tree2, intp_t i_node2) except -1: """compute the minimum reduced distance between two nodes""" if tree1.euclidean: return euclidean_dist_to_rdist(min_dist_dual(tree1, i_node1, @@ -175,8 +175,8 @@ cdef inline DTYPE_t min_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, tree2, i_node2)) -cdef inline DTYPE_t max_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, - BinaryTree tree2, ITYPE_t i_node2) except -1: +cdef inline float64_t max_rdist_dual(BinaryTree tree1, intp_t i_node1, + BinaryTree tree2, intp_t i_node2) except -1: """compute the maximum reduced distance between two nodes""" if tree1.euclidean: return euclidean_dist_to_rdist(max_dist_dual(tree1, i_node1, diff --git a/sklearn/neighbors/_binary_tree.pxi b/sklearn/neighbors/_binary_tree.pxi index 99ed4341ad155..a03b7cdec2294 100644 --- a/sklearn/neighbors/_binary_tree.pxi +++ b/sklearn/neighbors/_binary_tree.pxi @@ -103,43 +103,43 @@ # These are the names and descriptions of the "abstract" functions which are # defined in kd_tree.pyx and ball_tree.pyx: -# cdef int allocate_data(BinaryTree tree, ITYPE_t n_nodes, ITYPE_t n_features): +# cdef int allocate_data(BinaryTree tree, intp_t n_nodes, intp_t n_features): # """Allocate arrays needed for the KD Tree""" -# cdef int init_node(BinaryTree tree, ITYPE_t i_node, -# ITYPE_t idx_start, ITYPE_t idx_end): +# cdef int init_node(BinaryTree tree, intp_t i_node, +# intp_t idx_start, intp_t idx_end): # """Initialize the node for the dataset stored in tree.data""" -# cdef DTYPE_t min_rdist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt): +# cdef float64_t min_rdist(BinaryTree tree, intp_t i_node, float64_t* pt): # """Compute the minimum reduced-distance between a point and a node""" -# cdef DTYPE_t min_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt): +# cdef float64_t min_dist(BinaryTree tree, intp_t i_node, float64_t* pt): # """Compute the minimum distance between a point and a node""" -# cdef DTYPE_t max_rdist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt): +# cdef float64_t max_rdist(BinaryTree tree, intp_t i_node, float64_t* pt): # """Compute the maximum reduced-distance between a point and a node""" -# cdef DTYPE_t max_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt): +# cdef float64_t max_dist(BinaryTree tree, intp_t i_node, float64_t* pt): # """Compute the maximum distance between a point and a node""" -# cdef inline int min_max_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt, -# DTYPE_t* min_dist, DTYPE_t* max_dist): +# cdef inline int min_max_dist(BinaryTree tree, intp_t i_node, float64_t* pt, +# float64_t* min_dist, float64_t* max_dist): # """Compute the minimum and maximum distance between a point and a node""" -# cdef inline DTYPE_t min_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, -# BinaryTree tree2, ITYPE_t i_node2): +# cdef inline float64_t min_rdist_dual(BinaryTree tree1, intp_t i_node1, +# BinaryTree tree2, intp_t i_node2): # """Compute the minimum reduced distance between two nodes""" -# cdef inline DTYPE_t min_dist_dual(BinaryTree tree1, ITYPE_t i_node1, -# BinaryTree tree2, ITYPE_t i_node2): +# cdef inline float64_t min_dist_dual(BinaryTree tree1, intp_t i_node1, +# BinaryTree tree2, intp_t i_node2): # """Compute the minimum distance between two nodes""" -# cdef inline DTYPE_t max_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, -# BinaryTree tree2, ITYPE_t i_node2): +# cdef inline float64_t max_rdist_dual(BinaryTree tree1, intp_t i_node1, +# BinaryTree tree2, intp_t i_node2): # """Compute the maximum reduced distance between two nodes""" -# cdef inline DTYPE_t max_dist_dual(BinaryTree tree1, ITYPE_t i_node1, -# BinaryTree tree2, ITYPE_t i_node2): +# cdef inline float64_t max_dist_dual(BinaryTree tree1, intp_t i_node1, +# BinaryTree tree2, intp_t i_node2): # """Compute the maximum distance between two nodes""" cimport numpy as cnp @@ -161,41 +161,42 @@ from ..metrics._dist_metrics cimport ( from ._partition_nodes cimport partition_node_indices from ..utils import check_array -from ..utils._typedefs cimport DTYPE_t, ITYPE_t -from ..utils._typedefs import DTYPE, ITYPE +from ..utils._typedefs cimport float64_t, intp_t from ..utils._heap cimport heap_push from ..utils._sorting cimport simultaneous_sort as _simultaneous_sort +cnp.import_array() + + # TODO: use cnp.PyArray_ENABLEFLAGS when Cython>=3.0 is used. cdef extern from "numpy/arrayobject.h": void PyArray_ENABLEFLAGS(cnp.ndarray arr, int flags) -cnp.import_array() # some handy constants -cdef DTYPE_t INF = np.inf -cdef DTYPE_t NEG_INF = -np.inf -cdef DTYPE_t PI = np.pi -cdef DTYPE_t ROOT_2PI = sqrt(2 * PI) -cdef DTYPE_t LOG_PI = log(PI) -cdef DTYPE_t LOG_2PI = log(2 * PI) +cdef float64_t INF = np.inf +cdef float64_t NEG_INF = -np.inf +cdef float64_t PI = np.pi +cdef float64_t ROOT_2PI = sqrt(2 * PI) +cdef float64_t LOG_PI = log(PI) +cdef float64_t LOG_2PI = log(2 * PI) # Some compound datatypes used below: cdef struct NodeHeapData_t: - DTYPE_t val - ITYPE_t i1 - ITYPE_t i2 + float64_t val + intp_t i1 + intp_t i2 # build the corresponding numpy dtype for NodeHeapData cdef NodeHeapData_t nhd_tmp NodeHeapData = np.asarray((&nhd_tmp)).dtype cdef struct NodeData_t: - ITYPE_t idx_start - ITYPE_t idx_end - ITYPE_t is_leaf - DTYPE_t radius + intp_t idx_start + intp_t idx_end + intp_t is_leaf + float64_t radius # build the corresponding numpy dtype for NodeData cdef NodeData_t nd_tmp @@ -317,15 +318,15 @@ Compute a two-point auto-correlation function ###################################################################### # Utility functions -cdef DTYPE_t logaddexp(DTYPE_t x1, DTYPE_t x2): +cdef float64_t logaddexp(float64_t x1, float64_t x2): """logaddexp(x1, x2) -> log(exp(x1) + exp(x2))""" - cdef DTYPE_t a = fmax(x1, x2) + cdef float64_t a = fmax(x1, x2) if a == NEG_INF: return NEG_INF else: return a + log(exp(x1 - a) + exp(x2 - a)) -cdef DTYPE_t logsubexp(DTYPE_t x1, DTYPE_t x2): +cdef float64_t logsubexp(float64_t x1, float64_t x2): """logsubexp(x1, x2) -> log(exp(x1) - exp(x2))""" if x1 <= x2: return NEG_INF @@ -352,12 +353,12 @@ cdef enum KernelType: COSINE_KERNEL = 6 -cdef inline DTYPE_t log_gaussian_kernel(DTYPE_t dist, DTYPE_t h): +cdef inline float64_t log_gaussian_kernel(float64_t dist, float64_t h): """log of the gaussian kernel for bandwidth h (unnormalized)""" return -0.5 * (dist * dist) / (h * h) -cdef inline DTYPE_t log_tophat_kernel(DTYPE_t dist, DTYPE_t h): +cdef inline float64_t log_tophat_kernel(float64_t dist, float64_t h): """log of the tophat kernel for bandwidth h (unnormalized)""" if dist < h: return 0.0 @@ -365,7 +366,7 @@ cdef inline DTYPE_t log_tophat_kernel(DTYPE_t dist, DTYPE_t h): return NEG_INF -cdef inline DTYPE_t log_epanechnikov_kernel(DTYPE_t dist, DTYPE_t h): +cdef inline float64_t log_epanechnikov_kernel(float64_t dist, float64_t h): """log of the epanechnikov kernel for bandwidth h (unnormalized)""" if dist < h: return log(1.0 - (dist * dist) / (h * h)) @@ -373,12 +374,12 @@ cdef inline DTYPE_t log_epanechnikov_kernel(DTYPE_t dist, DTYPE_t h): return NEG_INF -cdef inline DTYPE_t log_exponential_kernel(DTYPE_t dist, DTYPE_t h): +cdef inline float64_t log_exponential_kernel(float64_t dist, float64_t h): """log of the exponential kernel for bandwidth h (unnormalized)""" return -dist / h -cdef inline DTYPE_t log_linear_kernel(DTYPE_t dist, DTYPE_t h): +cdef inline float64_t log_linear_kernel(float64_t dist, float64_t h): """log of the linear kernel for bandwidth h (unnormalized)""" if dist < h: return log(1 - dist / h) @@ -386,7 +387,7 @@ cdef inline DTYPE_t log_linear_kernel(DTYPE_t dist, DTYPE_t h): return NEG_INF -cdef inline DTYPE_t log_cosine_kernel(DTYPE_t dist, DTYPE_t h): +cdef inline float64_t log_cosine_kernel(float64_t dist, float64_t h): """log of the cosine kernel for bandwidth h (unnormalized)""" if dist < h: return log(cos(0.5 * PI * dist / h)) @@ -394,7 +395,7 @@ cdef inline DTYPE_t log_cosine_kernel(DTYPE_t dist, DTYPE_t h): return NEG_INF -cdef inline DTYPE_t compute_log_kernel(DTYPE_t dist, DTYPE_t h, +cdef inline float64_t compute_log_kernel(float64_t dist, float64_t h, KernelType kernel): """Given a KernelType enumeration, compute the appropriate log-kernel""" if kernel == GAUSSIAN_KERNEL: @@ -414,24 +415,24 @@ cdef inline DTYPE_t compute_log_kernel(DTYPE_t dist, DTYPE_t h, #------------------------------------------------------------ # Kernel norms are defined via the volume element V_n # and surface element S_(n-1) of an n-sphere. -cdef DTYPE_t logVn(ITYPE_t n): +cdef float64_t logVn(intp_t n): """V_n = pi^(n/2) / gamma(n/2 - 1)""" return 0.5 * n * LOG_PI - lgamma(0.5 * n + 1) -cdef DTYPE_t logSn(ITYPE_t n): +cdef float64_t logSn(intp_t n): """V_(n+1) = int_0^1 S_n r^n dr""" return LOG_2PI + logVn(n - 1) -cdef DTYPE_t _log_kernel_norm(DTYPE_t h, ITYPE_t d, +cdef float64_t _log_kernel_norm(float64_t h, intp_t d, KernelType kernel) except -1: """Given a KernelType enumeration, compute the kernel normalization. h is the bandwidth, d is the dimension. """ - cdef DTYPE_t tmp, factor = 0 - cdef ITYPE_t k + cdef float64_t tmp, factor = 0 + cdef intp_t k if kernel == GAUSSIAN_KERNEL: factor = 0.5 * d * LOG_2PI elif kernel == TOPHAT_KERNEL: @@ -512,21 +513,21 @@ cdef class NeighborsHeap: n_nbrs : int the size of each heap. """ - cdef DTYPE_t[:, ::1] distances - cdef ITYPE_t[:, ::1] indices + cdef float64_t[:, ::1] distances + cdef intp_t[:, ::1] indices def __cinit__(self): # One-element arrays are used as placeholders to prevent # any problem due to potential access to those attributes # (e.g. assigning to NULL or a to value in another segment). - self.distances = np.zeros((1, 1), dtype=DTYPE, order='C') - self.indices = np.zeros((1, 1), dtype=ITYPE, order='C') + self.distances = np.zeros((1, 1), dtype=np.float64, order='C') + self.indices = np.zeros((1, 1), dtype=np.intp, order='C') def __init__(self, n_pts, n_nbrs): self.distances = np.full( - (n_pts, n_nbrs), np.inf, dtype=DTYPE, order='C' + (n_pts, n_nbrs), np.inf, dtype=np.float64, order='C' ) - self.indices = np.zeros((n_pts, n_nbrs), dtype=ITYPE, order='C') + self.indices = np.zeros((n_pts, n_nbrs), dtype=np.intp, order='C') def get_arrays(self, sort=True): """Get the arrays of distances and indices within the heap. @@ -538,15 +539,15 @@ cdef class NeighborsHeap: self._sort() return self.distances.base, self.indices.base - cdef inline DTYPE_t largest(self, ITYPE_t row) except -1 nogil: + cdef inline float64_t largest(self, intp_t row) except -1 nogil: """Return the largest distance in the given row""" return self.distances[row, 0] - def push(self, ITYPE_t row, DTYPE_t val, ITYPE_t i_val): + def push(self, intp_t row, float64_t val, intp_t i_val): return self._push(row, val, i_val) - cdef int _push(self, ITYPE_t row, DTYPE_t val, - ITYPE_t i_val) except -1 nogil: + cdef int _push(self, intp_t row, float64_t val, + intp_t i_val) except -1 nogil: """push (val, i_val) into the given row""" return heap_push( values=&self.distances[row, 0], @@ -558,7 +559,7 @@ cdef class NeighborsHeap: cdef int _sort(self) except -1: """simultaneously sort the distances and indices""" - cdef ITYPE_t row + cdef intp_t row for row in range(self.distances.shape[0]): _simultaneous_sort( dist=&self.distances[row, 0], @@ -571,10 +572,10 @@ cdef class NeighborsHeap: # find_node_split_dim: # this computes the equivalent of # j_max = np.argmax(np.max(data, 0) - np.min(data, 0)) -cdef ITYPE_t find_node_split_dim(DTYPE_t* data, - ITYPE_t* node_indices, - ITYPE_t n_features, - ITYPE_t n_points) except -1: +cdef intp_t find_node_split_dim(float64_t* data, + intp_t* node_indices, + intp_t n_features, + intp_t n_points) except -1: """Find the dimension with the largest spread. Parameters @@ -601,8 +602,8 @@ cdef ITYPE_t find_node_split_dim(DTYPE_t* data, The cython version is much more efficient in both computation and memory. """ - cdef DTYPE_t min_val, max_val, val, spread, max_spread - cdef ITYPE_t i, j, j_max + cdef float64_t min_val, max_val, val, spread, max_spread + cdef intp_t i, j, j_max j_max = 0 max_spread = 0 @@ -624,7 +625,7 @@ cdef ITYPE_t find_node_split_dim(DTYPE_t* data, ###################################################################### # NodeHeap : min-heap used to keep track of nodes during # breadth-first query -cdef inline void swap_nodes(NodeHeapData_t* arr, ITYPE_t i1, ITYPE_t i2): +cdef inline void swap_nodes(NodeHeapData_t* arr, intp_t i1, intp_t i2): cdef NodeHeapData_t tmp = arr[i1] arr[i1] = arr[i2] arr[i2] = tmp @@ -644,7 +645,7 @@ cdef class NodeHeap: heap[i].val < min(heap[2 * i + 1].val, heap[2 * i + 2].val) """ cdef NodeHeapData_t[:] data - cdef ITYPE_t n + cdef intp_t n def __cinit__(self): # A one-elements array is used as a placeholder to prevent @@ -658,13 +659,13 @@ cdef class NodeHeap: self.n = size_guess self.clear() - cdef int resize(self, ITYPE_t new_size) except -1: + cdef int resize(self, intp_t new_size) except -1: """Resize the heap to be either larger or smaller""" cdef: NodeHeapData_t *data_ptr NodeHeapData_t *new_data_ptr - ITYPE_t i - ITYPE_t size = self.data.shape[0] + intp_t i + intp_t size = self.data.shape[0] NodeHeapData_t[:] new_data = np.zeros( new_size, dtype=NodeHeapData, @@ -684,7 +685,7 @@ cdef class NodeHeap: cdef int push(self, NodeHeapData_t data) except -1: """Push a new item onto the heap""" - cdef ITYPE_t i, i_parent + cdef intp_t i, i_parent cdef NodeHeapData_t* data_arr self.n += 1 if self.n > self.data.shape[0]: @@ -714,7 +715,7 @@ cdef class NodeHeap: if self.n == 0: raise ValueError('cannot pop on empty heap') - cdef ITYPE_t i, i_child1, i_child2, i_swap + cdef intp_t i, i_child1, i_child2, i_swap cdef NodeHeapData_t* data_arr = &self.data[0] cdef NodeHeapData_t popped_element = data_arr[0] @@ -770,17 +771,17 @@ VALID_METRIC_IDS = get_valid_metric_ids(VALID_METRICS) # Binary Tree class cdef class BinaryTree: - cdef readonly const DTYPE_t[:, ::1] data - cdef readonly const DTYPE_t[::1] sample_weight - cdef public DTYPE_t sum_weight + cdef readonly const float64_t[:, ::1] data + cdef readonly const float64_t[::1] sample_weight + cdef public float64_t sum_weight - cdef public const ITYPE_t[::1] idx_array + cdef public const intp_t[::1] idx_array cdef public const NodeData_t[::1] node_data - cdef public const DTYPE_t[:, :, ::1] node_bounds + cdef public const float64_t[:, :, ::1] node_bounds - cdef ITYPE_t leaf_size - cdef ITYPE_t n_levels - cdef ITYPE_t n_nodes + cdef intp_t leaf_size + cdef intp_t n_levels + cdef intp_t n_nodes cdef DistanceMetric dist_metric cdef int euclidean @@ -799,11 +800,11 @@ cdef class BinaryTree: # any problem due to potential access to this attribute # (e.g. assigning to NULL or a to value in another segment). def __cinit__(self): - self.data = np.empty((1, 1), dtype=DTYPE, order='C') - self.sample_weight = np.empty(1, dtype=DTYPE, order='C') - self.idx_array = np.empty(1, dtype=ITYPE, order='C') + self.data = np.empty((1, 1), dtype=np.float64, order='C') + self.sample_weight = np.empty(1, dtype=np.float64, order='C') + self.idx_array = np.empty(1, dtype=np.intp, order='C') self.node_data = np.empty(1, dtype=NodeData, order='C') - self.node_bounds = np.empty((1, 1, 1), dtype=DTYPE) + self.node_bounds = np.empty((1, 1, 1), dtype=np.float64) self.leaf_size = 0 self.n_levels = 0 @@ -819,7 +820,7 @@ cdef class BinaryTree: def __init__(self, data, leaf_size=40, metric='minkowski', sample_weight=None, **kwargs): # validate data - self.data = check_array(data, dtype=DTYPE, order='C') + self.data = check_array(data, dtype=np.float64, order='C') if self.data.size == 0: raise ValueError("X is an empty array") @@ -849,7 +850,7 @@ cdef class BinaryTree: self.n_nodes = (2 ** self.n_levels) - 1 # allocate arrays for storage - self.idx_array = np.arange(n_samples, dtype=ITYPE) + self.idx_array = np.arange(n_samples, dtype=np.intp) self.node_data = np.zeros(self.n_nodes, dtype=NodeData) self._update_sample_weight(n_samples, sample_weight) @@ -866,11 +867,11 @@ cdef class BinaryTree: def _update_sample_weight(self, n_samples, sample_weight): if sample_weight is not None: self.sample_weight = np.asarray( - sample_weight, dtype=DTYPE, order='C') + sample_weight, dtype=np.float64, order='C') self.sum_weight = np.sum(self.sample_weight) else: self.sample_weight = None - self.sum_weight = n_samples + self.sum_weight = n_samples def __reduce__(self): @@ -992,8 +993,8 @@ cdef class BinaryTree: """ return cls._valid_metrics - cdef inline DTYPE_t dist(self, DTYPE_t* x1, DTYPE_t* x2, - ITYPE_t size) except -1 nogil: + cdef inline float64_t dist(self, float64_t* x1, float64_t* x2, + intp_t size) except -1 nogil: """Compute the distance between arrays x1 and x2""" self.n_calls += 1 if self.euclidean: @@ -1001,8 +1002,8 @@ cdef class BinaryTree: else: return self.dist_metric.dist(x1, x2, size) - cdef inline DTYPE_t rdist(self, DTYPE_t* x1, DTYPE_t* x2, - ITYPE_t size) except -1 nogil: + cdef inline float64_t rdist(self, float64_t* x1, float64_t* x2, + intp_t size) except -1 nogil: """Compute the reduced distance between arrays x1 and x2. The reduced distance, defined for some metrics, is a quantity which @@ -1016,8 +1017,8 @@ cdef class BinaryTree: else: return self.dist_metric.rdist(x1, x2, size) - cdef int _recursive_build(self, NodeData_t[::1] node_data, ITYPE_t i_node, ITYPE_t idx_start, - ITYPE_t idx_end) except -1: + cdef int _recursive_build(self, NodeData_t[::1] node_data, intp_t i_node, intp_t idx_start, + intp_t idx_end) except -1: """Recursively build the tree. Parameters @@ -1028,12 +1029,12 @@ cdef class BinaryTree: the bounding indices in the idx_array which define the points that belong to this node. """ - cdef ITYPE_t imax - cdef ITYPE_t n_features = self.data.shape[1] - cdef ITYPE_t n_points = idx_end - idx_start - cdef ITYPE_t n_mid = n_points / 2 - cdef ITYPE_t* idx_array = &self.idx_array[idx_start] - cdef DTYPE_t* data = &self.data[0, 0] + cdef intp_t imax + cdef intp_t n_features = self.data.shape[1] + cdef intp_t n_points = idx_end - idx_start + cdef intp_t n_mid = n_points / 2 + cdef intp_t* idx_array = &self.idx_array[idx_start] + cdef float64_t* data = &self.data[0, 0] # initialize node data init_node(self, node_data, i_node, idx_start, idx_end) @@ -1113,7 +1114,7 @@ cdef class BinaryTree: corresponding point. """ # XXX: we should allow X to be a pre-built tree. - X = check_array(X, dtype=DTYPE, order='C') + X = check_array(X, dtype=np.float64, order='C') if X.shape[X.ndim - 1] != self.data.shape[1]: raise ValueError("query data dimension must " @@ -1125,10 +1126,10 @@ cdef class BinaryTree: # flatten X, and save original shape information np_Xarr = X.reshape((-1, self.data.shape[1])) - cdef const DTYPE_t[:, ::1] Xarr = np_Xarr - cdef DTYPE_t reduced_dist_LB - cdef ITYPE_t i - cdef DTYPE_t* pt + cdef const float64_t[:, ::1] Xarr = np_Xarr + cdef float64_t reduced_dist_LB + cdef intp_t i + cdef float64_t* pt # initialize heap for neighbors cdef NeighborsHeap heap = NeighborsHeap(Xarr.shape[0], k) @@ -1139,7 +1140,7 @@ cdef class BinaryTree: nodeheap = NodeHeap(self.data.shape[0] // self.leaf_size) # bounds is needed for the dual tree algorithm - cdef DTYPE_t[::1] bounds + cdef float64_t[::1] bounds self.n_trims = 0 self.n_leaves = 0 @@ -1241,52 +1242,52 @@ cdef class BinaryTree: raise ValueError("return_distance must be True " "if sort_results is True") - cdef ITYPE_t i, count_i = 0 - cdef ITYPE_t n_features = self.data.shape[1] - cdef DTYPE_t[::1] dist_arr_i - cdef ITYPE_t[::1] idx_arr_i, counts - cdef DTYPE_t* pt - cdef ITYPE_t** indices = NULL - cdef DTYPE_t** distances = NULL + cdef intp_t i, count_i = 0 + cdef intp_t n_features = self.data.shape[1] + cdef float64_t[::1] dist_arr_i + cdef intp_t[::1] idx_arr_i, counts + cdef float64_t* pt + cdef intp_t** indices = NULL + cdef float64_t** distances = NULL # validate X and prepare for query - X = check_array(X, dtype=DTYPE, order='C') + X = check_array(X, dtype=np.float64, order='C') if X.shape[X.ndim - 1] != self.data.shape[1]: raise ValueError("query data dimension must " "match training data dimension") - cdef const DTYPE_t[:, ::1] Xarr = X.reshape((-1, self.data.shape[1])) + cdef const float64_t[:, ::1] Xarr = X.reshape((-1, self.data.shape[1])) # prepare r for query - r = np.asarray(r, dtype=DTYPE, order='C') + r = np.asarray(r, dtype=np.float64, order='C') r = np.atleast_1d(r) if r.shape == (1,): - r = np.full(X.shape[:X.ndim - 1], r[0], dtype=DTYPE) + r = np.full(X.shape[:X.ndim - 1], r[0], dtype=np.float64) else: if r.shape != X.shape[:X.ndim - 1]: raise ValueError("r must be broadcastable to X.shape") rarr_np = r.reshape(-1) # store explicitly to keep in scope - cdef DTYPE_t[::1] rarr = rarr_np + cdef float64_t[::1] rarr = rarr_np if not count_only: - indices = calloc(Xarr.shape[0], sizeof(ITYPE_t*)) + indices = calloc(Xarr.shape[0], sizeof(intp_t*)) if indices == NULL: raise MemoryError() if return_distance: - distances = calloc(Xarr.shape[0], sizeof(DTYPE_t*)) + distances = calloc(Xarr.shape[0], sizeof(float64_t*)) if distances == NULL: free(indices) raise MemoryError() - np_idx_arr = np.zeros(self.data.shape[0], dtype=ITYPE) + np_idx_arr = np.zeros(self.data.shape[0], dtype=np.intp) idx_arr_i = np_idx_arr - np_dist_arr = np.zeros(self.data.shape[0], dtype=DTYPE) + np_dist_arr = np.zeros(self.data.shape[0], dtype=np.float64) dist_arr_i = np_dist_arr - counts_arr = np.zeros(Xarr.shape[0], dtype=ITYPE) + counts_arr = np.zeros(Xarr.shape[0], dtype=np.intp) counts = counts_arr pt = &Xarr[0, 0] @@ -1308,19 +1309,19 @@ cdef class BinaryTree: counts[i]) # equivalent to: indices[i] = np_idx_arr[:counts[i]].copy() - indices[i] = malloc(counts[i] * sizeof(ITYPE_t)) + indices[i] = malloc(counts[i] * sizeof(intp_t)) if indices[i] == NULL: memory_error = True break - memcpy(indices[i], &idx_arr_i[0], counts[i] * sizeof(ITYPE_t)) + memcpy(indices[i], &idx_arr_i[0], counts[i] * sizeof(intp_t)) if return_distance: # equivalent to: distances[i] = np_dist_arr[:counts[i]].copy() - distances[i] = malloc(counts[i] * sizeof(DTYPE_t)) + distances[i] = malloc(counts[i] * sizeof(float64_t)) if distances[i] == NULL: memory_error = True break - memcpy(distances[i], &dist_arr_i[0], counts[i] * sizeof(DTYPE_t)) + memcpy(distances[i], &dist_arr_i[0], counts[i] * sizeof(float64_t)) try: if memory_error: @@ -1334,14 +1335,16 @@ cdef class BinaryTree: distances_npy = np.zeros(Xarr.shape[0], dtype='object') for i in range(Xarr.shape[0]): # make a new numpy array that wraps the existing data - indices_npy[i] = cnp.PyArray_SimpleNewFromData(1, &counts[i], cnp.NPY_INTP, indices[i]) + # TODO: remove the explicit cast to cnp.intp_t* when cython min version >= 3.0 + indices_npy[i] = cnp.PyArray_SimpleNewFromData(1, &counts[i], cnp.NPY_INTP, indices[i]) # make sure the data will be freed when the numpy array is garbage collected PyArray_ENABLEFLAGS(indices_npy[i], cnp.NPY_ARRAY_OWNDATA) # make sure the data is not freed twice indices[i] = NULL # make a new numpy array that wraps the existing data - distances_npy[i] = cnp.PyArray_SimpleNewFromData(1, &counts[i], cnp.NPY_DOUBLE, distances[i]) + # TODO: remove the explicit cast to cnp.intp_t* when cython min version >= 3.0 + distances_npy[i] = cnp.PyArray_SimpleNewFromData(1, &counts[i], cnp.NPY_DOUBLE, distances[i]) # make sure the data will be freed when the numpy array is garbage collected PyArray_ENABLEFLAGS(distances_npy[i], cnp.NPY_ARRAY_OWNDATA) # make sure the data is not freed twice @@ -1354,7 +1357,8 @@ cdef class BinaryTree: indices_npy = np.zeros(Xarr.shape[0], dtype='object') for i in range(Xarr.shape[0]): # make a new numpy array that wraps the existing data - indices_npy[i] = cnp.PyArray_SimpleNewFromData(1, &counts[i], cnp.NPY_INTP, indices[i]) + # TODO: remove the explicit cast to cnp.intp_t* when cython min version >= 3.0 + indices_npy[i] = cnp.PyArray_SimpleNewFromData(1, &counts[i], cnp.NPY_INTP, indices[i]) # make sure the data will be freed when the numpy array is garbage collected PyArray_ENABLEFLAGS(indices_npy[i], cnp.NPY_ARRAY_OWNDATA) # make sure the data is not freed twice @@ -1423,15 +1427,15 @@ cdef class BinaryTree: density : ndarray of shape X.shape[:-1] The array of (log)-density evaluations """ - cdef DTYPE_t h_c = h - cdef DTYPE_t log_atol = log(atol) - cdef DTYPE_t log_rtol = log(rtol) - cdef DTYPE_t log_min_bound, log_max_bound, log_bound_spread - cdef DTYPE_t dist_LB = 0, dist_UB = 0 - - cdef ITYPE_t n_samples = self.data.shape[0] - cdef ITYPE_t n_features = self.data.shape[1] - cdef ITYPE_t i + cdef float64_t h_c = h + cdef float64_t log_atol = log(atol) + cdef float64_t log_rtol = log(rtol) + cdef float64_t log_min_bound, log_max_bound, log_bound_spread + cdef float64_t dist_LB = 0, dist_UB = 0 + + cdef intp_t n_samples = self.data.shape[0] + cdef intp_t n_features = self.data.shape[1] + cdef intp_t i cdef KernelType kernel_c # validate kernel @@ -1450,27 +1454,27 @@ cdef class BinaryTree: else: raise ValueError("kernel = '%s' not recognized" % kernel) - cdef DTYPE_t log_knorm = _log_kernel_norm(h_c, n_features, kernel_c) + cdef float64_t log_knorm = _log_kernel_norm(h_c, n_features, kernel_c) # validate X and prepare for query - X = check_array(X, dtype=DTYPE, order='C') + X = check_array(X, dtype=np.float64, order='C') if X.shape[X.ndim - 1] != n_features: raise ValueError("query data dimension must " "match training data dimension") Xarr_np = X.reshape((-1, n_features)) - cdef DTYPE_t[:, ::1] Xarr = Xarr_np + cdef float64_t[:, ::1] Xarr = Xarr_np - log_density_arr = np.zeros(Xarr.shape[0], dtype=DTYPE) - cdef DTYPE_t[::1] log_density = log_density_arr + log_density_arr = np.zeros(Xarr.shape[0], dtype=np.float64) + cdef float64_t[::1] log_density = log_density_arr - cdef DTYPE_t* pt = &Xarr[0, 0] + cdef float64_t* pt = &Xarr[0, 0] cdef NodeHeap nodeheap if breadth_first: nodeheap = NodeHeap(self.data.shape[0] // self.leaf_size) - cdef DTYPE_t[::1] node_log_min_bounds - cdef DTYPE_t[::1] node_bound_widths + cdef float64_t[::1] node_log_min_bounds + cdef float64_t[::1] node_bound_widths # TODO: implement dual tree approach. # this is difficult because of the need to cache values # computed between node pairs. @@ -1543,33 +1547,33 @@ cdef class BinaryTree: counts[i] contains the number of pairs of points with distance less than or equal to r[i] """ - cdef ITYPE_t n_features = self.data.shape[1] - cdef ITYPE_t i + cdef intp_t n_features = self.data.shape[1] + cdef intp_t i # validate X and prepare for query - X = check_array(X, dtype=DTYPE, order='C') + X = check_array(X, dtype=np.float64, order='C') if X.shape[X.ndim - 1] != self.data.shape[1]: raise ValueError("query data dimension must " "match training data dimension") np_Xarr = X.reshape((-1, self.data.shape[1])) - cdef DTYPE_t[:, ::1] Xarr = np_Xarr + cdef float64_t[:, ::1] Xarr = np_Xarr # prepare r for query - r = np.asarray(r, dtype=DTYPE, order='C') + r = np.asarray(r, dtype=np.float64, order='C') r = np.atleast_1d(r) if r.ndim != 1: raise ValueError("r must be a 1-dimensional array") i_rsort = np.argsort(r) rarr_np = r[i_rsort] # needed to keep memory in scope - cdef DTYPE_t[::1] rarr = rarr_np + cdef float64_t[::1] rarr = rarr_np # create array to hold counts - count = np.zeros(r.shape[0], dtype=ITYPE) - cdef ITYPE_t[::1] carr = count + count = np.zeros(r.shape[0], dtype=np.intp) + cdef intp_t[::1] carr = count - cdef DTYPE_t* pt = &Xarr[0, 0] + cdef float64_t* pt = &Xarr[0, 0] if dualtree: other = self.__class__(Xarr, metric=self.dist_metric, @@ -1584,17 +1588,17 @@ cdef class BinaryTree: return count - cdef int _query_single_depthfirst(self, ITYPE_t i_node, - DTYPE_t* pt, ITYPE_t i_pt, + cdef int _query_single_depthfirst(self, intp_t i_node, + float64_t* pt, intp_t i_pt, NeighborsHeap heap, - DTYPE_t reduced_dist_LB) except -1 nogil: + float64_t reduced_dist_LB) except -1 nogil: """Recursive Single-tree k-neighbors query, depth-first approach""" cdef NodeData_t node_info = self.node_data[i_node] - cdef DTYPE_t dist_pt, reduced_dist_LB_1, reduced_dist_LB_2 - cdef ITYPE_t i, i1, i2 + cdef float64_t dist_pt, reduced_dist_LB_1, reduced_dist_LB_2 + cdef intp_t i, i1, i2 - cdef DTYPE_t* data = &self.data[0, 0] + cdef float64_t* data = &self.data[0, 0] #------------------------------------------------------------ # Case 1: query point is outside node radius: @@ -1635,15 +1639,15 @@ cdef class BinaryTree: reduced_dist_LB_1) return 0 - cdef int _query_single_breadthfirst(self, DTYPE_t* pt, - ITYPE_t i_pt, + cdef int _query_single_breadthfirst(self, float64_t* pt, + intp_t i_pt, NeighborsHeap heap, NodeHeap nodeheap) except -1: """Non-recursive single-tree k-neighbors query, breadth-first search""" - cdef ITYPE_t i, i_node - cdef DTYPE_t dist_pt, reduced_dist_LB + cdef intp_t i, i_node + cdef float64_t dist_pt, reduced_dist_LB cdef NodeData_t* node_data = &self.node_data[0] - cdef DTYPE_t* data = &self.data[0, 0] + cdef float64_t* data = &self.data[0, 0] # Set up the node heap and push the head node onto it cdef NodeHeapData_t nodeheap_item @@ -1684,11 +1688,11 @@ cdef class BinaryTree: nodeheap.push(nodeheap_item) return 0 - cdef int _query_dual_depthfirst(self, ITYPE_t i_node1, - BinaryTree other, ITYPE_t i_node2, - DTYPE_t[::1] bounds, + cdef int _query_dual_depthfirst(self, intp_t i_node1, + BinaryTree other, intp_t i_node2, + float64_t[::1] bounds, NeighborsHeap heap, - DTYPE_t reduced_dist_LB) except -1: + float64_t reduced_dist_LB) except -1: """Recursive dual-tree k-neighbors query, depth-first""" # note that the array `bounds` is maintained such that # bounds[i] is the largest distance among any of the @@ -1696,12 +1700,12 @@ cdef class BinaryTree: cdef NodeData_t node_info1 = self.node_data[i_node1] cdef NodeData_t node_info2 = other.node_data[i_node2] - cdef DTYPE_t* data1 = &self.data[0, 0] - cdef DTYPE_t* data2 = &other.data[0, 0] - cdef ITYPE_t n_features = self.data.shape[1] + cdef float64_t* data1 = &self.data[0, 0] + cdef float64_t* data2 = &other.data[0, 0] + cdef intp_t n_features = self.data.shape[1] - cdef DTYPE_t bound_max, dist_pt, reduced_dist_LB1, reduced_dist_LB2 - cdef ITYPE_t i1, i2, i_pt, i_parent + cdef float64_t bound_max, dist_pt, reduced_dist_LB1, reduced_dist_LB2 + cdef intp_t i1, i2, i_pt, i_parent #------------------------------------------------------------ # Case 1: nodes are further apart than the current bound: @@ -1789,15 +1793,15 @@ cdef class BinaryTree: NeighborsHeap heap, NodeHeap nodeheap) except -1: """Non-recursive dual-tree k-neighbors query, breadth-first""" - cdef ITYPE_t i, i1, i2, i_node1, i_node2, i_pt - cdef DTYPE_t dist_pt, reduced_dist_LB - cdef DTYPE_t[::1] bounds = np.full(other.node_data.shape[0], np.inf) + cdef intp_t i, i1, i2, i_node1, i_node2, i_pt + cdef float64_t dist_pt, reduced_dist_LB + cdef float64_t[::1] bounds = np.full(other.node_data.shape[0], np.inf) cdef NodeData_t* node_data1 = &self.node_data[0] cdef NodeData_t* node_data2 = &other.node_data[0] cdef NodeData_t node_info1, node_info2 - cdef DTYPE_t* data1 = &self.data[0, 0] - cdef DTYPE_t* data2 = &other.data[0, 0] - cdef ITYPE_t n_features = self.data.shape[1] + cdef float64_t* data1 = &self.data[0, 0] + cdef float64_t* data2 = &other.data[0, 0] + cdef intp_t n_features = self.data.shape[1] # Set up the node heap and push the head nodes onto it cdef NodeHeapData_t nodeheap_item @@ -1869,24 +1873,24 @@ cdef class BinaryTree: nodeheap.push(nodeheap_item) return 0 - cdef ITYPE_t _query_radius_single(self, - ITYPE_t i_node, - DTYPE_t* pt, DTYPE_t r, - ITYPE_t* indices, - DTYPE_t* distances, - ITYPE_t count, + cdef intp_t _query_radius_single(self, + intp_t i_node, + float64_t* pt, float64_t r, + intp_t* indices, + float64_t* distances, + intp_t count, int count_only, int return_distance) noexcept nogil: """recursive single-tree radius query, depth-first""" - cdef DTYPE_t* data = &self.data[0, 0] - cdef ITYPE_t* idx_array = &self.idx_array[0] - cdef ITYPE_t n_features = self.data.shape[1] + cdef float64_t* data = &self.data[0, 0] + cdef intp_t* idx_array = &self.idx_array[0] + cdef intp_t n_features = self.data.shape[1] cdef NodeData_t node_info = self.node_data[i_node] - cdef ITYPE_t i - cdef DTYPE_t reduced_r + cdef intp_t i + cdef float64_t reduced_r - cdef DTYPE_t dist_pt, dist_LB = 0, dist_UB = 0 + cdef float64_t dist_pt, dist_LB = 0, dist_UB = 0 min_max_dist(self, i_node, pt, &dist_LB, &dist_UB) #------------------------------------------------------------ @@ -1945,13 +1949,13 @@ cdef class BinaryTree: return count - cdef DTYPE_t _kde_single_breadthfirst(self, DTYPE_t* pt, - KernelType kernel, DTYPE_t h, - DTYPE_t log_knorm, - DTYPE_t log_atol, DTYPE_t log_rtol, + cdef float64_t _kde_single_breadthfirst(self, float64_t* pt, + KernelType kernel, float64_t h, + float64_t log_knorm, + float64_t log_atol, float64_t log_rtol, NodeHeap nodeheap, - DTYPE_t* node_log_min_bounds, - DTYPE_t* node_log_bound_spreads): + float64_t* node_log_min_bounds, + float64_t* node_log_bound_spreads): """non-recursive single-tree kernel density estimation""" # For the given point, node_log_min_bounds and node_log_bound_spreads # will encode the current bounds on the density between the point @@ -1960,32 +1964,32 @@ cdef class BinaryTree: # keep track of the global bounds on density. The procedure here is # to split nodes, updating these bounds, until the bounds are within # atol & rtol. - cdef ITYPE_t i, i1, i2, i_node - cdef DTYPE_t N1, N2 - cdef DTYPE_t global_log_min_bound, global_log_bound_spread - cdef DTYPE_t global_log_max_bound + cdef intp_t i, i1, i2, i_node + cdef float64_t N1, N2 + cdef float64_t global_log_min_bound, global_log_bound_spread + cdef float64_t global_log_max_bound - cdef DTYPE_t* data = &self.data[0, 0] + cdef float64_t* data = &self.data[0, 0] cdef bint with_sample_weight = self.sample_weight is not None - cdef DTYPE_t* sample_weight + cdef float64_t* sample_weight if with_sample_weight: sample_weight = &self.sample_weight[0] - cdef ITYPE_t* idx_array = &self.idx_array[0] + cdef intp_t* idx_array = &self.idx_array[0] cdef NodeData_t* node_data = &self.node_data[0] - cdef DTYPE_t N - cdef DTYPE_t log_weight + cdef float64_t N + cdef float64_t log_weight if with_sample_weight: N = self.sum_weight else: - N = self.data.shape[0] - cdef ITYPE_t n_features = self.data.shape[1] + N = self.data.shape[0] + cdef intp_t n_features = self.data.shape[1] cdef NodeData_t node_info - cdef DTYPE_t dist_pt, log_density - cdef DTYPE_t dist_LB_1 = 0, dist_LB_2 = 0 - cdef DTYPE_t dist_UB_1 = 0, dist_UB_2 = 0 + cdef float64_t dist_pt, log_density + cdef float64_t dist_LB_1 = 0, dist_LB_2 = 0 + cdef float64_t dist_UB_1 = 0, dist_UB_2 = 0 - cdef DTYPE_t dist_UB, dist_LB + cdef float64_t dist_UB, dist_LB # push the top node to the heap cdef NodeHeapData_t nodeheap_item @@ -2110,47 +2114,47 @@ cdef class BinaryTree: global_log_bound_spread - log(2)) cdef int _kde_single_depthfirst( - self, ITYPE_t i_node, DTYPE_t* pt, - KernelType kernel, DTYPE_t h, - DTYPE_t log_knorm, - DTYPE_t log_atol, DTYPE_t log_rtol, - DTYPE_t local_log_min_bound, - DTYPE_t local_log_bound_spread, - DTYPE_t* global_log_min_bound, - DTYPE_t* global_log_bound_spread) except -1: + self, intp_t i_node, float64_t* pt, + KernelType kernel, float64_t h, + float64_t log_knorm, + float64_t log_atol, float64_t log_rtol, + float64_t local_log_min_bound, + float64_t local_log_bound_spread, + float64_t* global_log_min_bound, + float64_t* global_log_bound_spread) except -1: """recursive single-tree kernel density estimate, depth-first""" # For the given point, local_min_bound and local_max_bound give the # minimum and maximum density for the current node, while # global_min_bound and global_max_bound give the minimum and maximum # density over the entire tree. We recurse down until global_min_bound # and global_max_bound are within rtol and atol. - cdef ITYPE_t i, i1, i2, iw, start, end - cdef DTYPE_t N1, N2 + cdef intp_t i, i1, i2, iw, start, end + cdef float64_t N1, N2 - cdef DTYPE_t* data = &self.data[0, 0] + cdef float64_t* data = &self.data[0, 0] cdef NodeData_t* node_data = &self.node_data[0] cdef bint with_sample_weight = self.sample_weight is not None - cdef DTYPE_t* sample_weight - cdef DTYPE_t log_weight + cdef float64_t* sample_weight + cdef float64_t log_weight if with_sample_weight: sample_weight = &self.sample_weight[0] - cdef ITYPE_t* idx_array = &self.idx_array[0] - cdef ITYPE_t n_features = self.data.shape[1] + cdef intp_t* idx_array = &self.idx_array[0] + cdef intp_t n_features = self.data.shape[1] cdef NodeData_t node_info = self.node_data[i_node] - cdef DTYPE_t dist_pt, log_dens_contribution + cdef float64_t dist_pt, log_dens_contribution - cdef DTYPE_t child1_log_min_bound, child2_log_min_bound - cdef DTYPE_t child1_log_bound_spread, child2_log_bound_spread - cdef DTYPE_t dist_UB = 0, dist_LB = 0 + cdef float64_t child1_log_min_bound, child2_log_min_bound + cdef float64_t child1_log_bound_spread, child2_log_bound_spread + cdef float64_t dist_UB = 0, dist_LB = 0 if with_sample_weight: N1 = _total_node_weight(node_data, sample_weight, idx_array, i_node) N2 = self.sum_weight else: - N1 = (node_info.idx_end - node_info.idx_start) - N2 = self.data.shape[0] + N1 = (node_info.idx_end - node_info.idx_start) + N2 = self.data.shape[0] #------------------------------------------------------------ # Case 1: local bounds are equal to within errors. Return @@ -2197,8 +2201,8 @@ cdef class BinaryTree: N2 = _total_node_weight(node_data, sample_weight, idx_array, i2) else: - N1 = (self.node_data[i1].idx_end - self.node_data[i1].idx_start) - N2 = (self.node_data[i2].idx_end - self.node_data[i2].idx_start) + N1 = (self.node_data[i1].idx_end - self.node_data[i1].idx_start) + N2 = (self.node_data[i2].idx_end - self.node_data[i2].idx_start) min_max_dist(self, i1, pt, &dist_LB, &dist_UB) child1_log_min_bound = log(N1) + compute_log_kernel(dist_UB, h, @@ -2244,19 +2248,19 @@ cdef class BinaryTree: global_log_bound_spread) return 0 - cdef int _two_point_single(self, ITYPE_t i_node, DTYPE_t* pt, DTYPE_t* r, - ITYPE_t* count, ITYPE_t i_min, - ITYPE_t i_max) except -1: + cdef int _two_point_single(self, intp_t i_node, float64_t* pt, float64_t* r, + intp_t* count, intp_t i_min, + intp_t i_max) except -1: """recursive single-tree two-point correlation function query""" - cdef DTYPE_t* data = &self.data[0, 0] - cdef ITYPE_t* idx_array = &self.idx_array[0] - cdef ITYPE_t n_features = self.data.shape[1] + cdef float64_t* data = &self.data[0, 0] + cdef intp_t* idx_array = &self.idx_array[0] + cdef intp_t n_features = self.data.shape[1] cdef NodeData_t node_info = self.node_data[i_node] - cdef ITYPE_t i, j, Npts - cdef DTYPE_t reduced_r + cdef intp_t i, j, Npts + cdef float64_t reduced_r - cdef DTYPE_t dist_pt, dist_LB = 0, dist_UB = 0 + cdef float64_t dist_pt, dist_LB = 0, dist_UB = 0 min_max_dist(self, i_node, pt, &dist_LB, &dist_UB) #------------------------------------------------------------ @@ -2293,24 +2297,24 @@ cdef class BinaryTree: count, i_min, i_max) return 0 - cdef int _two_point_dual(self, ITYPE_t i_node1, - BinaryTree other, ITYPE_t i_node2, - DTYPE_t* r, ITYPE_t* count, - ITYPE_t i_min, ITYPE_t i_max) except -1: + cdef int _two_point_dual(self, intp_t i_node1, + BinaryTree other, intp_t i_node2, + float64_t* r, intp_t* count, + intp_t i_min, intp_t i_max) except -1: """recursive dual-tree two-point correlation function query""" - cdef DTYPE_t* data1 = &self.data[0, 0] - cdef DTYPE_t* data2 = &other.data[0, 0] - cdef ITYPE_t* idx_array1 = &self.idx_array[0] - cdef ITYPE_t* idx_array2 = &other.idx_array[0] + cdef float64_t* data1 = &self.data[0, 0] + cdef float64_t* data2 = &other.data[0, 0] + cdef intp_t* idx_array1 = &self.idx_array[0] + cdef intp_t* idx_array2 = &other.idx_array[0] cdef NodeData_t node_info1 = self.node_data[i_node1] cdef NodeData_t node_info2 = other.node_data[i_node2] - cdef ITYPE_t n_features = self.data.shape[1] + cdef intp_t n_features = self.data.shape[1] - cdef ITYPE_t i1, i2, j, Npts - cdef DTYPE_t reduced_r + cdef intp_t i1, i2, j, Npts + cdef float64_t reduced_r - cdef DTYPE_t dist_pt, dist_LB = 0, dist_UB = 0 + cdef float64_t dist_pt, dist_LB = 0, dist_UB = 0 dist_LB = min_dist_dual(self, i_node1, other, i_node2) dist_UB = max_dist_dual(self, i_node1, other, i_node2) @@ -2369,18 +2373,18 @@ cdef class BinaryTree: ###################################################################### # Python functions for benchmarking and testing C implementations -def load_heap(DTYPE_t[:, ::1] X, ITYPE_t k): +def load_heap(float64_t[:, ::1] X, intp_t k): """test fully loading the heap""" assert k <= X.shape[1] cdef NeighborsHeap heap = NeighborsHeap(X.shape[0], k) - cdef ITYPE_t i, j + cdef intp_t i, j for i in range(X.shape[0]): for j in range(X.shape[1]): heap._push(i, X[i, j], j) return heap.get_arrays() -def simultaneous_sort(DTYPE_t[:, ::1] distances, ITYPE_t[:, ::1] indices): +def simultaneous_sort(float64_t[:, ::1] distances, intp_t[:, ::1] indices): """In-place simultaneous sort the given row of the arrays This python wrapper exists primarily to enable unit testing @@ -2388,22 +2392,22 @@ def simultaneous_sort(DTYPE_t[:, ::1] distances, ITYPE_t[:, ::1] indices): """ assert distances.shape[0] == indices.shape[0] assert distances.shape[1] == indices.shape[1] - cdef ITYPE_t row + cdef intp_t row for row in range(distances.shape[0]): _simultaneous_sort(&distances[row, 0], &indices[row, 0], distances.shape[1]) -def nodeheap_sort(DTYPE_t[::1] vals): +def nodeheap_sort(float64_t[::1] vals): """In-place reverse sort of vals using NodeHeap""" - cdef ITYPE_t[::1] indices = np.zeros(vals.shape[0], dtype=ITYPE) - cdef DTYPE_t[::1] vals_sorted = np.zeros_like(vals) + cdef intp_t[::1] indices = np.zeros(vals.shape[0], dtype=np.intp) + cdef float64_t[::1] vals_sorted = np.zeros_like(vals) # use initial size 0 to check corner case cdef NodeHeap heap = NodeHeap(0) cdef NodeHeapData_t data - cdef ITYPE_t i + cdef intp_t i for i in range(vals.shape[0]): data.val = vals[i] data.i1 = i @@ -2418,12 +2422,12 @@ def nodeheap_sort(DTYPE_t[::1] vals): return np.asarray(vals_sorted), np.asarray(indices) -cdef inline DTYPE_t _total_node_weight(NodeData_t* node_data, - DTYPE_t* sample_weight, - ITYPE_t* idx_array, - ITYPE_t i_node): - cdef ITYPE_t i - cdef DTYPE_t N = 0.0 +cdef inline float64_t _total_node_weight(NodeData_t* node_data, + float64_t* sample_weight, + intp_t* idx_array, + intp_t i_node): + cdef intp_t i + cdef float64_t N = 0.0 for i in range(node_data[i_node].idx_start, node_data[i_node].idx_end): N += sample_weight[idx_array[i]] return N diff --git a/sklearn/neighbors/_kd_tree.pyx b/sklearn/neighbors/_kd_tree.pyx index a5db18b4ad772..d48589431f698 100644 --- a/sklearn/neighbors/_kd_tree.pyx +++ b/sklearn/neighbors/_kd_tree.pyx @@ -29,26 +29,26 @@ cdef class KDTree(BinaryTree): # For some metrics, the reduced distance is simply the distance. -cdef int allocate_data(BinaryTree tree, ITYPE_t n_nodes, - ITYPE_t n_features) except -1: +cdef int allocate_data(BinaryTree tree, intp_t n_nodes, + intp_t n_features) except -1: """Allocate arrays needed for the KD Tree""" - tree.node_bounds = np.zeros((2, n_nodes, n_features), dtype=DTYPE) + tree.node_bounds = np.zeros((2, n_nodes, n_features), dtype=np.float64) return 0 -cdef int init_node(BinaryTree tree, NodeData_t[::1] node_data, ITYPE_t i_node, - ITYPE_t idx_start, ITYPE_t idx_end) except -1: +cdef int init_node(BinaryTree tree, NodeData_t[::1] node_data, intp_t i_node, + intp_t idx_start, intp_t idx_end) except -1: """Initialize the node for the dataset stored in tree.data""" - cdef ITYPE_t n_features = tree.data.shape[1] - cdef ITYPE_t i, j - cdef DTYPE_t rad = 0 + cdef intp_t n_features = tree.data.shape[1] + cdef intp_t i, j + cdef float64_t rad = 0 - cdef DTYPE_t* lower_bounds = &tree.node_bounds[0, i_node, 0] - cdef DTYPE_t* upper_bounds = &tree.node_bounds[1, i_node, 0] - cdef DTYPE_t* data = &tree.data[0, 0] - cdef ITYPE_t* idx_array = &tree.idx_array[0] + cdef float64_t* lower_bounds = &tree.node_bounds[0, i_node, 0] + cdef float64_t* upper_bounds = &tree.node_bounds[1, i_node, 0] + cdef float64_t* data = &tree.data[0, 0] + cdef intp_t* idx_array = &tree.idx_array[0] - cdef DTYPE_t* data_row + cdef float64_t* data_row # determine Node bounds for j in range(n_features): @@ -81,12 +81,12 @@ cdef int init_node(BinaryTree tree, NodeData_t[::1] node_data, ITYPE_t i_node, return 0 -cdef DTYPE_t min_rdist(BinaryTree tree, ITYPE_t i_node, - DTYPE_t* pt) except -1 nogil: +cdef float64_t min_rdist(BinaryTree tree, intp_t i_node, + float64_t* pt) except -1 nogil: """Compute the minimum reduced-distance between a point and a node""" - cdef ITYPE_t n_features = tree.data.shape[1] - cdef DTYPE_t d, d_lo, d_hi, rdist=0.0 - cdef ITYPE_t j + cdef intp_t n_features = tree.data.shape[1] + cdef float64_t d, d_lo, d_hi, rdist=0.0 + cdef intp_t j if tree.dist_metric.p == INF: for j in range(n_features): @@ -105,7 +105,7 @@ cdef DTYPE_t min_rdist(BinaryTree tree, ITYPE_t i_node, return rdist -cdef DTYPE_t min_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt) except -1: +cdef float64_t min_dist(BinaryTree tree, intp_t i_node, float64_t* pt) except -1: """Compute the minimum distance between a point and a node""" if tree.dist_metric.p == INF: return min_rdist(tree, i_node, pt) @@ -113,13 +113,13 @@ cdef DTYPE_t min_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt) except -1: return pow(min_rdist(tree, i_node, pt), 1. / tree.dist_metric.p) -cdef DTYPE_t max_rdist(BinaryTree tree, - ITYPE_t i_node, DTYPE_t* pt) except -1: +cdef float64_t max_rdist(BinaryTree tree, + intp_t i_node, float64_t* pt) except -1: """Compute the maximum reduced-distance between a point and a node""" - cdef ITYPE_t n_features = tree.data.shape[1] + cdef intp_t n_features = tree.data.shape[1] - cdef DTYPE_t d_lo, d_hi, rdist=0.0 - cdef ITYPE_t j + cdef float64_t d_lo, d_hi, rdist=0.0 + cdef intp_t j if tree.dist_metric.p == INF: for j in range(n_features): @@ -134,7 +134,7 @@ cdef DTYPE_t max_rdist(BinaryTree tree, return rdist -cdef DTYPE_t max_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt) except -1: +cdef float64_t max_dist(BinaryTree tree, intp_t i_node, float64_t* pt) except -1: """Compute the maximum distance between a point and a node""" if tree.dist_metric.p == INF: return max_rdist(tree, i_node, pt) @@ -142,13 +142,13 @@ cdef DTYPE_t max_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt) except -1: return pow(max_rdist(tree, i_node, pt), 1. / tree.dist_metric.p) -cdef inline int min_max_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt, - DTYPE_t* min_dist, DTYPE_t* max_dist) except -1 nogil: +cdef inline int min_max_dist(BinaryTree tree, intp_t i_node, float64_t* pt, + float64_t* min_dist, float64_t* max_dist) except -1 nogil: """Compute the minimum and maximum distance between a point and a node""" - cdef ITYPE_t n_features = tree.data.shape[1] + cdef intp_t n_features = tree.data.shape[1] - cdef DTYPE_t d, d_lo, d_hi - cdef ITYPE_t j + cdef float64_t d, d_lo, d_hi + cdef intp_t j min_dist[0] = 0.0 max_dist[0] = 0.0 @@ -177,13 +177,13 @@ cdef inline int min_max_dist(BinaryTree tree, ITYPE_t i_node, DTYPE_t* pt, return 0 -cdef inline DTYPE_t min_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, - BinaryTree tree2, ITYPE_t i_node2) except -1: +cdef inline float64_t min_rdist_dual(BinaryTree tree1, intp_t i_node1, + BinaryTree tree2, intp_t i_node2) except -1: """Compute the minimum reduced distance between two nodes""" - cdef ITYPE_t n_features = tree1.data.shape[1] + cdef intp_t n_features = tree1.data.shape[1] - cdef DTYPE_t d, d1, d2, rdist=0.0 - cdef ITYPE_t j + cdef float64_t d, d1, d2, rdist=0.0 + cdef intp_t j if tree1.dist_metric.p == INF: for j in range(n_features): @@ -208,20 +208,20 @@ cdef inline DTYPE_t min_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, return rdist -cdef inline DTYPE_t min_dist_dual(BinaryTree tree1, ITYPE_t i_node1, - BinaryTree tree2, ITYPE_t i_node2) except -1: +cdef inline float64_t min_dist_dual(BinaryTree tree1, intp_t i_node1, + BinaryTree tree2, intp_t i_node2) except -1: """Compute the minimum distance between two nodes""" return tree1.dist_metric._rdist_to_dist(min_rdist_dual(tree1, i_node1, tree2, i_node2)) -cdef inline DTYPE_t max_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, - BinaryTree tree2, ITYPE_t i_node2) except -1: +cdef inline float64_t max_rdist_dual(BinaryTree tree1, intp_t i_node1, + BinaryTree tree2, intp_t i_node2) except -1: """Compute the maximum reduced distance between two nodes""" - cdef ITYPE_t n_features = tree1.data.shape[1] + cdef intp_t n_features = tree1.data.shape[1] - cdef DTYPE_t d1, d2, rdist=0.0 - cdef ITYPE_t j + cdef float64_t d1, d2, rdist=0.0 + cdef intp_t j if tree1.dist_metric.p == INF: for j in range(n_features): @@ -240,8 +240,8 @@ cdef inline DTYPE_t max_rdist_dual(BinaryTree tree1, ITYPE_t i_node1, return rdist -cdef inline DTYPE_t max_dist_dual(BinaryTree tree1, ITYPE_t i_node1, - BinaryTree tree2, ITYPE_t i_node2) except -1: +cdef inline float64_t max_dist_dual(BinaryTree tree1, intp_t i_node1, + BinaryTree tree2, intp_t i_node2) except -1: """Compute the maximum distance between two nodes""" return tree1.dist_metric._rdist_to_dist(max_rdist_dual(tree1, i_node1, tree2, i_node2)) diff --git a/sklearn/neighbors/_kde.py b/sklearn/neighbors/_kde.py index 8aa6e8c8ffc0d..f285b03403b5f 100644 --- a/sklearn/neighbors/_kde.py +++ b/sklearn/neighbors/_kde.py @@ -15,7 +15,7 @@ from ..utils.validation import _check_sample_weight, check_is_fitted from ..utils._param_validation import Interval, StrOptions from ..utils.extmath import row_norms -from ._ball_tree import BallTree, DTYPE +from ._ball_tree import BallTree from ._kd_tree import KDTree @@ -222,11 +222,11 @@ def fit(self, X, y=None, sample_weight=None): else: self.bandwidth_ = self.bandwidth - X = self._validate_data(X, order="C", dtype=DTYPE) + X = self._validate_data(X, order="C", dtype=np.float64) if sample_weight is not None: sample_weight = _check_sample_weight( - sample_weight, X, DTYPE, only_non_negative=True + sample_weight, X, dtype=np.float64, only_non_negative=True ) kwargs = self.metric_params @@ -261,7 +261,7 @@ def score_samples(self, X): # The returned density is normalized to the number of points. # For it to be a probability, we must scale it. For this reason # we'll also scale atol. - X = self._validate_data(X, order="C", dtype=DTYPE, reset=False) + X = self._validate_data(X, order="C", dtype=np.float64, reset=False) if self.tree_.sample_weight is None: N = self.tree_.data.shape[0] else: diff --git a/sklearn/neighbors/_partition_nodes.pxd b/sklearn/neighbors/_partition_nodes.pxd index 94b02002d7a1e..927fde873ee58 100644 --- a/sklearn/neighbors/_partition_nodes.pxd +++ b/sklearn/neighbors/_partition_nodes.pxd @@ -1,9 +1,9 @@ -from ..utils._typedefs cimport DTYPE_t, ITYPE_t +from ..utils._typedefs cimport float64_t, intp_t cdef int partition_node_indices( - DTYPE_t *data, - ITYPE_t *node_indices, - ITYPE_t split_dim, - ITYPE_t split_index, - ITYPE_t n_features, - ITYPE_t n_points) except -1 + float64_t *data, + intp_t *node_indices, + intp_t split_dim, + intp_t split_index, + intp_t n_features, + intp_t n_points) except -1 diff --git a/sklearn/neighbors/_partition_nodes.pyx b/sklearn/neighbors/_partition_nodes.pyx index f2f655a7de275..d293b765ea279 100644 --- a/sklearn/neighbors/_partition_nodes.pyx +++ b/sklearn/neighbors/_partition_nodes.pyx @@ -63,12 +63,12 @@ cdef extern from *: cdef int partition_node_indices( - DTYPE_t *data, - ITYPE_t *node_indices, - ITYPE_t split_dim, - ITYPE_t split_index, - ITYPE_t n_features, - ITYPE_t n_points) except -1: + float64_t *data, + intp_t *node_indices, + intp_t split_dim, + intp_t split_index, + intp_t n_features, + intp_t n_points) except -1: """Partition points in the node into two equal-sized groups. Upon return, the values in node_indices will be rearranged such that diff --git a/sklearn/neighbors/tests/test_neighbors_tree.py b/sklearn/neighbors/tests/test_neighbors_tree.py index 85d578c271faa..d485e799eb5b0 100644 --- a/sklearn/neighbors/tests/test_neighbors_tree.py +++ b/sklearn/neighbors/tests/test_neighbors_tree.py @@ -10,8 +10,6 @@ from sklearn.neighbors._ball_tree import ( BallTree, kernel_norm, - DTYPE, - ITYPE, NeighborsHeap as NeighborsHeapBT, simultaneous_sort as simultaneous_sort_bt, nodeheap_sort as nodeheap_sort_bt, @@ -163,8 +161,8 @@ def test_neighbors_heap(NeighborsHeap, n_pts=5, n_nbrs=10): rng = check_random_state(0) for row in range(n_pts): - d_in = rng.random_sample(2 * n_nbrs).astype(DTYPE, copy=False) - i_in = np.arange(2 * n_nbrs, dtype=ITYPE) + d_in = rng.random_sample(2 * n_nbrs).astype(np.float64, copy=False) + i_in = np.arange(2 * n_nbrs, dtype=np.intp) for d, i in zip(d_in, i_in): heap.push(row, d, i) @@ -181,7 +179,7 @@ def test_neighbors_heap(NeighborsHeap, n_pts=5, n_nbrs=10): @pytest.mark.parametrize("nodeheap_sort", [nodeheap_sort_bt, nodeheap_sort_kdt]) def test_node_heap(nodeheap_sort, n_nodes=50): rng = check_random_state(0) - vals = rng.random_sample(n_nodes).astype(DTYPE, copy=False) + vals = rng.random_sample(n_nodes).astype(np.float64, copy=False) i1 = np.argsort(vals) vals2, i2 = nodeheap_sort(vals) @@ -195,8 +193,8 @@ def test_node_heap(nodeheap_sort, n_nodes=50): ) def test_simultaneous_sort(simultaneous_sort, n_rows=10, n_pts=201): rng = check_random_state(0) - dist = rng.random_sample((n_rows, n_pts)).astype(DTYPE, copy=False) - ind = (np.arange(n_pts) + np.zeros((n_rows, 1))).astype(ITYPE, copy=False) + dist = rng.random_sample((n_rows, n_pts)).astype(np.float64, copy=False) + ind = (np.arange(n_pts) + np.zeros((n_rows, 1))).astype(np.intp, copy=False) dist2 = dist.copy() ind2 = ind.copy() diff --git a/sklearn/utils/_heap.pxd b/sklearn/utils/_heap.pxd index 2f1b9b71d59ce..39de4dc02d315 100644 --- a/sklearn/utils/_heap.pxd +++ b/sklearn/utils/_heap.pxd @@ -2,13 +2,13 @@ from cython cimport floating -from ._typedefs cimport ITYPE_t +from ._typedefs cimport intp_t cdef int heap_push( floating* values, - ITYPE_t* indices, - ITYPE_t size, + intp_t* indices, + intp_t size, floating val, - ITYPE_t val_idx, + intp_t val_idx, ) noexcept nogil diff --git a/sklearn/utils/_heap.pyx b/sklearn/utils/_heap.pyx index 14cb7722ef793..98bc3046a0798 100644 --- a/sklearn/utils/_heap.pyx +++ b/sklearn/utils/_heap.pyx @@ -1,14 +1,14 @@ from cython cimport floating -from ._typedefs cimport ITYPE_t +from ._typedefs cimport intp_t cdef inline int heap_push( floating* values, - ITYPE_t* indices, - ITYPE_t size, + intp_t* indices, + intp_t size, floating val, - ITYPE_t val_idx, + intp_t val_idx, ) noexcept nogil: """Push a tuple (val, val_idx) onto a fixed-size max-heap. @@ -40,7 +40,7 @@ cdef inline int heap_push( """ cdef: - ITYPE_t current_idx, left_child_idx, right_child_idx, swap_idx + intp_t current_idx, left_child_idx, right_child_idx, swap_idx # Check if val should be in heap if val >= values[0]: diff --git a/sklearn/utils/_sorting.pxd b/sklearn/utils/_sorting.pxd index 9a199ef2be182..51f21afd4d3e4 100644 --- a/sklearn/utils/_sorting.pxd +++ b/sklearn/utils/_sorting.pxd @@ -1,9 +1,9 @@ -from ._typedefs cimport DTYPE_t, ITYPE_t +from ._typedefs cimport intp_t from cython cimport floating cdef int simultaneous_sort( floating *dist, - ITYPE_t *idx, - ITYPE_t size, + intp_t *idx, + intp_t size, ) noexcept nogil diff --git a/sklearn/utils/_sorting.pyx b/sklearn/utils/_sorting.pyx index 9a9eaebcf2dd2..13b2d872392b9 100644 --- a/sklearn/utils/_sorting.pyx +++ b/sklearn/utils/_sorting.pyx @@ -2,24 +2,24 @@ from cython cimport floating cdef inline void dual_swap( floating* darr, - ITYPE_t *iarr, - ITYPE_t a, - ITYPE_t b, + intp_t *iarr, + intp_t a, + intp_t b, ) noexcept nogil: """Swap the values at index a and b of both darr and iarr""" cdef floating dtmp = darr[a] darr[a] = darr[b] darr[b] = dtmp - cdef ITYPE_t itmp = iarr[a] + cdef intp_t itmp = iarr[a] iarr[a] = iarr[b] iarr[b] = itmp cdef int simultaneous_sort( floating* values, - ITYPE_t* indices, - ITYPE_t size, + intp_t* indices, + intp_t size, ) noexcept nogil: """ Perform a recursive quicksort on the values array as to sort them ascendingly. @@ -42,7 +42,7 @@ cdef int simultaneous_sort( # an Array of Structures (AoS) instead of the Structure of Arrays (SoA) # currently used. cdef: - ITYPE_t pivot_idx, i, store_idx + intp_t pivot_idx, i, store_idx floating pivot_val # in the small-array case, do things efficiently diff --git a/sklearn/utils/_typedefs.pxd b/sklearn/utils/_typedefs.pxd index 9298fad89a762..7baed97c1ef03 100644 --- a/sklearn/utils/_typedefs.pxd +++ b/sklearn/utils/_typedefs.pxd @@ -20,7 +20,10 @@ cimport numpy as cnp # NOTE: Extend this list as needed when converting more cython extensions. ctypedef unsigned char bool_t ctypedef Py_ssize_t intp_t +ctypedef float float32_t ctypedef double float64_t +ctypedef signed int int32_t +ctypedef signed long long int64_t # Floating point/data type @@ -28,15 +31,10 @@ ctypedef cnp.float64_t DTYPE_t # WARNING: should match DTYPE in typedefs.pyx cdef enum: DTYPECODE = cnp.NPY_FLOAT64 - ITYPECODE = cnp.NPY_INTP - INT32TYPECODE = cnp.NPY_INT32 - INT64TYPECODE = cnp.NPY_INT64 # Index/integer type. # WARNING: ITYPE_t must be a signed integer type or you will have a bad time! ctypedef cnp.intp_t ITYPE_t # WARNING: should match ITYPE in typedefs.pyx -ctypedef cnp.int32_t INT32TYPE_t # WARNING: should match INT32TYPE in typedefs.pyx -ctypedef cnp.int64_t INT64TYPE_t # WARNING: should match INT32TYPE in typedefs.pyx # scipy matrices indices dtype (namely for indptr and indices arrays) # diff --git a/sklearn/utils/_typedefs.pyx b/sklearn/utils/_typedefs.pyx index 49d0e46101b4f..faf9bd386beca 100644 --- a/sklearn/utils/_typedefs.pyx +++ b/sklearn/utils/_typedefs.pyx @@ -1,7 +1,6 @@ #!python import numpy as np -from libc.math cimport sqrt # use a hack to determine the associated numpy data types @@ -11,8 +10,6 @@ from libc.math cimport sqrt #cdef ITYPE_t[:] idummy_view = &idummy #ITYPE = np.asarray(idummy_view).dtype ITYPE = np.intp # WARNING: this should match ITYPE_t in typedefs.pxd -INT32TYPE = np.int32 # WARNING: should match INT32TYPE_t in typedefs.pyx -INT64TYPE = np.int64 # WARNING: this should match INT64TYPE_t in typedefs.pxd #cdef DTYPE_t ddummy #cdef DTYPE_t[:] ddummy_view = &ddummy @@ -21,8 +18,3 @@ DTYPE = np.float64 # WARNING: this should match DTYPE_t in typedefs.pxd # WARNING: this must match SPARSE_INDEX_TYPE_t in typedefs.pxd SPARSE_INDEX_TYPE = np.int32 - -# some handy constants -cdef DTYPE_t INF = np.inf -cdef DTYPE_t PI = np.pi -cdef DTYPE_t ROOT_2PI = sqrt(2 * PI) diff --git a/sklearn/utils/_vector_sentinel.pxd b/sklearn/utils/_vector_sentinel.pxd index b3d9a3ff32613..64de6c18830b5 100644 --- a/sklearn/utils/_vector_sentinel.pxd +++ b/sklearn/utils/_vector_sentinel.pxd @@ -1,12 +1,12 @@ cimport numpy as cnp from libcpp.vector cimport vector -from ..utils._typedefs cimport ITYPE_t, DTYPE_t, INT32TYPE_t, INT64TYPE_t +from ..utils._typedefs cimport intp_t, float64_t, int32_t, int64_t ctypedef fused vector_typed: - vector[DTYPE_t] - vector[ITYPE_t] - vector[INT32TYPE_t] - vector[INT64TYPE_t] + vector[float64_t] + vector[intp_t] + vector[int32_t] + vector[int64_t] cdef cnp.ndarray vector_to_nd_array(vector_typed * vect_ptr) diff --git a/sklearn/utils/_vector_sentinel.pyx b/sklearn/utils/_vector_sentinel.pyx index 45c48de9dac68..eb935714b0baf 100644 --- a/sklearn/utils/_vector_sentinel.pyx +++ b/sklearn/utils/_vector_sentinel.pyx @@ -2,19 +2,17 @@ from cython.operator cimport dereference as deref from cpython.ref cimport Py_INCREF cimport numpy as cnp -from ._typedefs cimport DTYPECODE, ITYPECODE, INT32TYPECODE, INT64TYPECODE - cnp.import_array() cdef StdVectorSentinel _create_sentinel(vector_typed * vect_ptr): - if vector_typed is vector[DTYPE_t]: + if vector_typed is vector[float64_t]: return StdVectorSentinelFloat64.create_for(vect_ptr) - elif vector_typed is vector[INT32TYPE_t]: + elif vector_typed is vector[int32_t]: return StdVectorSentinelInt32.create_for(vect_ptr) - elif vector_typed is vector[INT64TYPE_t]: + elif vector_typed is vector[int64_t]: return StdVectorSentinelInt64.create_for(vect_ptr) - else: + else: # intp_t return StdVectorSentinelIntP.create_for(vect_ptr) @@ -33,10 +31,10 @@ cdef class StdVectorSentinel: cdef class StdVectorSentinelFloat64(StdVectorSentinel): - cdef vector[DTYPE_t] vec + cdef vector[float64_t] vec @staticmethod - cdef StdVectorSentinel create_for(vector[DTYPE_t] * vect_ptr): + cdef StdVectorSentinel create_for(vector[float64_t] * vect_ptr): # This initializes the object directly without calling __init__ # See: https://cython.readthedocs.io/en/latest/src/userguide/extension_types.html#instantiation-from-existing-c-c-pointers # noqa cdef StdVectorSentinelFloat64 sentinel = StdVectorSentinelFloat64.__new__(StdVectorSentinelFloat64) @@ -47,14 +45,14 @@ cdef class StdVectorSentinelFloat64(StdVectorSentinel): return self.vec.data() cdef int get_typenum(self): - return DTYPECODE + return cnp.NPY_FLOAT64 cdef class StdVectorSentinelIntP(StdVectorSentinel): - cdef vector[ITYPE_t] vec + cdef vector[intp_t] vec @staticmethod - cdef StdVectorSentinel create_for(vector[ITYPE_t] * vect_ptr): + cdef StdVectorSentinel create_for(vector[intp_t] * vect_ptr): # This initializes the object directly without calling __init__ # See: https://cython.readthedocs.io/en/latest/src/userguide/extension_types.html#instantiation-from-existing-c-c-pointers # noqa cdef StdVectorSentinelIntP sentinel = StdVectorSentinelIntP.__new__(StdVectorSentinelIntP) @@ -65,14 +63,14 @@ cdef class StdVectorSentinelIntP(StdVectorSentinel): return self.vec.data() cdef int get_typenum(self): - return ITYPECODE + return cnp.NPY_INTP cdef class StdVectorSentinelInt32(StdVectorSentinel): - cdef vector[INT32TYPE_t] vec + cdef vector[int32_t] vec @staticmethod - cdef StdVectorSentinel create_for(vector[INT32TYPE_t] * vect_ptr): + cdef StdVectorSentinel create_for(vector[int32_t] * vect_ptr): # This initializes the object directly without calling __init__ # See: https://cython.readthedocs.io/en/latest/src/userguide/extension_types.html#instantiation-from-existing-c-c-pointers # noqa cdef StdVectorSentinelInt32 sentinel = StdVectorSentinelInt32.__new__(StdVectorSentinelInt32) @@ -83,14 +81,14 @@ cdef class StdVectorSentinelInt32(StdVectorSentinel): return self.vec.data() cdef int get_typenum(self): - return INT32TYPECODE + return cnp.NPY_INT32 cdef class StdVectorSentinelInt64(StdVectorSentinel): - cdef vector[INT64TYPE_t] vec + cdef vector[int64_t] vec @staticmethod - cdef StdVectorSentinel create_for(vector[INT64TYPE_t] * vect_ptr): + cdef StdVectorSentinel create_for(vector[int64_t] * vect_ptr): # This initializes the object directly without calling __init__ # See: https://cython.readthedocs.io/en/latest/src/userguide/extension_types.html#instantiation-from-existing-c-c-pointers # noqa cdef StdVectorSentinelInt64 sentinel = StdVectorSentinelInt64.__new__(StdVectorSentinelInt64) @@ -101,7 +99,7 @@ cdef class StdVectorSentinelInt64(StdVectorSentinel): return self.vec.data() cdef int get_typenum(self): - return INT64TYPECODE + return cnp.NPY_INT64 cdef cnp.ndarray vector_to_nd_array(vector_typed * vect_ptr): From 5b21afdabc08a59925bea1795ce334b5bb79300b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Mon, 20 Mar 2023 23:12:35 +0100 Subject: [PATCH 072/230] TST Speed-up common tests of DictionaryLearning (#25892) --- sklearn/utils/estimator_checks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/utils/estimator_checks.py b/sklearn/utils/estimator_checks.py index 8a220966b3b86..ed7f325df5275 100644 --- a/sklearn/utils/estimator_checks.py +++ b/sklearn/utils/estimator_checks.py @@ -676,7 +676,7 @@ def _set_checking_parameters(estimator): estimator.set_params(max_iter=500) # DictionaryLearning if name == "DictionaryLearning": - estimator.set_params(max_iter=200, transform_algorithm="lasso_lars") + estimator.set_params(max_iter=20, transform_algorithm="lasso_lars") # MiniBatchNMF if estimator.__class__.__name__ == "MiniBatchNMF": estimator.set_params(max_iter=20, fresh_restarts=True) From 4f8492bae3b6b33fe4df2b310e4f994af39b4f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Mon, 20 Mar 2023 23:49:00 +0100 Subject: [PATCH 073/230] TST Speed-up test_dbscan_optics_parity (#25893) --- sklearn/cluster/tests/test_optics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/cluster/tests/test_optics.py b/sklearn/cluster/tests/test_optics.py index 38c92f855b746..0acf818912c0f 100644 --- a/sklearn/cluster/tests/test_optics.py +++ b/sklearn/cluster/tests/test_optics.py @@ -300,7 +300,7 @@ def test_dbscan_optics_parity(eps, min_samples, metric, is_sparse, global_dtype) centers = [[1, 1], [-1, -1], [1, -1]] X, labels_true = make_blobs( - n_samples=750, centers=centers, cluster_std=0.4, random_state=0 + n_samples=150, centers=centers, cluster_std=0.4, random_state=0 ) X = sparse.csr_matrix(X) if is_sparse else X From b84c1b65986d49df0866ecc49a69063b302cc7a1 Mon Sep 17 00:00:00 2001 From: Marc Torrellas Socastro Date: Tue, 21 Mar 2023 12:16:01 +0200 Subject: [PATCH 074/230] ENH add np.nan option for zero_division in precision/recall/f-score (#25531) Co-authored-by: Guillaume Lemaitre --- doc/whats_new/v1.3.rst | 16 +- sklearn/metrics/_classification.py | 168 ++++++++++++------- sklearn/metrics/tests/test_classification.py | 127 ++++++++++---- sklearn/utils/extmath.py | 44 +++++ 4 files changed, 263 insertions(+), 92 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 477ce9ac9063a..dac97146be221 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -163,7 +163,7 @@ Changelog - |API| The `sample_weight` parameter in `predict` for :meth:`cluster.KMeans.predict` and :meth:`cluster.MiniBatchKMeans.predict` - is now deprecated and will be removed in v1.5. + is now deprecated and will be removed in v1.5. :pr:`25251` by :user:`Gleb Levitski `. - |Enhancement| The `sample_weight` parameter now will be used in centroids @@ -279,9 +279,23 @@ Changelog :user:`Guillaume Lemaitre `, :user:`Omar Salman ` and :user:`Jérémie du Boisberranger `. +- |Feature| Adds `zero_division=np.nan` to multiple classification metrics: + :func:`precision_score`, :func:`recall_score`, :func:`f1_score`, + :func:`fbeta_score`, :func:`precision_recall_fscore_support`, + :func:`classification_report`. When `zero_division=np.nan` and there is a + zero division, the metric is undefined and is excluded from averaging. When not used + for averages, the value returned is `np.nan`. + :pr:`25531` by :user:`Marc Torrellas Socastro `. + - |Fix| :func:`metric.manhattan_distances` now supports readonly sparse datasets. :pr:`25432` by :user:`Julien Jerphanion `. +- |Fix| Fixed :func:`classification_report` so that empty input will return + `np.nan`. Previously, "macro avg" and `weighted avg` would return + e.g. `f1-score=np.nan` and `f1-score=0.0`, being inconsistent. Now, they + both return `np.nan`. + :pr:`25531` by :user:`Marc Torrellas Socastro `. + - |Enhancement| :class:`metrics.silhouette_samples` nows accepts a sparse matrix of pairwise distances between samples, or a feature array. :pr:`18723` by :user:`Sahil Gupta ` and diff --git a/sklearn/metrics/_classification.py b/sklearn/metrics/_classification.py index 50425bb082d39..67c34e92cf8f3 100644 --- a/sklearn/metrics/_classification.py +++ b/sklearn/metrics/_classification.py @@ -37,6 +37,7 @@ from ..utils import check_array from ..utils import check_consistent_length from ..utils import column_or_1d +from ..utils.extmath import _nanaverage from ..utils.multiclass import unique_labels from ..utils.multiclass import type_of_target from ..utils.validation import _num_samples @@ -49,12 +50,11 @@ def _check_zero_division(zero_division): if isinstance(zero_division, str) and zero_division == "warn": - return + return np.float64(0.0) elif isinstance(zero_division, (int, float)) and zero_division in [0, 1]: - return - raise ValueError( - 'Got zero_division={0}. Must be one of ["warn", 0, 1]'.format(zero_division) - ) + return np.float64(zero_division) + else: # np.isnan(zero_division) + return np.nan def _check_targets(y_true, y_pred): @@ -1075,7 +1075,7 @@ def zero_one_loss(y_true, y_pred, *, normalize=True, sample_weight=None): ], "sample_weight": ["array-like", None], "zero_division": [ - Options(Integral, {0, 1}), + Options(Real, {0.0, 1.0, np.nan}), StrOptions({"warn"}), ], } @@ -1159,10 +1159,16 @@ def f1_score( sample_weight : array-like of shape (n_samples,), default=None Sample weights. - zero_division : "warn", 0 or 1, default="warn" + zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" Sets the value to return when there is a zero division, i.e. when all - predictions and labels are negative. If set to "warn", this acts as 0, - but warnings are also raised. + predictions and labels are negative. + + Notes: + - If set to "warn", this acts like 0, but a warning is also raised. + - If set to `np.nan`, such values will be excluded from the average. + + .. versionadded:: 1.3 + `np.nan` option was added. Returns ------- @@ -1185,7 +1191,8 @@ def f1_score( When ``true positive + false negative == 0``, recall is undefined. In such cases, by default the metric will be set to 0, as will f-score, and ``UndefinedMetricWarning`` will be raised. This behavior can be - modified with ``zero_division``. + modified with ``zero_division``. Note that if `zero_division` is np.nan, + scores being `np.nan` will be ignored for averaging. References ---------- @@ -1194,6 +1201,7 @@ def f1_score( Examples -------- + >>> import numpy as np >>> from sklearn.metrics import f1_score >>> y_true = [0, 1, 2, 0, 1, 2] >>> y_pred = [0, 2, 1, 0, 0, 1] @@ -1205,10 +1213,17 @@ def f1_score( 0.26... >>> f1_score(y_true, y_pred, average=None) array([0.8, 0. , 0. ]) - >>> y_true = [0, 0, 0, 0, 0, 0] - >>> y_pred = [0, 0, 0, 0, 0, 0] - >>> f1_score(y_true, y_pred, zero_division=1) + + >>> # binary classification + >>> y_true_empty = [0, 0, 0, 0, 0, 0] + >>> y_pred_empty = [0, 0, 0, 0, 0, 0] + >>> f1_score(y_true_empty, y_pred_empty) + 0.0... + >>> f1_score(y_true_empty, y_pred_empty, zero_division=1.0) 1.0... + >>> f1_score(y_true_empty, y_pred_empty, zero_division=np.nan) + nan... + >>> # multilabel classification >>> y_true = [[0, 0, 0], [1, 1, 1], [0, 1, 1]] >>> y_pred = [[0, 0, 0], [1, 1, 1], [1, 1, 0]] @@ -1240,7 +1255,7 @@ def f1_score( ], "sample_weight": ["array-like", None], "zero_division": [ - Options(Real, {0, 1}), + Options(Real, {0.0, 1.0, np.nan}), StrOptions({"warn"}), ], } @@ -1325,10 +1340,16 @@ def fbeta_score( sample_weight : array-like of shape (n_samples,), default=None Sample weights. - zero_division : "warn", 0 or 1, default="warn" + zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" Sets the value to return when there is a zero division, i.e. when all - predictions and labels are negative. If set to "warn", this acts as 0, - but warnings are also raised. + predictions and labels are negative. + + Notes: + - If set to "warn", this acts like 0, but a warning is also raised. + - If set to `np.nan`, such values will be excluded from the average. + + .. versionadded:: 1.3 + `np.nan` option was added. Returns ------- @@ -1361,6 +1382,7 @@ def fbeta_score( Examples -------- + >>> import numpy as np >>> from sklearn.metrics import fbeta_score >>> y_true = [0, 1, 2, 0, 1, 2] >>> y_pred = [0, 2, 1, 0, 0, 1] @@ -1372,6 +1394,10 @@ def fbeta_score( 0.23... >>> fbeta_score(y_true, y_pred, average=None, beta=0.5) array([0.71..., 0. , 0. ]) + >>> y_pred_empty = [0, 0, 0, 0, 0, 0] + >>> fbeta_score(y_true, y_pred_empty, + ... average="macro", zero_division=np.nan, beta=0.5) + 0.38... """ _, _, f, _ = precision_recall_fscore_support( @@ -1394,7 +1420,7 @@ def _prf_divide( """Performs division and handles divide-by-zero. On zero-division, sets the corresponding result elements equal to - 0 or 1 (according to ``zero_division``). Plus, if + 0, 1 or np.nan (according to ``zero_division``). Plus, if ``zero_division != "warn"`` raises a warning. The metric, modifier and average arguments are used only for determining @@ -1408,11 +1434,12 @@ def _prf_divide( if not np.any(mask): return result - # if ``zero_division=1``, set those with denominator == 0 equal to 1 - result[mask] = 0.0 if zero_division in ["warn", 0] else 1.0 + # set those with 0 denominator to `zero_division`, and 0 when "warn" + zero_division_value = _check_zero_division(zero_division) + result[mask] = zero_division_value - # the user will be removing warnings if zero_division is set to something - # different than its default value. If we are computing only f-score + # we assume the user will be removing warnings if zero_division is set + # to something different than "warn". If we are computing only f-score # the warning will be raised only if precision and recall are ill-defined if zero_division != "warn" or metric not in warn_for: return result @@ -1507,7 +1534,7 @@ def _check_set_wise_labels(y_true, y_pred, average, labels, pos_label): "warn_for": [list, tuple, set], "sample_weight": ["array-like", None], "zero_division": [ - Options(Real, {0, 1}), + Options(Real, {0.0, 1.0, np.nan}), StrOptions({"warn"}), ], } @@ -1607,13 +1634,18 @@ def precision_recall_fscore_support( sample_weight : array-like of shape (n_samples,), default=None Sample weights. - zero_division : "warn", 0 or 1, default="warn" + zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" Sets the value to return when there is a zero division: - recall: when there are no positive labels - precision: when there are no positive predictions - f-score: both - If set to "warn", this acts as 0, but warnings are also raised. + Notes: + - If set to "warn", this acts like 0, but a warning is also raised. + - If set to `np.nan`, such values will be excluded from the average. + + .. versionadded:: 1.3 + `np.nan` option was added. Returns ------- @@ -1676,7 +1708,7 @@ def precision_recall_fscore_support( array([0., 0., 1.]), array([0. , 0. , 0.8]), array([2, 2, 2])) """ - _check_zero_division(zero_division) + zero_division_value = _check_zero_division(zero_division) labels = _check_set_wise_labels(y_true, y_pred, average, labels, pos_label) # Calculate tp_sum, pred_sum, true_sum ### @@ -1715,37 +1747,24 @@ def precision_recall_fscore_support( if (pred_sum[true_sum == 0] == 0).any(): _warn_prf(average, "true nor predicted", "F-score is", len(true_sum)) - # if tp == 0 F will be 1 only if all predictions are zero, all labels are - # zero, and zero_division=1. In all other case, 0 if np.isposinf(beta): f_score = recall + elif beta == 0: + f_score = precision else: + # The score is defined as: + # score = (1 + beta**2) * precision * recall / (beta**2 * precision + recall) + # We set to `zero_division_value` if the denominator is 0 **or** if **both** + # precision and recall are ill-defined. denom = beta2 * precision + recall - - denom[denom == 0.0] = 1 # avoid division by 0 + mask = np.isclose(denom, 0) | np.isclose(pred_sum + true_sum, 0) + denom[mask] = 1 # avoid division by 0 f_score = (1 + beta2) * precision * recall / denom + f_score[mask] = zero_division_value # Average the results if average == "weighted": weights = true_sum - if weights.sum() == 0: - zero_division_value = np.float64(1.0) - if zero_division in ["warn", 0]: - zero_division_value = np.float64(0.0) - # precision is zero_division if there are no positive predictions - # recall is zero_division if there are no positive labels - # fscore is zero_division if all labels AND predictions are - # negative - if pred_sum.sum() == 0: - return ( - zero_division_value, - zero_division_value, - zero_division_value, - None, - ) - else: - return (np.float64(0.0), zero_division_value, np.float64(0.0), None) - elif average == "samples": weights = sample_weight else: @@ -1753,9 +1772,9 @@ def precision_recall_fscore_support( if average is not None: assert average != "binary" or len(precision) == 1 - precision = np.average(precision, weights=weights) - recall = np.average(recall, weights=weights) - f_score = np.average(f_score, weights=weights) + precision = _nanaverage(precision, weights=weights) + recall = _nanaverage(recall, weights=weights) + f_score = _nanaverage(f_score, weights=weights) true_sum = None # return no support return precision, recall, f_score, true_sum @@ -1950,7 +1969,7 @@ class after being classified as negative. This is the case when the ], "sample_weight": ["array-like", None], "zero_division": [ - Options(Real, {0, 1}), + Options(Real, {0.0, 1.0, np.nan}), StrOptions({"warn"}), ], } @@ -2030,9 +2049,15 @@ def precision_score( sample_weight : array-like of shape (n_samples,), default=None Sample weights. - zero_division : "warn", 0 or 1, default="warn" - Sets the value to return when there is a zero division. If set to - "warn", this acts as 0, but warnings are also raised. + zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" + Sets the value to return when there is a zero division. + + Notes: + - If set to "warn", this acts like 0, but a warning is also raised. + - If set to `np.nan`, such values will be excluded from the average. + + .. versionadded:: 1.3 + `np.nan` option was added. Returns ------- @@ -2062,6 +2087,7 @@ def precision_score( Examples -------- + >>> import numpy as np >>> from sklearn.metrics import precision_score >>> y_true = [0, 1, 2, 0, 1, 2] >>> y_pred = [0, 2, 1, 0, 0, 1] @@ -2078,6 +2104,9 @@ def precision_score( array([0.33..., 0. , 0. ]) >>> precision_score(y_true, y_pred, average=None, zero_division=1) array([0.33..., 1. , 1. ]) + >>> precision_score(y_true, y_pred, average=None, zero_division=np.nan) + array([0.33..., nan, nan]) + >>> # multilabel classification >>> y_true = [[0, 0, 0], [1, 1, 1], [0, 1, 1]] >>> y_pred = [[0, 0, 0], [1, 1, 1], [1, 1, 0]] @@ -2109,7 +2138,7 @@ def precision_score( ], "sample_weight": ["array-like", None], "zero_division": [ - Options(Real, {0, 1}), + Options(Real, {0.0, 1.0, np.nan}), StrOptions({"warn"}), ], } @@ -2189,9 +2218,15 @@ def recall_score( sample_weight : array-like of shape (n_samples,), default=None Sample weights. - zero_division : "warn", 0 or 1, default="warn" - Sets the value to return when there is a zero division. If set to - "warn", this acts as 0, but warnings are also raised. + zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" + Sets the value to return when there is a zero division. + + Notes: + - If set to "warn", this acts like 0, but a warning is also raised. + - If set to `np.nan`, such values will be excluded from the average. + + .. versionadded:: 1.3 + `np.nan` option was added. Returns ------- @@ -2223,6 +2258,7 @@ def recall_score( Examples -------- + >>> import numpy as np >>> from sklearn.metrics import recall_score >>> y_true = [0, 1, 2, 0, 1, 2] >>> y_pred = [0, 2, 1, 0, 0, 1] @@ -2239,6 +2275,9 @@ def recall_score( array([0.5, 0. , 0. ]) >>> recall_score(y_true, y_pred, average=None, zero_division=1) array([0.5, 1. , 1. ]) + >>> recall_score(y_true, y_pred, average=None, zero_division=np.nan) + array([0.5, nan, nan]) + >>> # multilabel classification >>> y_true = [[0, 0, 0], [1, 1, 1], [0, 1, 1]] >>> y_pred = [[0, 0, 0], [1, 1, 1], [1, 1, 0]] @@ -2360,7 +2399,7 @@ def balanced_accuracy_score(y_true, y_pred, *, sample_weight=None, adjusted=Fals "digits": [Interval(Integral, 0, None, closed="left")], "output_dict": ["boolean"], "zero_division": [ - Options(Real, {0, 1}), + Options(Real, {0.0, 1.0, np.nan}), StrOptions({"warn"}), ], } @@ -2407,10 +2446,13 @@ def classification_report( .. versionadded:: 0.20 - zero_division : "warn", 0 or 1, default="warn" + zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" Sets the value to return when there is a zero division. If set to "warn", this acts as 0, but warnings are also raised. + .. versionadded:: 1.3 + `np.nan` option was added. + Returns ------- report : str or dict @@ -2530,7 +2572,7 @@ class 2 1.00 0.67 0.80 3 if output_dict: report_dict = {label[0]: label[1:] for label in rows} for label, scores in report_dict.items(): - report_dict[label] = dict(zip(headers, [i.item() for i in scores])) + report_dict[label] = dict(zip(headers, [float(i) for i in scores])) else: longest_last_line_heading = "weighted avg" name_width = max(len(cn) for cn in target_names) @@ -2562,7 +2604,7 @@ class 2 1.00 0.67 0.80 3 avg = [avg_p, avg_r, avg_f1, np.sum(s)] if output_dict: - report_dict[line_heading] = dict(zip(headers, [i.item() for i in avg])) + report_dict[line_heading] = dict(zip(headers, [float(i) for i in avg])) else: if line_heading == "accuracy": row_fmt_accuracy = ( diff --git a/sklearn/metrics/tests/test_classification.py b/sklearn/metrics/tests/test_classification.py index fcb0e447bb8ba..74a85448a6b11 100644 --- a/sklearn/metrics/tests/test_classification.py +++ b/sklearn/metrics/tests/test_classification.py @@ -47,6 +47,7 @@ from sklearn.metrics._classification import _check_targets from sklearn.exceptions import UndefinedMetricWarning +from sklearn.utils.extmath import _nanaverage from scipy.spatial.distance import hamming as sp_hamming @@ -178,9 +179,9 @@ def test_classification_report_output_dict_empty_input(): "support": 0, }, "weighted avg": { - "f1-score": 0.0, - "precision": 0.0, - "recall": 0.0, + "f1-score": np.nan, + "precision": np.nan, + "recall": np.nan, "support": 0, }, } @@ -197,7 +198,7 @@ def test_classification_report_output_dict_empty_input(): assert_almost_equal(expected_report[key][metric], report[key][metric]) -@pytest.mark.parametrize("zero_division", ["warn", 0, 1]) +@pytest.mark.parametrize("zero_division", ["warn", 0, 1, np.nan]) def test_classification_report_zero_division_warning(zero_division): y_true, y_pred = ["a", "b", "c"], ["a", "b", "d"] with warnings.catch_warnings(record=True) as record: @@ -711,6 +712,50 @@ def test_matthews_corrcoef_nan(): assert matthews_corrcoef([0, 0], [0, 1]) == 0.0 +@pytest.mark.parametrize("zero_division", [0, 1, np.nan]) +@pytest.mark.parametrize("y_true, y_pred", [([0], [0]), ([], [])]) +@pytest.mark.parametrize( + "metric", + [ + f1_score, + partial(fbeta_score, beta=1), + precision_score, + recall_score, + ], +) +def test_zero_division_nan_no_warning(metric, y_true, y_pred, zero_division): + """Check the behaviour of `zero_division` when setting to 0, 1 or np.nan. + No warnings should be raised. + """ + with warnings.catch_warnings(): + warnings.simplefilter("error") + result = metric(y_true, y_pred, zero_division=zero_division) + + if np.isnan(zero_division): + assert np.isnan(result) + else: + assert result == zero_division + + +@pytest.mark.parametrize("y_true, y_pred", [([0], [0]), ([], [])]) +@pytest.mark.parametrize( + "metric", + [ + f1_score, + partial(fbeta_score, beta=1), + precision_score, + recall_score, + ], +) +def test_zero_division_nan_warning(metric, y_true, y_pred): + """Check the behaviour of `zero_division` when setting to "warn". + A `UndefinedMetricWarning` should be raised. + """ + with pytest.warns(UndefinedMetricWarning): + result = metric(y_true, y_pred, zero_division="warn") + assert result == 0.0 + + def test_matthews_corrcoef_against_numpy_corrcoef(): rng = np.random.RandomState(0) y_true = rng.randint(0, 2, size=20) @@ -1678,36 +1723,55 @@ def test_precision_recall_f1_score_multilabel_2(): @ignore_warnings -@pytest.mark.parametrize("zero_division", ["warn", 0, 1]) -def test_precision_recall_f1_score_with_an_empty_prediction(zero_division): +@pytest.mark.parametrize( + "zero_division, zero_division_expected", + [("warn", 0), (0, 0), (1, 1), (np.nan, np.nan)], +) +def test_precision_recall_f1_score_with_an_empty_prediction( + zero_division, zero_division_expected +): y_true = np.array([[0, 1, 0, 0], [1, 0, 0, 0], [0, 1, 1, 0]]) y_pred = np.array([[0, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 0]]) # true_pos = [ 0. 1. 1. 0.] # false_pos = [ 0. 0. 0. 1.] # false_neg = [ 1. 1. 0. 0.] - zero_division = 1.0 if zero_division == 1.0 else 0.0 + p, r, f, s = precision_recall_fscore_support( y_true, y_pred, average=None, zero_division=zero_division ) - assert_array_almost_equal(p, [zero_division, 1.0, 1.0, 0.0], 2) - assert_array_almost_equal(r, [0.0, 0.5, 1.0, zero_division], 2) - assert_array_almost_equal(f, [0.0, 1 / 1.5, 1, 0.0], 2) + + assert_array_almost_equal(p, [zero_division_expected, 1.0, 1.0, 0.0], 2) + assert_array_almost_equal(r, [0.0, 0.5, 1.0, zero_division_expected], 2) + expected_f = 0 if not np.isnan(zero_division_expected) else np.nan + assert_array_almost_equal(f, [expected_f, 1 / 1.5, 1, expected_f], 2) assert_array_almost_equal(s, [1, 2, 1, 0], 2) f2 = fbeta_score(y_true, y_pred, beta=2, average=None, zero_division=zero_division) support = s - assert_array_almost_equal(f2, [0, 0.55, 1, 0], 2) + assert_array_almost_equal(f2, [expected_f, 0.55, 1, expected_f], 2) p, r, f, s = precision_recall_fscore_support( y_true, y_pred, average="macro", zero_division=zero_division ) - assert_almost_equal(p, (2 + zero_division) / 4) - assert_almost_equal(r, (1.5 + zero_division) / 4) - assert_almost_equal(f, 2.5 / (4 * 1.5)) + + value_to_sum = 0 if np.isnan(zero_division_expected) else zero_division_expected + values_to_average = 3 + (not np.isnan(zero_division_expected)) + + assert_almost_equal(p, (2 + value_to_sum) / values_to_average) + assert_almost_equal(r, (1.5 + value_to_sum) / values_to_average) + expected_f = (2 / 3 + 1) / (4 if not np.isnan(zero_division_expected) else 2) + assert_almost_equal(f, expected_f) assert s is None assert_almost_equal( - fbeta_score(y_true, y_pred, beta=2, average="macro"), np.mean(f2) + fbeta_score( + y_true, + y_pred, + beta=2, + average="macro", + zero_division=zero_division, + ), + _nanaverage(f2, weights=None), ) p, r, f, s = precision_recall_fscore_support( @@ -1727,15 +1791,16 @@ def test_precision_recall_f1_score_with_an_empty_prediction(zero_division): p, r, f, s = precision_recall_fscore_support( y_true, y_pred, average="weighted", zero_division=zero_division ) - assert_almost_equal(p, 3 / 4 if zero_division == 0 else 1.0) + assert_almost_equal(p, 3 / 4 if zero_division_expected == 0 else 1.0) assert_almost_equal(r, 0.5) - assert_almost_equal(f, (2 / 1.5 + 1) / 4) + values_to_average = 4 if not np.isnan(zero_division_expected) else 3 + assert_almost_equal(f, (2 * 2 / 3 + 1) / values_to_average) assert s is None assert_almost_equal( fbeta_score( y_true, y_pred, beta=2, average="weighted", zero_division=zero_division ), - np.average(f2, weights=support), + _nanaverage(f2, weights=support), ) p, r, f, s = precision_recall_fscore_support(y_true, y_pred, average="samples") @@ -1746,18 +1811,19 @@ def test_precision_recall_f1_score_with_an_empty_prediction(zero_division): assert_almost_equal(r, 1 / 3) assert_almost_equal(f, 1 / 3) assert s is None + expected_result = {1: 0.666, np.nan: 1.0} assert_almost_equal( fbeta_score( y_true, y_pred, beta=2, average="samples", zero_division=zero_division ), - 0.333, + expected_result.get(zero_division, 0.333), 2, ) @pytest.mark.parametrize("beta", [1]) @pytest.mark.parametrize("average", ["macro", "micro", "weighted", "samples"]) -@pytest.mark.parametrize("zero_division", [0, 1]) +@pytest.mark.parametrize("zero_division", [0, 1, np.nan]) def test_precision_recall_f1_no_labels(beta, average, zero_division): y_true = np.zeros((20, 3)) y_pred = np.zeros_like(y_true) @@ -1778,12 +1844,18 @@ def test_precision_recall_f1_no_labels(beta, average, zero_division): average=average, zero_division=zero_division, ) + assert s is None + + # if zero_division = nan, check that all metrics are nan and exit + if np.isnan(zero_division): + for metric in [p, r, f, fbeta]: + assert np.isnan(metric) + return zero_division = float(zero_division) assert_almost_equal(p, zero_division) assert_almost_equal(r, zero_division) assert_almost_equal(f, zero_division) - assert s is None assert_almost_equal(fbeta, float(zero_division)) @@ -1808,7 +1880,7 @@ def test_precision_recall_f1_no_labels_check_warnings(average): assert_almost_equal(fbeta, 0) -@pytest.mark.parametrize("zero_division", [0, 1]) +@pytest.mark.parametrize("zero_division", [0, 1, np.nan]) def test_precision_recall_f1_no_labels_average_none(zero_division): y_true = np.zeros((20, 3)) y_pred = np.zeros_like(y_true) @@ -1832,8 +1904,7 @@ def test_precision_recall_f1_no_labels_average_none(zero_division): fbeta = assert_no_warnings( fbeta_score, y_true, y_pred, beta=1.0, average=None, zero_division=zero_division ) - - zero_division = float(zero_division) + zero_division = np.float64(zero_division) assert_array_almost_equal(p, [zero_division, zero_division, zero_division], 2) assert_array_almost_equal(r, [zero_division, zero_division, zero_division], 2) assert_array_almost_equal(f, [zero_division, zero_division, zero_division], 2) @@ -1968,7 +2039,7 @@ def test_prf_warnings(): assert str(record.pop().message) == msg -@pytest.mark.parametrize("zero_division", [0, 1]) +@pytest.mark.parametrize("zero_division", [0, 1, np.nan]) def test_prf_no_warnings_if_zero_division_set(zero_division): # average of per-label scores f = precision_recall_fscore_support @@ -2032,7 +2103,7 @@ def test_prf_no_warnings_if_zero_division_set(zero_division): assert len(record) == 0 -@pytest.mark.parametrize("zero_division", ["warn", 0, 1]) +@pytest.mark.parametrize("zero_division", ["warn", 0, 1, np.nan]) def test_recall_warnings(zero_division): assert_no_warnings( recall_score, @@ -2071,7 +2142,7 @@ def test_recall_warnings(zero_division): ) -@pytest.mark.parametrize("zero_division", ["warn", 0, 1]) +@pytest.mark.parametrize("zero_division", ["warn", 0, 1, np.nan]) def test_precision_warnings(zero_division): with warnings.catch_warnings(record=True) as record: warnings.simplefilter("always") @@ -2111,7 +2182,7 @@ def test_precision_warnings(zero_division): ) -@pytest.mark.parametrize("zero_division", ["warn", 0, 1]) +@pytest.mark.parametrize("zero_division", ["warn", 0, 1, np.nan]) def test_fscore_warnings(zero_division): with warnings.catch_warnings(record=True) as record: warnings.simplefilter("always") diff --git a/sklearn/utils/extmath.py b/sklearn/utils/extmath.py index 02e65704274c1..49908fdf1083d 100644 --- a/sklearn/utils/extmath.py +++ b/sklearn/utils/extmath.py @@ -1148,3 +1148,47 @@ def stable_cumsum(arr, axis=None, rtol=1e-05, atol=1e-08): RuntimeWarning, ) return out + + +def _nanaverage(a, weights=None): + """Compute the weighted average, ignoring NaNs. + + Parameters + ---------- + a : ndarray + Array containing data to be averaged. + weights : array-like, default=None + An array of weights associated with the values in a. Each value in a + contributes to the average according to its associated weight. The + weights array can either be 1-D of the same shape as a. If `weights=None`, + then all data in a are assumed to have a weight equal to one. + + Returns + ------- + weighted_average : float + The weighted average. + + Notes + ----- + This wrapper to combine :func:`numpy.average` and :func:`numpy.nanmean`, so + that :func:`np.nan` values are ignored from the average and weights can + be passed. Note that when possible, we delegate to the prime methods. + """ + + if len(a) == 0: + return np.nan + + mask = np.isnan(a) + if mask.all(): + return np.nan + + if weights is None: + return np.nanmean(a) + + weights = np.array(weights, copy=False) + a, weights = a[~mask], weights[~mask] + try: + return np.average(a, weights=weights) + except ZeroDivisionError: + # this is when all weights are zero, then ignore them + return np.average(a) From 0dab4ed7e2525ab1d068f5d693a2a8e00fba8568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Tue, 21 Mar 2023 12:57:19 +0100 Subject: [PATCH 075/230] MAINT Parameters validation for datasets.make_low_rank_matrix (#25901) --- sklearn/datasets/_samples_generator.py | 9 +++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 10 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index a3495b358354f..0577d7917c726 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1198,6 +1198,15 @@ def make_friedman3(n_samples=100, *, noise=0.0, random_state=None): return X, y +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "n_features": [Interval(Integral, 1, None, closed="left")], + "effective_rank": [Interval(Integral, 1, None, closed="left")], + "tail_strength": [Interval(Real, 0, 1, closed="both")], + "random_state": ["random_state"], + } +) def make_low_rank_matrix( n_samples=100, n_features=100, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index cf830c79ad0f7..a32098403f1fe 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -132,6 +132,7 @@ def _check_function_param_validation( "sklearn.datasets.make_circles", "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", + "sklearn.datasets.make_low_rank_matrix", "sklearn.datasets.make_sparse_coded_signal", "sklearn.decomposition.sparse_encode", "sklearn.feature_extraction.grid_to_graph", From 04ec4783bcb6291ba43fa5c430a1d85b68bd93f4 Mon Sep 17 00:00:00 2001 From: zeeshan lone <56621467+still-learning-ev@users.noreply.github.com> Date: Tue, 21 Mar 2023 18:34:12 +0530 Subject: [PATCH 076/230] MAINT Parameter validation for metrics.cluster.adjusted_mutual_info_score (#25898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/metrics/cluster/_supervised.py | 16 +++++++++++----- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sklearn/metrics/cluster/_supervised.py b/sklearn/metrics/cluster/_supervised.py index 1cd7f6c5ce80e..d05ccec33beb6 100644 --- a/sklearn/metrics/cluster/_supervised.py +++ b/sklearn/metrics/cluster/_supervised.py @@ -27,7 +27,7 @@ from ...utils.multiclass import type_of_target from ...utils.validation import check_array, check_consistent_length from ...utils._param_validation import validate_params -from ...utils._param_validation import Interval +from ...utils._param_validation import Interval, StrOptions def check_clusterings(labels_true, labels_pred): @@ -847,6 +847,13 @@ def mutual_info_score(labels_true, labels_pred, *, contingency=None): return np.clip(mi.sum(), 0.0, None) +@validate_params( + { + "labels_true": ["array-like"], + "labels_pred": ["array-like"], + "average_method": [StrOptions({"arithmetic", "max", "min", "geometric"})], + } +) def adjusted_mutual_info_score( labels_true, labels_pred, *, average_method="arithmetic" ): @@ -876,7 +883,7 @@ def adjusted_mutual_info_score( Parameters ---------- - labels_true : int array, shape = [n_samples] + labels_true : int array-like of shape (n_samples,) A clustering of the data into disjoint subsets, called :math:`U` in the above formula. @@ -884,9 +891,8 @@ def adjusted_mutual_info_score( A clustering of the data into disjoint subsets, called :math:`V` in the above formula. - average_method : str, default='arithmetic' - How to compute the normalizer in the denominator. Possible options - are 'min', 'geometric', 'arithmetic', and 'max'. + average_method : {'min', 'geometric', 'arithmetic', 'max'}, default='arithmetic' + How to compute the normalizer in the denominator. .. versionadded:: 0.20 diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index a32098403f1fe..e14b9f0b67205 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -153,6 +153,7 @@ def _check_function_param_validation( "sklearn.metrics.brier_score_loss", "sklearn.metrics.class_likelihood_ratios", "sklearn.metrics.classification_report", + "sklearn.metrics.cluster.adjusted_mutual_info_score", "sklearn.metrics.cluster.contingency_matrix", "sklearn.metrics.cohen_kappa_score", "sklearn.metrics.confusion_matrix", From a502545707f45b7608003a89045c6f89166e8e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Tue, 21 Mar 2023 14:05:47 +0100 Subject: [PATCH 077/230] TST Speed-up test_partial_dependence.test_output_shape (#25895) Co-authored-by: Thomas J. Fan --- sklearn/inspection/tests/test_partial_dependence.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sklearn/inspection/tests/test_partial_dependence.py b/sklearn/inspection/tests/test_partial_dependence.py index 37a2249857981..a42f80da301d1 100644 --- a/sklearn/inspection/tests/test_partial_dependence.py +++ b/sklearn/inspection/tests/test_partial_dependence.py @@ -93,6 +93,8 @@ def test_output_shape(Estimator, method, data, grid_resolution, features, kind): # - multi-task regressors est = Estimator() + if hasattr(est, "n_estimators"): + est.set_params(n_estimators=2) # speed-up computations # n_target corresponds to the number of classes (1 for binary classif) or # the number of tasks / outputs in multi task settings. It's equal to 1 for From 0a89b166edc73df93a22cad9063b96842c0907c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Tue, 21 Mar 2023 15:01:33 +0100 Subject: [PATCH 078/230] MAINT Parameters validation for datasets.make_regression (#25899) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/datasets/_samples_generator.py | 15 +++++++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 16 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 0577d7917c726..87e09a92ee224 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -523,6 +523,21 @@ def make_hastie_10_2(n_samples=12000, *, random_state=None): return X, y +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "n_features": [Interval(Integral, 1, None, closed="left")], + "n_informative": [Interval(Integral, 0, None, closed="left")], + "n_targets": [Interval(Integral, 1, None, closed="left")], + "bias": [Interval(Real, None, None, closed="neither")], + "effective_rank": [Interval(Integral, 1, None, closed="left"), None], + "tail_strength": [Interval(Real, 0, 1, closed="both")], + "noise": [Interval(Real, 0, None, closed="left")], + "shuffle": ["boolean"], + "coef": ["boolean"], + "random_state": ["random_state"], + } +) def make_regression( n_samples=100, n_features=100, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index e14b9f0b67205..19c57d1e38720 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -133,6 +133,7 @@ def _check_function_param_validation( "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", "sklearn.datasets.make_low_rank_matrix", + "sklearn.datasets.make_regression", "sklearn.datasets.make_sparse_coded_signal", "sklearn.decomposition.sparse_encode", "sklearn.feature_extraction.grid_to_graph", From ced38d886eeaf1f9e08e06ec733aa52f2ced0709 Mon Sep 17 00:00:00 2001 From: Dominic Fox Date: Tue, 21 Mar 2023 14:13:37 +0000 Subject: [PATCH 079/230] MAINT Parameters validation for metrics.mean_squared_log_error (#25924) --- sklearn/metrics/_regression.py | 9 +++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 10 insertions(+) diff --git a/sklearn/metrics/_regression.py b/sklearn/metrics/_regression.py index d4337cad59984..c351320a48278 100644 --- a/sklearn/metrics/_regression.py +++ b/sklearn/metrics/_regression.py @@ -487,6 +487,15 @@ def mean_squared_error( return np.average(output_errors, weights=multioutput) +@validate_params( + { + "y_true": ["array-like"], + "y_pred": ["array-like"], + "sample_weight": ["array-like", None], + "multioutput": [StrOptions({"raw_values", "uniform_average"}), "array-like"], + "squared": ["boolean"], + } +) def mean_squared_log_error( y_true, y_pred, *, sample_weight=None, multioutput="uniform_average", squared=True ): diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 19c57d1e38720..6667d286e2e98 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -179,6 +179,7 @@ def _check_function_param_validation( "sklearn.metrics.mean_gamma_deviance", "sklearn.metrics.mean_pinball_loss", "sklearn.metrics.mean_squared_error", + "sklearn.metrics.mean_squared_log_error", "sklearn.metrics.mean_tweedie_deviance", "sklearn.metrics.median_absolute_error", "sklearn.metrics.multilabel_confusion_matrix", From b72ddd748f12b184cf904244e7543f2e4bb2d369 Mon Sep 17 00:00:00 2001 From: Veghit Date: Tue, 21 Mar 2023 16:25:36 +0200 Subject: [PATCH 080/230] TST Use global_random_seed in tests/test_naive_bayes.py (#25890) --- sklearn/tests/test_naive_bayes.py | 48 ++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/sklearn/tests/test_naive_bayes.py b/sklearn/tests/test_naive_bayes.py index 979ae4caed407..4516fabb8961d 100644 --- a/sklearn/tests/test_naive_bayes.py +++ b/sklearn/tests/test_naive_bayes.py @@ -31,15 +31,22 @@ X = np.array([[-2, -1], [-1, -1], [-1, -2], [1, 1], [1, 2], [2, 1]]) y = np.array([1, 1, 1, 2, 2, 2]) -# A bit more random tests -rng = np.random.RandomState(0) -X1 = rng.normal(size=(10, 3)) -y1 = (rng.normal(size=(10)) > 0).astype(int) -# Data is 6 random integer points in a 100 dimensional space classified to -# three classes. -X2 = rng.randint(5, size=(6, 100)) -y2 = np.array([1, 1, 2, 2, 3, 3]) +def get_random_normal_x_binary_y(global_random_seed): + # A bit more random tests + rng = np.random.RandomState(global_random_seed) + X1 = rng.normal(size=(10, 3)) + y1 = (rng.normal(size=10) > 0).astype(int) + return X1, y1 + + +def get_random_integer_x_three_classes_y(global_random_seed): + # Data is 6 random integer points in a 100 dimensional space classified to + # three classes. + rng = np.random.RandomState(global_random_seed) + X2 = rng.randint(5, size=(6, 100)) + y2 = np.array([1, 1, 2, 2, 3, 3]) + return X2, y2 def test_gnb(): @@ -64,16 +71,17 @@ def test_gnb(): GaussianNB().partial_fit(X, y, classes=[0, 1]) -def test_gnb_prior(): +def test_gnb_prior(global_random_seed): # Test whether class priors are properly set. clf = GaussianNB().fit(X, y) assert_array_almost_equal(np.array([3, 3]) / 6.0, clf.class_prior_, 8) + X1, y1 = get_random_normal_x_binary_y(global_random_seed) clf = GaussianNB().fit(X1, y1) # Check that the class priors sum to 1 assert_array_almost_equal(clf.class_prior_.sum(), 1) -def test_gnb_sample_weight(): +def test_gnb_sample_weight(global_random_seed): """Test whether sample weights are properly used in GNB.""" # Sample weights all being 1 should not change results sw = np.ones(6) @@ -85,6 +93,8 @@ def test_gnb_sample_weight(): # Fitting twice with half sample-weights should result # in same result as fitting once with full weights + rng = np.random.RandomState(global_random_seed) + sw = rng.rand(y.shape[0]) clf1 = GaussianNB().fit(X, y, sample_weight=sw) clf2 = GaussianNB().partial_fit(X, y, classes=[1, 2], sample_weight=sw / 2) @@ -215,8 +225,9 @@ def test_gnb_naive_bayes_scale_invariance(): @pytest.mark.parametrize("DiscreteNaiveBayes", DISCRETE_NAIVE_BAYES_CLASSES) -def test_discretenb_prior(DiscreteNaiveBayes): +def test_discretenb_prior(DiscreteNaiveBayes, global_random_seed): # Test whether class priors are properly set. + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) clf = DiscreteNaiveBayes().fit(X2, y2) assert_array_almost_equal( np.log(np.array([2, 2, 2]) / 6.0), clf.class_log_prior_, 8 @@ -274,8 +285,10 @@ def test_discretenb_partial_fit(DiscreteNaiveBayes): @pytest.mark.parametrize("NaiveBayes", ALL_NAIVE_BAYES_CLASSES) -def test_NB_partial_fit_no_first_classes(NaiveBayes): +def test_NB_partial_fit_no_first_classes(NaiveBayes, global_random_seed): # classes is required for first call to partial fit + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + with pytest.raises( ValueError, match="classes must be passed on the first call to partial_fit." ): @@ -452,10 +465,11 @@ def test_discretenb_degenerate_one_class_case( @pytest.mark.parametrize("kind", ("dense", "sparse")) -def test_mnnb(kind): +def test_mnnb(kind, global_random_seed): # Test Multinomial Naive Bayes classification. # This checks that MultinomialNB implements fit and predict and returns # correct values for a simple toy dataset. + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) if kind == "dense": X = X2 @@ -676,9 +690,11 @@ def test_cnb(): assert_array_almost_equal(clf.feature_log_prob_, normed_weights) -def test_categoricalnb(): +def test_categoricalnb(global_random_seed): # Check the ability to predict the training set. clf = CategoricalNB() + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) + y_pred = clf.fit(X2, y2).predict(X2) assert_array_equal(y_pred, y2) @@ -784,7 +800,6 @@ def test_categoricalnb_with_min_categories( ], ) def test_categoricalnb_min_categories_errors(min_categories, error_msg): - X = np.array([[0, 0], [0, 1], [0, 0], [1, 1]]) y = np.array([1, 1, 2, 2]) @@ -966,7 +981,8 @@ def test_check_alpha(): @pytest.mark.parametrize("Estimator", ALL_NAIVE_BAYES_CLASSES) -def test_predict_joint_proba(Estimator): +def test_predict_joint_proba(Estimator, global_random_seed): + X2, y2 = get_random_integer_x_three_classes_y(global_random_seed) est = Estimator().fit(X2, y2) jll = est.predict_joint_log_proba(X2) log_prob_x = logsumexp(jll, axis=1) From be3f852d618afaf3d2b86391c08b38c4f5eb90b9 Mon Sep 17 00:00:00 2001 From: Maren Westermann Date: Tue, 21 Mar 2023 15:45:43 +0100 Subject: [PATCH 081/230] TST add global_random_seed fixture to sklearn/datasets/tests/test_covtype.py (#25904) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> Co-authored-by: jeremiedbb --- sklearn/datasets/tests/test_covtype.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sklearn/datasets/tests/test_covtype.py b/sklearn/datasets/tests/test_covtype.py index aa2bd30a2ee8a..2cc2fed81bad6 100644 --- a/sklearn/datasets/tests/test_covtype.py +++ b/sklearn/datasets/tests/test_covtype.py @@ -6,9 +6,9 @@ from sklearn.datasets.tests.test_common import check_return_X_y -def test_fetch(fetch_covtype_fxt): - data1 = fetch_covtype_fxt(shuffle=True, random_state=42) - data2 = fetch_covtype_fxt(shuffle=True, random_state=37) +def test_fetch(fetch_covtype_fxt, global_random_seed): + data1 = fetch_covtype_fxt(shuffle=True, random_state=global_random_seed) + data2 = fetch_covtype_fxt(shuffle=True, random_state=global_random_seed + 1) X1, X2 = data1["data"], data2["data"] assert (581012, 54) == X1.shape From db0e68350a81b514dce85d8af3187a07a85f56ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:23:31 +0100 Subject: [PATCH 082/230] MAINT Parameters validation for datasets.make_multilabel_classification (#25920) --- sklearn/datasets/_samples_generator.py | 28 +++++++++---------- .../datasets/tests/test_samples_generator.py | 12 -------- sklearn/tests/test_public_functions.py | 1 + 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 87e09a92ee224..192f8e6759ddb 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -309,6 +309,20 @@ def make_classification( return X, y +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "n_features": [Interval(Integral, 1, None, closed="left")], + "n_classes": [Interval(Integral, 1, None, closed="left")], + "n_labels": [Interval(Integral, 0, None, closed="left")], + "length": [Interval(Integral, 1, None, closed="left")], + "allow_unlabeled": ["boolean"], + "sparse": ["boolean"], + "return_indicator": [StrOptions({"dense", "sparse"}), "boolean"], + "return_distributions": ["boolean"], + "random_state": ["random_state"], + } +) def make_multilabel_classification( n_samples=100, n_features=20, @@ -398,18 +412,6 @@ def make_multilabel_classification( The probability of each feature being drawn given each class. Only returned if ``return_distributions=True``. """ - if n_classes < 1: - raise ValueError( - "'n_classes' should be an integer greater than 0. Got {} instead.".format( - n_classes - ) - ) - if length < 1: - raise ValueError( - "'length' should be an integer greater than 0. Got {} instead.".format( - length - ) - ) generator = check_random_state(random_state) p_c = generator.uniform(size=n_classes) @@ -469,8 +471,6 @@ def sample_example(): if return_indicator in (True, "sparse", "dense"): lb = MultiLabelBinarizer(sparse_output=(return_indicator == "sparse")) Y = lb.fit([range(n_classes)]).transform(Y) - elif return_indicator is not False: - raise ValueError("return_indicator must be either 'sparse', 'dense' or False.") if return_distributions: return X, Y, p_c, p_w_c return X, Y diff --git a/sklearn/datasets/tests/test_samples_generator.py b/sklearn/datasets/tests/test_samples_generator.py index 13df2bc796a55..e722ed5c4f02a 100644 --- a/sklearn/datasets/tests/test_samples_generator.py +++ b/sklearn/datasets/tests/test_samples_generator.py @@ -283,18 +283,6 @@ def test_make_multilabel_classification_return_indicator_sparse(): assert sp.issparse(Y) -@pytest.mark.parametrize( - "params, err_msg", - [ - ({"n_classes": 0}, "'n_classes' should be an integer"), - ({"length": 0}, "'length' should be an integer"), - ], -) -def test_make_multilabel_classification_valid_arguments(params, err_msg): - with pytest.raises(ValueError, match=err_msg): - make_multilabel_classification(**params) - - def test_make_hastie_10_2(): X, y = make_hastie_10_2(n_samples=100, random_state=0) assert X.shape == (100, 10), "X shape mismatch" diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 6667d286e2e98..4b1934c378fbf 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -133,6 +133,7 @@ def _check_function_param_validation( "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", "sklearn.datasets.make_low_rank_matrix", + "sklearn.datasets.make_multilabel_classification", "sklearn.datasets.make_regression", "sklearn.datasets.make_sparse_coded_signal", "sklearn.decomposition.sparse_encode", From 5a46b9f91b182c3becfdcf8033b07aaab9fef6b3 Mon Sep 17 00:00:00 2001 From: futurewarning <36329275+futurewarning@users.noreply.github.com> Date: Wed, 22 Mar 2023 10:54:44 +0300 Subject: [PATCH 083/230] Fixed feature mapping typo (#25934) --- examples/preprocessing/plot_all_scaling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/preprocessing/plot_all_scaling.py b/examples/preprocessing/plot_all_scaling.py index d8a20ece5c56c..28aff97382355 100644 --- a/examples/preprocessing/plot_all_scaling.py +++ b/examples/preprocessing/plot_all_scaling.py @@ -69,7 +69,7 @@ feature_mapping = { "MedInc": "Median income in block", - "HousAge": "Median house age in block", + "HouseAge": "Median house age in block", "AveRooms": "Average number of rooms", "AveBedrms": "Average number of bedrooms", "Population": "Block population", From 6c368176cd5735556147fda6a84cbe54bdfca5f3 Mon Sep 17 00:00:00 2001 From: Guillaume Lemaitre Date: Wed, 22 Mar 2023 09:59:45 +0100 Subject: [PATCH 084/230] MAINT switch to newer codecov uploader (#25919) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Loïc Estève --- ...38_conda_defaults_openblas_environment.yml | 1 - ...onda_defaults_openblas_linux-64_conda.lock | 17 ++---- .../py38_conda_forge_mkl_environment.yml | 1 - .../py38_conda_forge_mkl_win-64_conda.lock | 13 +++-- ...e_openblas_ubuntu_2204_linux-64_conda.lock | 12 ++--- ...latest_conda_forge_mkl_linux-64_conda.lock | 17 +++--- ...t_conda_forge_mkl_linux-64_environment.yml | 1 - ..._forge_mkl_no_coverage_linux-64_conda.lock | 12 ++--- ...pylatest_conda_forge_mkl_osx-64_conda.lock | 23 ++++---- ...est_conda_forge_mkl_osx-64_environment.yml | 1 - ...latest_conda_mkl_no_openmp_environment.yml | 1 - ...test_conda_mkl_no_openmp_osx-64_conda.lock | 7 ++- ...latest_pip_openblas_pandas_environment.yml | 1 - ...st_pip_openblas_pandas_linux-64_conda.lock | 17 +++--- .../pylatest_pip_scipy_dev_environment.yml | 1 - ...pylatest_pip_scipy_dev_linux-64_conda.lock | 53 +++++++++---------- build_tools/azure/pypy3_linux-64_conda.lock | 6 +-- build_tools/azure/upload_codecov.sh | 28 +++++++++- build_tools/circle/doc_linux-64_conda.lock | 22 ++++---- .../doc_min_dependencies_linux-64_conda.lock | 34 ++++++------ .../py39_conda_forge_linux-aarch64_conda.lock | 8 +-- .../update_environments_and_lock_files.py | 1 - 22 files changed, 138 insertions(+), 139 deletions(-) diff --git a/build_tools/azure/py38_conda_defaults_openblas_environment.yml b/build_tools/azure/py38_conda_defaults_openblas_environment.yml index 24caf7f564aae..68d860e720830 100644 --- a/build_tools/azure/py38_conda_defaults_openblas_environment.yml +++ b/build_tools/azure/py38_conda_defaults_openblas_environment.yml @@ -16,7 +16,6 @@ dependencies: - pytest - pytest-xdist=2.5.0 - pillow - - codecov - pytest-cov - coverage=6.2 - ccache diff --git a/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock b/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock index 4ca6039ea4824..b19ba3b8133eb 100644 --- a/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock +++ b/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 1863117ea2056e97dc2c1fbe9911947e624810721a98e00f07cebe4547d44b3f +# input_hash: b2abf7313453f4c215a430bad6b188860065331448105408976274d4b5370848 @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 https://repo.anaconda.com/pkgs/main/linux-64/blas-1.0-openblas.conda#9ddfcaef10d79366c90128f5dc444be8 @@ -48,7 +48,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/libclang-10.0.1-default_hb85057a_2. https://repo.anaconda.com/pkgs/main/linux-64/libtiff-4.5.0-h6a678d5_2.conda#b3391ee6956636eb8ef159c1c454e3da https://repo.anaconda.com/pkgs/main/linux-64/libxkbcommon-1.0.1-hfa300c1_0.conda#913e6c7c04026ff341960a9700889498 https://repo.anaconda.com/pkgs/main/linux-64/libxslt-1.1.35-h4e12654_0.conda#328c111d87dccd5a3e471a691833f670 -https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.40.1-h5082296_0.conda#7d44bb7460f1b1b0764d63240d7f7f81 +https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.41.1-h5eee18b_0.conda#709601b06aa55f41f299ef6d374a3eef https://repo.anaconda.com/pkgs/main/linux-64/fontconfig-2.14.1-h52c9d5c_1.conda#cd3f711abef17203045b7bcfc83fac2f https://repo.anaconda.com/pkgs/main/linux-64/gst-plugins-base-1.14.1-h6a678d5_1.conda#afd9cbe949d670d24cc0a007aaec1fe1 https://repo.anaconda.com/pkgs/main/linux-64/lcms2-2.12-h3be6417_0.conda#719db47afba9f6586eecb5eacac70bff @@ -58,23 +58,19 @@ https://repo.anaconda.com/pkgs/main/linux-64/nss-3.74-h0370c37_0.conda#fb2426b2f https://repo.anaconda.com/pkgs/main/linux-64/python-3.8.16-h7a1cb2a_3.conda#c11c0992727585f5f991760f5b18c968 https://repo.anaconda.com/pkgs/main/linux-64/attrs-22.1.0-py38h06a4308_0.conda#51beb64c6f06b5a69529df7ecaccc3f9 https://repo.anaconda.com/pkgs/main/linux-64/certifi-2022.12.7-py38h06a4308_0.conda#243cddde550e2c3e765db25cdea99a13 -https://repo.anaconda.com/pkgs/main/noarch/charset-normalizer-2.0.4-pyhd3eb1b0_0.conda#e7a441d94234b2b5fafee06e25dbf076 https://repo.anaconda.com/pkgs/main/linux-64/coverage-6.2-py38h7f8727e_0.conda#34a3006ca7d8d286b63593b31b845ace https://repo.anaconda.com/pkgs/main/noarch/cycler-0.11.0-pyhd3eb1b0_0.conda#f5e365d2cdb66d547eb8c3ab93843aab https://repo.anaconda.com/pkgs/main/noarch/execnet-1.9.0-pyhd3eb1b0_0.conda#f895937671af67cebb8af617494b3513 -https://repo.anaconda.com/pkgs/main/linux-64/idna-3.4-py38h06a4308_0.conda#e1c05a7fa231e08f357d92702689cbdd https://repo.anaconda.com/pkgs/main/noarch/iniconfig-1.1.1-pyhd3eb1b0_0.tar.bz2#e40edff2c5708f342cef43c7f280c507 https://repo.anaconda.com/pkgs/main/linux-64/joblib-1.1.1-py38h06a4308_0.conda#e655dfc29e36336810c9f69dea37b2de https://repo.anaconda.com/pkgs/main/linux-64/kiwisolver-1.4.4-py38h6a678d5_0.conda#7424aa335d22974192800ec19a68486e https://repo.anaconda.com/pkgs/main/linux-64/numpy-base-1.17.3-py38h2f8d375_0.conda#40edbb76ecacefb1e6ab639b514822b1 -https://repo.anaconda.com/pkgs/main/linux-64/packaging-22.0-py38h06a4308_0.conda#f09d8a44adf4dae78562c6f9af3603d6 +https://repo.anaconda.com/pkgs/main/linux-64/packaging-23.0-py38h06a4308_0.conda#87dd3a3af0b6c6f5bbb99b7f205c2612 https://repo.anaconda.com/pkgs/main/linux-64/pillow-9.4.0-py38h6a678d5_0.conda#8afd1f4f8b23a1c44fca4975253b17f7 https://repo.anaconda.com/pkgs/main/linux-64/pluggy-1.0.0-py38h06a4308_1.conda#87bb1d3f6cf3e409a1dac38cee99918e https://repo.anaconda.com/pkgs/main/linux-64/ply-3.11-py38_0.conda#d6a69c576c6e4d19e3074eaae3d149f2 https://repo.anaconda.com/pkgs/main/noarch/py-1.11.0-pyhd3eb1b0_0.conda#7205a898ed2abbf6e9b903dff6abe08e -https://repo.anaconda.com/pkgs/main/noarch/pycparser-2.21-pyhd3eb1b0_0.conda#135a72ff2a31150a3a3ff0b1edd41ca9 https://repo.anaconda.com/pkgs/main/linux-64/pyparsing-3.0.9-py38h06a4308_0.conda#becbbf51d2b05de228eed968e20f963d -https://repo.anaconda.com/pkgs/main/linux-64/pysocks-1.7.1-py38h06a4308_0.conda#21c67581f3a81ffbb02728eb2178d693 https://repo.anaconda.com/pkgs/main/linux-64/pytz-2022.7-py38h06a4308_0.conda#19c9f6a24d5c6f779c645d00f646666b https://repo.anaconda.com/pkgs/main/linux-64/qt-main-5.15.2-h327a75a_7.conda#1868b206ade356f1812a723804e1cc31 https://repo.anaconda.com/pkgs/main/noarch/six-1.16.0-pyhd3eb1b0_1.conda#34586824d411d36af2fa40e799c172d0 @@ -83,15 +79,12 @@ https://repo.anaconda.com/pkgs/main/noarch/toml-0.10.2-pyhd3eb1b0_0.conda#cda05f https://repo.anaconda.com/pkgs/main/linux-64/tomli-2.0.1-py38h06a4308_0.conda#791cce9de9913e9587b0a85cd8419123 https://repo.anaconda.com/pkgs/main/linux-64/tornado-6.2-py38h5eee18b_0.conda#db2f7ebc500d97a4af6889dfd0d03dbc https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.38.4-py38h06a4308_0.conda#52f195e95a5f11c5b9a9eed9cd3d6958 -https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.15.1-py38h5eee18b_3.conda#ebf03031554d834c5aafdbed9be24f7f https://repo.anaconda.com/pkgs/main/linux-64/numpy-1.17.3-py38h7e8d029_0.conda#5f2b196b515f8fe6b37e3d224650577d https://repo.anaconda.com/pkgs/main/linux-64/pytest-7.1.2-py38h06a4308_0.conda#8d7f526a3d29273e06957d302f515755 https://repo.anaconda.com/pkgs/main/noarch/python-dateutil-2.8.2-pyhd3eb1b0_0.conda#211ee00320b08a1ac9fea6677649f6c9 https://repo.anaconda.com/pkgs/main/linux-64/qt-webengine-5.15.9-hd2b0992_4.conda#ed674e212597b93fffa1afc90a3e100c https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.6.3-py38h06a4308_0.conda#7676b836ec3f9cb1b0f8661d5863d1a4 https://repo.anaconda.com/pkgs/main/linux-64/sip-6.6.2-py38h6a678d5_0.conda#cb3f0d10f7f79870945f4dbbe0000f92 -https://repo.anaconda.com/pkgs/main/linux-64/brotlipy-0.7.0-py38h27cfd23_1003.conda#e881c8ee8a4048f29da5d20f0330fe37 -https://repo.anaconda.com/pkgs/main/linux-64/cryptography-39.0.1-py38h9ce1e76_0.conda#ad365e5ba98df04384bb85fe322bc1a4 https://repo.anaconda.com/pkgs/main/linux-64/matplotlib-base-3.1.3-py38hef1b27d_0.conda#a7ad7d097c25b7beeb76f370d51687a1 https://repo.anaconda.com/pkgs/main/linux-64/pandas-1.2.4-py38ha9443f7_0.conda#5bd3fd807a294f387feabc65821b75d0 https://repo.anaconda.com/pkgs/main/linux-64/pip-23.0.1-py38h06a4308_0.conda#76496ff05a04113680df82fd3566e215 @@ -101,11 +94,7 @@ https://repo.anaconda.com/pkgs/main/noarch/pytest-forked-1.3.0-pyhd3eb1b0_0.tar. https://repo.anaconda.com/pkgs/main/linux-64/qtwebkit-5.212-h4eab89a_4.conda#7317bbf3f3e66a0a02b07b860783ecff https://repo.anaconda.com/pkgs/main/linux-64/scipy-1.3.2-py38he2b7bc3_0.conda#a9df91d5a41c1f39524fc8a53c56bc29 https://repo.anaconda.com/pkgs/main/linux-64/pyamg-4.2.3-py38h79cecc1_0.conda#6e7f4f94000b244396de8bf4e6ae8dc4 -https://repo.anaconda.com/pkgs/main/linux-64/pyopenssl-23.0.0-py38h06a4308_0.conda#3f667b964a242e8c4463935ea3a3331e https://repo.anaconda.com/pkgs/main/linux-64/pyqt-5.15.7-py38h6a678d5_1.conda#62232dc285be8e7e85ae9596d89b3b95 https://repo.anaconda.com/pkgs/main/noarch/pytest-xdist-2.5.0-pyhd3eb1b0_0.conda#d15cdc4207bcf8ca920822597f1d138d https://repo.anaconda.com/pkgs/main/linux-64/matplotlib-3.1.3-py38_0.conda#70d5f6df438d469dc78f082389ada23d -https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.14-py38h06a4308_0.conda#c84afcc85e999af5ef824aae356cce6a -https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py38h06a4308_1.conda#657ef918b2c2ee58064feb167e451dc6 -https://repo.anaconda.com/pkgs/main/noarch/codecov-2.1.11-pyhd3eb1b0_0.conda#83a743cc928162d53d4066c43468b2c7 # pip cython @ https://files.pythonhosted.org/packages/4c/59/3702d649aeb0fef4dac55036279d3981130cc7024ea2492753f66fb622dd/Cython-0.29.33-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl#sha256=b5e8ce3039ff64000d58cd45b3f6f83e13f032dde7f27bb1ab96070d9213550b diff --git a/build_tools/azure/py38_conda_forge_mkl_environment.yml b/build_tools/azure/py38_conda_forge_mkl_environment.yml index 847d8f6e471c7..a3f5fdae5d7b6 100644 --- a/build_tools/azure/py38_conda_forge_mkl_environment.yml +++ b/build_tools/azure/py38_conda_forge_mkl_environment.yml @@ -15,7 +15,6 @@ dependencies: - pytest - pytest-xdist=2.5.0 - pillow - - codecov - pytest-cov - coverage - wheel diff --git a/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock b/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock index 0460596c2df20..b60485a906c33 100644 --- a/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock +++ b/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: e176819d6d3155f9b8afd9e262f268db47cb5d6dc157a00168d3bd0c0f55766c +# input_hash: d20b90a2fb34524e3b754ff7df81ecfd23ca81c25ec515df39bfd005501dca12 @EXPLICIT https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.12.7-h5b45459_0.conda#31de4d9887dc8eaed9e6230a5dfbb9d6 https://conda.anaconda.org/conda-forge/win-64/intel-openmp-2023.0.0-h57928b3_25922.conda#8ecf3a448f5a35bd30cb39ddc2a19058 @@ -26,7 +26,7 @@ https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_0.tar.bz https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.3.0-hcfcfb64_0.conda#381a3645c51cbf478872899b16490318 https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#0cc5c5cc64ee1637f37f8540a175854c https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libgfortran-5.3.0-6.tar.bz2#066552ac6b907ec6d72c0ddab29050dc -https://conda.anaconda.org/conda-forge/win-64/openssl-3.0.8-hcfcfb64_0.conda#46cd47b2c18522b98c34e5101e583137 +https://conda.anaconda.org/conda-forge/win-64/openssl-3.1.0-hcfcfb64_0.conda#4245a25fae1aaf85bc3fbf6fc29c2d5d https://conda.anaconda.org/conda-forge/win-64/pthreads-win32-2.9.1-hfa6e2cd_3.tar.bz2#e2da8758d7d51ff6aa78a14dfb9dbed4 https://conda.anaconda.org/conda-forge/win-64/tk-8.6.12-h8ffe710_0.tar.bz2#c69a5047cc9291ae40afd4a1ad6f0c0f https://conda.anaconda.org/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2#515d77642eaa3639413c6b1bc3f94219 @@ -37,7 +37,7 @@ https://conda.anaconda.org/conda-forge/win-64/libbrotlienc-1.0.9-hcfcfb64_8.tar. https://conda.anaconda.org/conda-forge/win-64/libclang13-15.0.7-default_h77d9078_1.conda#799890c6c093e7a64ea0dcb3d4f90115 https://conda.anaconda.org/conda-forge/win-64/libpng-1.6.39-h19919ed_0.conda#ab6febdb2dbd9c00803609079db4de71 https://conda.anaconda.org/conda-forge/win-64/libvorbis-1.3.7-h0e60522_0.tar.bz2#e1a22282de0169c93e4ffe6ce6acc212 -https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.3-hc3477c8_0.tar.bz2#6dcf17bf780618ddb559d992ea3b6961 +https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.3-hc3477c8_3.conda#1f37656230ab24d79970fe82594440f2 https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2#fe759119b8b3bfa720b8762c6fdc35de https://conda.anaconda.org/conda-forge/win-64/pcre2-10.40-h17e33f8_0.tar.bz2#2519de0d9620dc2bc7e19caf6867136d https://conda.anaconda.org/conda-forge/win-64/python-3.8.16-h4de0772_1_cpython.conda#461d9fc92cfde68f2ca7ef0988f6326a @@ -75,14 +75,14 @@ https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5 https://conda.anaconda.org/conda-forge/win-64/tornado-6.2-py38h91455d4_1.tar.bz2#ed09a022d62a1550692f856c104d929e https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/win-64/unicodedata2-15.0.0-py38h91455d4_0.tar.bz2#7a135e40d9f26c15419e5e82e1c436c0 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.40.0-pyhd8ed1ab_0.conda#49bb0d9e60ce1db25e151780331bb5f3 https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyhd8ed1ab_6.tar.bz2#30878ecc4bd36e8deeea1e3c151b2e0b https://conda.anaconda.org/conda-forge/win-64/xorg-libxau-1.0.9-hcd874cb_0.tar.bz2#9cef622e75683c17d05ae62d66e69e6c https://conda.anaconda.org/conda-forge/win-64/xorg-libxdmcp-1.1.3-hcd874cb_0.tar.bz2#46878ebb6b9cbd8afcf8088d7ef00ece https://conda.anaconda.org/conda-forge/noarch/zipp-3.15.0-pyhd8ed1ab_0.conda#13018819ca8f5b7cc675a8faf1f5fedf https://conda.anaconda.org/conda-forge/win-64/brotli-1.0.9-hcfcfb64_8.tar.bz2#2e661f21e1741c11506bdc7226e6b0bc https://conda.anaconda.org/conda-forge/win-64/cffi-1.15.1-py38h57701bc_3.conda#9b94af390cfdf924a063302a2ddb3860 -https://conda.anaconda.org/conda-forge/win-64/coverage-7.2.1-py38h91455d4_0.conda#1719d68213cb7c4b35848ef9fd3fd910 +https://conda.anaconda.org/conda-forge/win-64/coverage-7.2.2-py38h91455d4_0.conda#f580488152afd50b99f830b075d55be9 https://conda.anaconda.org/conda-forge/win-64/glib-tools-2.74.1-h12be248_1.tar.bz2#cd93cc622f2fa0f68ddc978cb67a5061 https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb @@ -98,7 +98,7 @@ https://conda.anaconda.org/conda-forge/win-64/tbb-2021.8.0-h91493d7_0.conda#e155 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/win-64/brotlipy-0.7.0-py38h91455d4_1005.tar.bz2#9fabc7fadfb37addbe91cc67c09cda69 https://conda.anaconda.org/conda-forge/win-64/cryptography-39.0.2-py38h95f5157_0.conda#016c4a7f3965f42c2ad208b5a9aaf55f -https://conda.anaconda.org/conda-forge/win-64/fonttools-4.39.0-py38h91455d4_0.conda#161c6466cabd436abf9597d3053694b1 +https://conda.anaconda.org/conda-forge/win-64/fonttools-4.39.2-py38h91455d4_0.conda#add310032aa2cbae67f78ef5189b033a https://conda.anaconda.org/conda-forge/win-64/glib-2.74.1-h12be248_1.tar.bz2#7564888ab882b9d3aea46355ab7adaca https://conda.anaconda.org/conda-forge/noarch/importlib-resources-5.12.0-pyhd8ed1ab_0.conda#3544c818f0720c89eb16ae6940ab440b https://conda.anaconda.org/conda-forge/win-64/mkl-2022.1.0-h6a75c08_874.tar.bz2#2ff89a7337a9636029b4db9466e9f8e3 @@ -121,7 +121,6 @@ https://conda.anaconda.org/conda-forge/win-64/numpy-1.24.2-py38h7ec9225_0.conda# https://conda.anaconda.org/conda-forge/win-64/qt-main-5.15.8-h88fe7eb_7.conda#e3428bb2c38bb338c6421d81647a9865 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/win-64/blas-devel-3.9.0-16_win64_mkl.tar.bz2#dc89c75a7dd26c88ac77d64bf313973e -https://conda.anaconda.org/conda-forge/noarch/codecov-2.1.12-pyhd8ed1ab_0.conda#0317ed52e504b93da000e8a027628775 https://conda.anaconda.org/conda-forge/win-64/contourpy-1.0.7-py38hb1fd069_0.conda#6b53200dddcec578cdd90cac146eeadd https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e https://conda.anaconda.org/conda-forge/win-64/pyqt-5.15.7-py38hd6c051e_3.conda#9b17c0bbf19c6e265c3967e33df8770a diff --git a/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock b/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock index 68a408d18f707..c2596de2a0b43 100644 --- a/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock +++ b/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock @@ -46,10 +46,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 -https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.2-hcb278e6_0.conda#08efb1e1813f1a151b7a945b972a049b +https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.3-hcb278e6_0.conda#141a126675b6d1a4eabb111a4a353898 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-h0b41bf4_0.conda#2d833be81a21128e317325a01326d36f https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.38-h0b41bf4_0.conda#9ac34337e5101a87e5d91da05d84aa48 @@ -75,8 +75,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_3.conda#29474f139e5017090f218ef6b3753efd https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.21-pthreads_h320a7e8_3.tar.bz2#29155b9196b9d78022f11d86733e25a7 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b @@ -93,10 +92,11 @@ https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openbl https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.1-h166bdaf_0.tar.bz2#f967fc95089cd247ceed56eda31de3a9 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz2#ed5349aa96776e00b34eccecf4a948fe https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad -https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_0.conda#70cbb0c2033665f2a7339bf0ec51a67f +https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_1.conda#17d91085ccf5934ce652cb448d0cb65a https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.8.16-he550d4f_1_cpython.conda#9de84cccfbc5f8350a3667bb6ef6fc30 @@ -153,7 +153,7 @@ https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-16_linux64_open https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py38h4a40e3a_3.conda#3ac112151c6b6cfe457e976de41af0c5 https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.7-py38hfbd4bf9_0.conda#638537863b298151635c05c762a997ab -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py38h1de0b5d_0.conda#aac6f6ca6b8c5d321392f5f7aa3d3186 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.2-py38h1de0b5d_0.conda#affec6061f9a2d056db74561477a62b5 https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.1-h6239696_1.tar.bz2#f3220a9e9d3abcbfca43419a219df7e4 https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb diff --git a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock index c5db32b6a8597..b5a6711268661 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: e59a40b88334d702327a777b695d15c65c6ff904d742abc604e894d78faca06e +# input_hash: 074039c4568f960fb05dba525d0bfb9c74b80f243b83b0abdc0cdf9eafa1ef94 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080 @@ -47,10 +47,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 -https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.2-hcb278e6_0.conda#08efb1e1813f1a151b7a945b972a049b +https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.3-hcb278e6_0.conda#141a126675b6d1a4eabb111a4a353898 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-h0b41bf4_0.conda#2d833be81a21128e317325a01326d36f https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.38-h0b41bf4_0.conda#9ac34337e5101a87e5d91da05d84aa48 @@ -75,8 +75,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_3.conda#29474f139e5017090f218ef6b3753efd https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa @@ -91,10 +90,11 @@ https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.1-h166bdaf_0.tar.bz2#f967fc95089cd247ceed56eda31de3a9 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz2#ed5349aa96776e00b34eccecf4a948fe https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.0-hd6dc26d_0.conda#ab9d052373c9376c0ebcff4dfef3d296 -https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_0.conda#70cbb0c2033665f2a7339bf0ec51a67f +https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_1.conda#17d91085ccf5934ce652cb448d0cb65a https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-he550d4f_1_cpython.conda#8d14fc2aa12db370a443753c8230be1e @@ -146,8 +146,8 @@ https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.co https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py311h409f033_3.conda#9025d0786dbbe4bc91fd8e85502decce -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.2.1-py311h2582759_0.conda#4fee06fa1851addd1966f15ba28de7a8 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py311h2582759_0.conda#56d8b988010c53eb8ba5117e15e5b1a7 +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.2.2-py311h2582759_0.conda#41f2bca794aa1b4e70c1a23f8ec2dfa5 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.2-py311h2582759_0.conda#f227528f25c3d45717f71774222a2200 https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.1-h6239696_1.tar.bz2#f3220a9e9d3abcbfca43419a219df7e4 https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d @@ -183,7 +183,6 @@ https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.3-py311h2872171_0.con https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py311ha74522f_3.conda#ad6dd0bed0cdf5f2d4eb2b989d6253b3 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-mkl.tar.bz2#c196a26abf6b4f132c88828ab7c2231c -https://conda.anaconda.org/conda-forge/noarch/codecov-2.1.12-pyhd8ed1ab_0.conda#0317ed52e504b93da000e8a027628775 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py311h8597a09_0.conda#70c3b734ffe82c16b6d121aaa11929a8 https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py311h38be061_0.conda#8fd462c8bcbba5a3affcb2d04e387476 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_environment.yml b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_environment.yml index c6d6d70681063..ac132f87a2aba 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_environment.yml +++ b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_environment.yml @@ -17,7 +17,6 @@ dependencies: - pytest - pytest-xdist=2.5.0 - pillow - - codecov - pytest-cov - coverage - ccache diff --git a/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock index 613fb6945fa8b..0865c9331c5e7 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock @@ -47,10 +47,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 -https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.2-hcb278e6_0.conda#08efb1e1813f1a151b7a945b972a049b +https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.3-hcb278e6_0.conda#141a126675b6d1a4eabb111a4a353898 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-h0b41bf4_0.conda#2d833be81a21128e317325a01326d36f https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.38-h0b41bf4_0.conda#9ac34337e5101a87e5d91da05d84aa48 @@ -75,8 +75,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_3.conda#29474f139e5017090f218ef6b3753efd https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa @@ -91,10 +90,11 @@ https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.1-h166bdaf_0.tar.bz2#f967fc95089cd247ceed56eda31de3a9 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz2#ed5349aa96776e00b34eccecf4a948fe https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.0-hd6dc26d_0.conda#ab9d052373c9376c0ebcff4dfef3d296 -https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_0.conda#70cbb0c2033665f2a7339bf0ec51a67f +https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_1.conda#17d91085ccf5934ce652cb448d0cb65a https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-he550d4f_1_cpython.conda#8d14fc2aa12db370a443753c8230be1e @@ -146,7 +146,7 @@ https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.co https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py311h409f033_3.conda#9025d0786dbbe4bc91fd8e85502decce -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py311h2582759_0.conda#56d8b988010c53eb8ba5117e15e5b1a7 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.2-py311h2582759_0.conda#f227528f25c3d45717f71774222a2200 https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.1-h6239696_1.tar.bz2#f3220a9e9d3abcbfca43419a219df7e4 https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d diff --git a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock index d0968494e5592..bbffdb910ed00 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: osx-64 -# input_hash: 71e12e5567c1774957288c7db48fdb8c9ad13a8d69bf8e9bb6790429d0b35dcc +# input_hash: 3c603992c43a9511972b71d065855a67ea7f0e25c3e7d7e0b5a6d388a4326999 @EXPLICIT https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h0d85af4_4.tar.bz2#37edc4e6304ca87316e160f5ca0bd1b5 https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2022.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a @@ -13,7 +13,7 @@ https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hac89ed1_0.tar.bz2#6 https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-2.1.5.1-hb7f2c08_0.conda#d7309a152b9b79799063b8bb47e34a3a https://conda.anaconda.org/conda-forge/osx-64/libwebp-base-1.3.0-hb7f2c08_0.conda#18981e4c840126d6118d8952485fea51 https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.2.13-hfd90126_4.tar.bz2#35eb3fce8d51ed3c1fd4122bad48250b -https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-15.0.7-h61d9ccf_0.conda#3faa9933dff6e96333b5ca5274674b63 +https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-16.0.0-h61d9ccf_0.conda#00d0daa29e5a4ce56ef9b351148a1e88 https://conda.anaconda.org/conda-forge/osx-64/mkl-include-2022.1.0-h6bab518_928.tar.bz2#67f8511a5eaf693a202486f74035b3f7 https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.3-h96cf925_1.tar.bz2#76217ebfbb163ff2770a261f955a5861 https://conda.anaconda.org/conda-forge/osx-64/pthread-stubs-0.4-hc929b4f_1001.tar.bz2#addd19059de62181cd11ae8f4ef26084 @@ -32,7 +32,7 @@ https://conda.anaconda.org/conda-forge/osx-64/libllvm14-14.0.6-h5b596cc_1.tar.bz https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.39-ha978bb4_0.conda#35e4928794c5391aec14ffdf1deaaee5 https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_0.tar.bz2#ceb13b6726534b96e3b4e3dda91e9050 https://conda.anaconda.org/conda-forge/osx-64/libxcb-1.13-h0d85af4_1004.tar.bz2#eb7860935e14aec936065cbc21a1a962 -https://conda.anaconda.org/conda-forge/osx-64/openssl-3.0.8-hfd90126_0.conda#4239d01834a13512079046ea216b6657 +https://conda.anaconda.org/conda-forge/osx-64/openssl-3.1.0-hfd90126_0.conda#a7df3470c748a517663bf095c2ac0235 https://conda.anaconda.org/conda-forge/osx-64/readline-8.1.2-h3899abd_0.tar.bz2#89fa404901fa8fb7d4f4e07083b8d635 https://conda.anaconda.org/conda-forge/osx-64/tapi-1100.0.11-h9ce4665_0.tar.bz2#f9ff42ccf809a21ba6f8607f8de36108 https://conda.anaconda.org/conda-forge/osx-64/tbb-2021.8.0-hb8565cd_0.conda#17cc6d45a28433867fc74bf67c3d5459 @@ -63,7 +63,7 @@ https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#3427 https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.4-py311hd2070f0_1.tar.bz2#5219e72a43e53e8f6af4fdf76a0f90ef https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.15-h2dcdeff_1.conda#f1df9b0c2d9fbe985e62f4b24773a9e4 -https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-609-hfd63004_11.conda#8881d41cb8fa1104d4545c6b7ddc9671 +https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-609-hfd63004_12.conda#a906b0296ce3ef06fe49ae5f3a0bc2ba https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-16_osx64_mkl.tar.bz2#96b23c2ca3208c5cb1ed34270448af5c https://conda.anaconda.org/conda-forge/osx-64/libhiredis-1.0.2-h2beb688_0.tar.bz2#524282b2c46c9dedf051b3bc2ae05494 https://conda.anaconda.org/conda-forge/osx-64/mkl-devel-2022.1.0-h694c41f_929.tar.bz2#041ceef009fe6d29cbd2555907c23ab3 @@ -85,14 +85,14 @@ https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5 https://conda.anaconda.org/conda-forge/osx-64/tornado-6.2-py311h5547dcb_1.tar.bz2#bc9918caedfa2de9e582104bf605d57d https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/osx-64/ccache-4.7.3-h2822714_0.tar.bz2#a119676fd25b0268da665107f7176ec6 -https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-973.0.1-hcc6d90d_11.conda#f1af817221bc31e7c770e1ea15374355 +https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-973.0.1-hcc6d90d_12.conda#5e2c08283fa0292e0e40776a2b9ebb1c https://conda.anaconda.org/conda-forge/osx-64/cffi-1.15.1-py311ha86e640_3.conda#5967be4da33261eada7cc79593f71088 https://conda.anaconda.org/conda-forge/osx-64/clang-14.0.6-h694c41f_0.tar.bz2#77667c3c75b88f12782f628d171ffeda -https://conda.anaconda.org/conda-forge/osx-64/coverage-7.2.1-py311h5547dcb_0.conda#920a96ad1180ab4cd6629f05a3d1aa2b -https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.39.0-py311h5547dcb_0.conda#71ca7a0861fcba81e88c4221e58ca527 +https://conda.anaconda.org/conda-forge/osx-64/coverage-7.2.2-py311h5547dcb_0.conda#912eec0baf21527e058cff24f2bc6794 +https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.39.2-py311h5547dcb_0.conda#b108bcc7df5a90356ca9934261d84536 https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-11.3.0-h1f927f5_31.conda#926da9259d77f6a95d60c5a956425c2f https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/osx-64/ld64-609-hc6ad406_11.conda#9e14075f26a915bc6180b40789138adf +https://conda.anaconda.org/conda-forge/osx-64/ld64-609-hc6ad406_12.conda#5a29a02594a0420c065a9605f9584dff https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-16_osx64_mkl.tar.bz2#430c4d18fd8bbc987c4367f5d16135cf https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-16_osx64_mkl.tar.bz2#757f1ae46973ce6542784d99b9984d8d https://conda.anaconda.org/conda-forge/osx-64/pillow-9.4.0-py311hf47c0a6_2.conda#4607ae953e3b427be289048f8314b778 @@ -100,7 +100,7 @@ https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/osx-64/brotlipy-0.7.0-py311h5547dcb_1005.tar.bz2#5f97ac938a90d06eebea42c321abe0d7 -https://conda.anaconda.org/conda-forge/osx-64/cctools-973.0.1-h76f1dac_11.conda#77d8192c013d7a4a355aee5b0ae1ae20 +https://conda.anaconda.org/conda-forge/osx-64/cctools-973.0.1-h76f1dac_12.conda#4ee6ac722f14547eca4e6127fa58c2d2 https://conda.anaconda.org/conda-forge/osx-64/clangxx-14.0.6-default_h55ffa42_0.tar.bz2#6a46064b0506895d090302433e70397b https://conda.anaconda.org/conda-forge/osx-64/cryptography-39.0.2-py311h61927ef_0.conda#46ed09cb9666419cc7f3547ecb03037f https://conda.anaconda.org/conda-forge/osx-64/liblapacke-3.9.0-16_osx64_mkl.tar.bz2#ba52eebcca282a5abaa3d3ac79cf2b05 @@ -118,12 +118,11 @@ https://conda.anaconda.org/conda-forge/osx-64/blas-2.116-mkl.tar.bz2#bcaf774ad76 https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-14.0.6-h613da45_0.tar.bz2#b44e0625319f9933e584dc3b96f5baf7 https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.7.1-py311h2bf763f_0.conda#d67ac9c9b834ae77ff7b2c59f702803c https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 -https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-14.0.6-h3113cd8_4.conda#e1828ef1597292a9ea25627fdfacb9f3 +https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-14.0.6-h3113cd8_5.conda#58b412dfe688499105abf77a3e2efc45 https://conda.anaconda.org/conda-forge/osx-64/matplotlib-3.7.1-py311h6eed73b_0.conda#c112be16f02d1c68de63ae3ec6fc7db4 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.5.2-hbf74d83_0.conda#c1413ef5a20d658923e12dd3b566d8f3 -https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-14.0.6-h6f97653_4.conda#f9f2cc37068e5f2f4332793640329fe3 -https://conda.anaconda.org/conda-forge/noarch/codecov-2.1.12-pyhd8ed1ab_0.conda#0317ed52e504b93da000e8a027628775 +https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-14.0.6-h6f97653_5.conda#45b992b3f628805b2105868a96e87b20 https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-11.3.0-h18f7dce_1.conda#4e066d81dd3b86556b723021980f4ed8 https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.5.2-hb8565cd_0.conda#349ae14723b98f76ea0fcb8e532b2ead diff --git a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_environment.yml b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_environment.yml index 5bcc09b32fffa..feb695522a6f4 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_environment.yml +++ b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_environment.yml @@ -17,7 +17,6 @@ dependencies: - pytest - pytest-xdist=2.5.0 - pillow - - codecov - pytest-cov - coverage - ccache diff --git a/build_tools/azure/pylatest_conda_mkl_no_openmp_environment.yml b/build_tools/azure/pylatest_conda_mkl_no_openmp_environment.yml index 7c8d5eacce147..b7d03066bbfc7 100644 --- a/build_tools/azure/pylatest_conda_mkl_no_openmp_environment.yml +++ b/build_tools/azure/pylatest_conda_mkl_no_openmp_environment.yml @@ -16,7 +16,6 @@ dependencies: - pytest - pytest-xdist=2.5.0 - pillow - - codecov - pytest-cov - coverage=6.2 - ccache diff --git a/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock b/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock index 4ac5f819ac18a..aca715a4bf7e3 100644 --- a/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock +++ b/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: osx-64 -# input_hash: 211dc0aa2fa7562dd69a06e538952166b6595d4ba2e4d2c8351253db0e501950 +# input_hash: 40b842ec75ea372152bc67e814b589be36a20b034256a8d716ebf95351dc7866 @EXPLICIT https://repo.anaconda.com/pkgs/main/osx-64/blas-1.0-mkl.conda#cb2c87e85ac8e0ceae776d26d4214c8a https://repo.anaconda.com/pkgs/main/osx-64/ca-certificates-2023.01.10-hecd8cb5_0.conda#4544150389480f19dd67c20b3bb12d61 @@ -31,7 +31,7 @@ https://repo.anaconda.com/pkgs/main/osx-64/tk-8.6.12-h5d9f67b_0.conda#047f0af548 https://repo.anaconda.com/pkgs/main/osx-64/brotli-bin-1.0.9-hca72f7f_7.conda#110bdca1a20710820e61f7fa3047f737 https://repo.anaconda.com/pkgs/main/osx-64/freetype-2.12.1-hd8bbffd_0.conda#1f276af321375ee7fe8056843044fa76 https://repo.anaconda.com/pkgs/main/osx-64/libgfortran-5.0.0-11_3_0_hecd8cb5_28.conda#2eb13b680803f1064e53873ae0aaafb3 -https://repo.anaconda.com/pkgs/main/osx-64/sqlite-3.40.1-h880c91c_0.conda#88f64d3c988ae3688131cb38910776c0 +https://repo.anaconda.com/pkgs/main/osx-64/sqlite-3.41.1-h6c40b1e_0.conda#d0d96da969acd85080c45ee04fabc6aa https://repo.anaconda.com/pkgs/main/osx-64/zstd-1.5.2-hcb37349_0.conda#d3ba225e3bc4285d8efd8cdfd7aa6112 https://repo.anaconda.com/pkgs/main/osx-64/brotli-1.0.9-hca72f7f_7.conda#68e54d12ec67591deb2ffd70348fb00f https://repo.anaconda.com/pkgs/main/osx-64/libtiff-4.5.0-hcec6c5f_2.conda#f0b033a82af1bd028f112cdecef1fe0a @@ -50,7 +50,7 @@ https://repo.anaconda.com/pkgs/main/osx-64/kiwisolver-1.4.4-py39hcec6c5f_0.conda https://repo.anaconda.com/pkgs/main/osx-64/lcms2-2.12-hf1fd2bf_0.conda#697aba7a3308226df7a93ccfeae16ffa https://repo.anaconda.com/pkgs/main/osx-64/libwebp-1.2.4-hf6ce154_1.conda#07d0981c3847293d4aea5778298a12d3 https://repo.anaconda.com/pkgs/main/noarch/munkres-1.1.4-py_0.conda#148362ba07f92abab76999a680c80084 -https://repo.anaconda.com/pkgs/main/osx-64/packaging-22.0-py39hecd8cb5_0.conda#a1ac08e4d5f08fcb7240edb91639ac0e +https://repo.anaconda.com/pkgs/main/osx-64/packaging-23.0-py39hecd8cb5_0.conda#09e12aa29746fb55cc52f17b96bfe3c9 https://repo.anaconda.com/pkgs/main/osx-64/pluggy-1.0.0-py39hecd8cb5_1.conda#c5507133514846cc5f54dc4de9ba1563 https://repo.anaconda.com/pkgs/main/noarch/py-1.11.0-pyhd3eb1b0_0.conda#7205a898ed2abbf6e9b903dff6abe08e https://repo.anaconda.com/pkgs/main/noarch/pycparser-2.21-pyhd3eb1b0_0.conda#135a72ff2a31150a3a3ff0b1edd41ca9 @@ -82,7 +82,6 @@ https://repo.anaconda.com/pkgs/main/osx-64/pyopenssl-23.0.0-py39hecd8cb5_0.conda https://repo.anaconda.com/pkgs/main/noarch/pytest-xdist-2.5.0-pyhd3eb1b0_0.conda#d15cdc4207bcf8ca920822597f1d138d https://repo.anaconda.com/pkgs/main/osx-64/urllib3-1.26.14-py39hecd8cb5_0.conda#dc5d0364bf213af8a0ab1e75d608230c https://repo.anaconda.com/pkgs/main/osx-64/requests-2.28.1-py39hecd8cb5_1.conda#ca1021033fe6ba4cf13b563afed0b9ef -https://repo.anaconda.com/pkgs/main/noarch/codecov-2.1.11-pyhd3eb1b0_0.conda#83a743cc928162d53d4066c43468b2c7 https://repo.anaconda.com/pkgs/main/noarch/pooch-1.4.0-pyhd3eb1b0_0.conda#69ec83cb3d152f9e854115555004f368 https://repo.anaconda.com/pkgs/main/osx-64/bottleneck-1.3.5-py39h67323c0_0.conda#312133560b81ec1a2aaf95835e90b5e9 https://repo.anaconda.com/pkgs/main/osx-64/contourpy-1.0.5-py39haf03e11_0.conda#e4bf1c4fc91f39170273f422f2c97481 diff --git a/build_tools/azure/pylatest_pip_openblas_pandas_environment.yml b/build_tools/azure/pylatest_pip_openblas_pandas_environment.yml index 9cc56cc2716d3..c33ce0c250275 100644 --- a/build_tools/azure/pylatest_pip_openblas_pandas_environment.yml +++ b/build_tools/azure/pylatest_pip_openblas_pandas_environment.yml @@ -20,7 +20,6 @@ dependencies: - pytest - pytest-xdist==2.5.0 - pillow - - codecov - pytest-cov - coverage - numpydoc diff --git a/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock b/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock index 0b72d882699fb..4fade961151a6 100644 --- a/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock +++ b/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: c268536f64c353efd8a32b7f76ae09489ef30493354dfdfa69f5e648f908ad75 +# input_hash: 5973c99c9c39a0101d80d3c5f5a44274fc7376ade1e5d3ef8f0e488d464a7fe4 @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2023.01.10-h06a4308_0.conda#7704989a2ccf6c1f5a50c985509841c4 @@ -18,7 +18,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/zlib-1.2.13-h5eee18b_0.conda#333e31 https://repo.anaconda.com/pkgs/main/linux-64/ccache-3.7.9-hfe4627d_0.conda#bef6fc681c273bb7bd0c67d1a591365e https://repo.anaconda.com/pkgs/main/linux-64/readline-8.2-h5eee18b_0.conda#be42180685cce6e6b0329201d9f48efb https://repo.anaconda.com/pkgs/main/linux-64/tk-8.6.12-h1ccaba5_0.conda#fa10ff4aa631fa4aa090a6234d7770b9 -https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.40.1-h5082296_0.conda#7d44bb7460f1b1b0764d63240d7f7f81 +https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.41.1-h5eee18b_0.conda#709601b06aa55f41f299ef6d374a3eef https://repo.anaconda.com/pkgs/main/linux-64/python-3.9.16-h7a1cb2a_2.conda#6b4f255f11b3facb3fa17061757b8cc2 https://repo.anaconda.com/pkgs/main/noarch/alabaster-0.7.12-pyhd3eb1b0_0.tar.bz2#21ad3b69a5ce6c22e724e9dbb4cffa65 https://repo.anaconda.com/pkgs/main/linux-64/certifi-2022.12.7-py39h06a4308_0.conda#b4238d910e43d09651eebe8db79b5c68 @@ -28,7 +28,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/docutils-0.18.1-py39h06a4308_3.cond https://repo.anaconda.com/pkgs/main/linux-64/idna-3.4-py39h06a4308_0.conda#92ee6ebc3f880fe03d98f90d122d4719 https://repo.anaconda.com/pkgs/main/linux-64/imagesize-1.4.1-py39h06a4308_0.conda#daa11cdf95b501d5cd35edcaeaaa3fdc https://repo.anaconda.com/pkgs/main/linux-64/markupsafe-2.1.1-py39h7f8727e_0.conda#81867b86384d8b25db1141c360803b5f -https://repo.anaconda.com/pkgs/main/linux-64/packaging-22.0-py39h06a4308_0.conda#f0d5483df1e0c0221c519d557da09dec +https://repo.anaconda.com/pkgs/main/linux-64/packaging-23.0-py39h06a4308_0.conda#a3da65d1bfc6e59f5411c11c0fd1315f https://repo.anaconda.com/pkgs/main/noarch/pycparser-2.21-pyhd3eb1b0_0.conda#135a72ff2a31150a3a3ff0b1edd41ca9 https://repo.anaconda.com/pkgs/main/noarch/pygments-2.11.2-pyhd3eb1b0_0.conda#eff55c770961f459a734cf86768aac98 https://repo.anaconda.com/pkgs/main/linux-64/pysocks-1.7.1-py39h06a4308_0.conda#0a2dc6c521fd674b11a99dea461c2d84 @@ -44,7 +44,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.38.4-py39h06a4308_0.conda#8 https://repo.anaconda.com/pkgs/main/linux-64/zipp-3.11.0-py39h06a4308_0.conda#6b0ec14d6d5182748006e984590daca5 https://repo.anaconda.com/pkgs/main/linux-64/babel-2.11.0-py39h06a4308_0.conda#57afaec3ce18928835e87fa5187ef22c https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.15.1-py39h5eee18b_3.conda#89bf9aee92a2429222630337bec3d73f -https://repo.anaconda.com/pkgs/main/linux-64/importlib-metadata-4.11.3-py39h06a4308_0.conda#3049562ec071212e501225d07d0853db +https://repo.anaconda.com/pkgs/main/linux-64/importlib-metadata-6.0.0-py39h06a4308_0.conda#cc268ce97197920bd7ee27aa7c404a77 https://repo.anaconda.com/pkgs/main/linux-64/jinja2-3.1.2-py39h06a4308_0.conda#1ae40578c29a6ed9ca0cf23c89d48fa4 https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.6.3-py39h06a4308_0.conda#c45480250c7a422ae327df494aced180 https://repo.anaconda.com/pkgs/main/linux-64/brotlipy-0.7.0-py39h27cfd23_1003.conda#be47bcffb9e3e7495897b02589f5ad1a @@ -59,7 +59,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py39h06a4308_0.conda#8 # pip cython @ https://files.pythonhosted.org/packages/87/4c/41e4fc95a31ec6747e74283e987fb9b3b7c0b3cb2cf10af65f02bd0359d4/Cython-0.29.33-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl#sha256=4f88c2dc0653eef6468848eb8022faf64115b39734f750a1c01a7ba7eb04d89f # pip exceptiongroup @ https://files.pythonhosted.org/packages/61/97/17ed81b7a8d24d8f69b62c0db37abbd8c0042d4b3fc429c73dab986e7483/exceptiongroup-1.1.1-py3-none-any.whl#sha256=232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e # pip execnet @ https://files.pythonhosted.org/packages/81/c0/3072ecc23f4c5e0a1af35e3a222855cfd9c80a1a105ca67be3b6172637dd/execnet-1.9.0-py2.py3-none-any.whl#sha256=a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142 -# pip fonttools @ https://files.pythonhosted.org/packages/43/6e/810648a366d6488e1e0543f72dcb2016e54ec02933e302cd41d72599e90d/fonttools-4.39.0-py3-none-any.whl#sha256=f5e764e1fd6ad54dfc201ff32af0ba111bcfbe0d05b24540af74c63db4ed6390 +# pip fonttools @ https://files.pythonhosted.org/packages/0c/e6/77183fd874c8f6162a1c8f3b91a96ad910d10aef010a51a4db8c2f96f3dd/fonttools-4.39.2-py3-none-any.whl#sha256=85245aa2fd4cf502a643c9a9a2b5a393703e150a6eaacc3e0e84bb448053f061 # pip iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl#sha256=b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # pip joblib @ https://files.pythonhosted.org/packages/91/d4/3b4c8e5a30604df4c7518c562d4bf0502f2fa29221459226e140cf846512/joblib-1.2.0-py3-none-any.whl#sha256=091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385 # pip kiwisolver @ https://files.pythonhosted.org/packages/a4/36/c414d75be311ce97ef7248edcc4fc05afae2998641bf6b592d43a9dee581/kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f @@ -75,8 +75,8 @@ https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py39h06a4308_0.conda#8 # pip tomli @ https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl#sha256=939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc # pip typing-extensions @ https://files.pythonhosted.org/packages/31/25/5abcd82372d3d4a3932e1fa8c3dbf9efac10cc7c0d16e78467460571b404/typing_extensions-4.5.0-py3-none-any.whl#sha256=fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4 # pip contourpy @ https://files.pythonhosted.org/packages/c7/97/ba9ace011734cd01b63eb7d39b2cf97afbfa985b0239ab0db85bafa9b207/contourpy-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=e7281244c99fd7c6f27c1c6bfafba878517b0b62925a09b586d88ce750a016d2 -# pip coverage @ https://files.pythonhosted.org/packages/e5/a9/62aabc67971d2fd439474b05cfc25c852b28bb6dfe8082c5b665652899f5/coverage-7.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=8a6450da4c7afc4534305b2b7d8650131e130610cea448ff240b6ab73d7eab63 -# pip imageio @ https://files.pythonhosted.org/packages/dc/0b/202efcb00ba89c749bb7b22634c917f29a58bdf052dabe8041f23743974f/imageio-2.26.0-py3-none-any.whl#sha256=1a4fdb820abc52ba0f08e770ee46293c334908e8d53217808d9d888f993b1df2 +# pip coverage @ https://files.pythonhosted.org/packages/47/21/632047c45edb08f0eb51f9e8e49591d23c15ff078b32e0a88ddf99f4e8c2/coverage-7.2.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=db8c2c5ace167fd25ab5dd732714c51d4633f58bac21fb0ff63b0349f62755a8 +# pip imageio @ https://files.pythonhosted.org/packages/86/c2/d822a7f53a3ac91868419baac685c21812124ae882888e722fe01b529e09/imageio-2.26.1-py3-none-any.whl#sha256=df56ade8a9b43476ce020be0202b09a3a4cc0c7a079f8fe5ee4b87105eff4237 # pip importlib-resources @ https://files.pythonhosted.org/packages/38/71/c13ea695a4393639830bf96baea956538ba7a9d06fcce7cef10bfff20f72/importlib_resources-5.12.0-py3-none-any.whl#sha256=7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a # pip numpydoc @ https://files.pythonhosted.org/packages/c4/81/ad9b8837442ff451eca82515b41ac425f87acff7e2fc016fd1bda13fc01a/numpydoc-1.5.0-py3-none-any.whl#sha256=c997759fb6fc32662801cece76491eedbc0ec619b514932ffd2b270ae89c07f9 # pip pytest @ https://files.pythonhosted.org/packages/b2/68/5321b5793bd506961bd40bdbdd0674e7de4fb873ee7cab33dd27283ad513/pytest-7.2.2-py3-none-any.whl#sha256=130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e @@ -84,8 +84,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py39h06a4308_0.conda#8 # pip pywavelets @ https://files.pythonhosted.org/packages/5a/98/4549479a32972bdfdd5e75e168219e97f4dfaee535a8308efef7291e8398/PyWavelets-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=71ab30f51ee4470741bb55fc6b197b4a2b612232e30f6ac069106f0156342356 # pip scipy @ https://files.pythonhosted.org/packages/5d/30/b2a2a5bf1a3beefb7609fb871dcc6aef7217c69cef19a4631b7ab5622a8a/scipy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601 # pip setuptools-scm @ https://files.pythonhosted.org/packages/1d/66/8f42c941be949ef2b22fe905d850c794e7c170a526023612aad5f3a121ad/setuptools_scm-7.1.0-py3-none-any.whl#sha256=73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e -# pip tifffile @ https://files.pythonhosted.org/packages/df/30/b3a70a98b1be0ef881593b7f0ea7fd2aed9f5f3440e90547aa79000a8792/tifffile-2023.2.28-py3-none-any.whl#sha256=8357cd8ccbdd4378ad4d6b84ffe3ab15b1d96630b1719f576d4de386f45546f1 -# pip codecov @ https://files.pythonhosted.org/packages/dc/e2/964d0881eff5a67bf5ddaea79a13c7b34a74bc4efe917b368830b475a0b9/codecov-2.1.12-py2.py3-none-any.whl#sha256=585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47 +# pip tifffile @ https://files.pythonhosted.org/packages/87/4d/f4f4834ca37da0f1106fd0437f40931c91c26acba7d2db3535de5cb66649/tifffile-2023.3.15-py3-none-any.whl#sha256=0ad708d0d5a45d068444e9036a20f1f8a237da008e35cc9cbc69bbb5602d6987 # pip matplotlib @ https://files.pythonhosted.org/packages/9f/77/0cd22f92f7103383cb1ce3b3efc77411b9cc3a495242c8f2a623b498f586/matplotlib-3.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=f883a22a56a84dba3b588696a2b8a1ab0d2c3d41be53264115c71b0a942d8fdb # pip pandas @ https://files.pythonhosted.org/packages/e1/4d/3eb96e53a9208350ee21615f850c4be9a246d32bf1d34cd36682cb58c3b7/pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5 # pip pyamg @ https://files.pythonhosted.org/packages/8e/08/d512b6e34d502152723b5a4ad9d962a6141dfe83cd8bcd01af4cb6e84f28/pyamg-4.2.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=18af99d2551df07951c35cf270dc76703f8c5d30b16ea8e61657fda098f57dd7 diff --git a/build_tools/azure/pylatest_pip_scipy_dev_environment.yml b/build_tools/azure/pylatest_pip_scipy_dev_environment.yml index 4a887eb4d3dc7..63ed821ed8a7b 100644 --- a/build_tools/azure/pylatest_pip_scipy_dev_environment.yml +++ b/build_tools/azure/pylatest_pip_scipy_dev_environment.yml @@ -12,7 +12,6 @@ dependencies: - threadpoolctl - pytest - pytest-xdist==2.5.0 - - codecov - pytest-cov - coverage - pooch diff --git a/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock b/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock index 151c6e0a62fdb..0f6560ebf94e5 100644 --- a/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock +++ b/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 401344e88dad2c8fde3bee9593788afe08d47c9714c6bb772ee8cc2d1cdcc03e +# input_hash: bd4830a1fd6c0ce57e55705bfd110e229684142ae3d90f13c2822cb0ef88b69a @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2023.01.10-h06a4308_0.conda#7704989a2ccf6c1f5a50c985509841c4 @@ -20,21 +20,21 @@ https://repo.anaconda.com/pkgs/main/linux-64/zlib-1.2.13-h5eee18b_0.conda#333e31 https://repo.anaconda.com/pkgs/main/linux-64/ccache-3.7.9-hfe4627d_0.conda#bef6fc681c273bb7bd0c67d1a591365e https://repo.anaconda.com/pkgs/main/linux-64/readline-8.2-h5eee18b_0.conda#be42180685cce6e6b0329201d9f48efb https://repo.anaconda.com/pkgs/main/linux-64/tk-8.6.12-h1ccaba5_0.conda#fa10ff4aa631fa4aa090a6234d7770b9 -https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.40.1-h5082296_0.conda#7d44bb7460f1b1b0764d63240d7f7f81 -https://repo.anaconda.com/pkgs/main/linux-64/python-3.10.9-h7a1cb2a_2.conda#6f7b15ceb8bbfbadbd8574ceb3912328 +https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.41.1-h5eee18b_0.conda#709601b06aa55f41f299ef6d374a3eef +https://repo.anaconda.com/pkgs/main/linux-64/python-3.11.0-h7a1cb2a_3.conda#a2b9a7050d4dc13bc51eadbf557b3f6a https://repo.anaconda.com/pkgs/main/noarch/alabaster-0.7.12-pyhd3eb1b0_0.tar.bz2#21ad3b69a5ce6c22e724e9dbb4cffa65 -https://repo.anaconda.com/pkgs/main/linux-64/certifi-2022.12.7-py310h06a4308_0.conda#1f28faeb97a361c9998090edc4e7d729 +https://repo.anaconda.com/pkgs/main/linux-64/certifi-2022.12.7-py311h06a4308_0.conda#c83da4712f456a311a15392186b607a3 https://repo.anaconda.com/pkgs/main/noarch/charset-normalizer-2.0.4-pyhd3eb1b0_0.conda#e7a441d94234b2b5fafee06e25dbf076 -https://repo.anaconda.com/pkgs/main/linux-64/colorama-0.4.6-py310h06a4308_0.conda#7af8aba349d231595e84a92b6eede917 -https://repo.anaconda.com/pkgs/main/linux-64/docutils-0.18.1-py310h06a4308_3.conda#5613973eae6fa1c63272b3aee8999580 -https://repo.anaconda.com/pkgs/main/linux-64/idna-3.4-py310h06a4308_0.conda#7f4dba8f7c37983e0d56fad719c94ba3 -https://repo.anaconda.com/pkgs/main/linux-64/imagesize-1.4.1-py310h06a4308_0.conda#31935cd380a5bd6e42694f23b3775a0a -https://repo.anaconda.com/pkgs/main/linux-64/markupsafe-2.1.1-py310h7f8727e_0.conda#01b266ef21f9c040fef79461e4d0bd41 -https://repo.anaconda.com/pkgs/main/linux-64/packaging-22.0-py310h06a4308_0.conda#def74f82ff8818339ec8d80cdc836374 +https://repo.anaconda.com/pkgs/main/linux-64/colorama-0.4.6-py311h06a4308_0.conda#e9e95330183ae1f49a4448bc772c0f86 +https://repo.anaconda.com/pkgs/main/linux-64/docutils-0.18.1-py311h06a4308_3.conda#4e54aecf990cdca05853247a80f0db47 +https://repo.anaconda.com/pkgs/main/linux-64/idna-3.4-py311h06a4308_0.conda#ace9494db4d1927c447dc6f81bc95f0a +https://repo.anaconda.com/pkgs/main/linux-64/imagesize-1.4.1-py311h06a4308_0.conda#b1336aeeee49deaee844b31324ce0a16 +https://repo.anaconda.com/pkgs/main/linux-64/markupsafe-2.1.1-py311h5eee18b_0.conda#5d815163b43fe73c9e224453d470f5cf +https://repo.anaconda.com/pkgs/main/linux-64/packaging-23.0-py311h06a4308_0.conda#00e34d9a35fc77d5f6d4a475c947a93e https://repo.anaconda.com/pkgs/main/noarch/pycparser-2.21-pyhd3eb1b0_0.conda#135a72ff2a31150a3a3ff0b1edd41ca9 https://repo.anaconda.com/pkgs/main/noarch/pygments-2.11.2-pyhd3eb1b0_0.conda#eff55c770961f459a734cf86768aac98 -https://repo.anaconda.com/pkgs/main/linux-64/pysocks-1.7.1-py310h06a4308_0.conda#b0753810caadcd4a550c833f87fb3866 -https://repo.anaconda.com/pkgs/main/linux-64/pytz-2022.7-py310h06a4308_0.conda#e9fa82907692334494d14d7751ca0190 +https://repo.anaconda.com/pkgs/main/linux-64/pysocks-1.7.1-py311h06a4308_0.conda#0c6bf55446eb174d2c749fd9499ca181 +https://repo.anaconda.com/pkgs/main/linux-64/pytz-2022.7-py311h06a4308_0.conda#97637c3925dc85ac3cb42cd561f82f31 https://repo.anaconda.com/pkgs/main/noarch/snowballstemmer-2.2.0-pyhd3eb1b0_0.conda#c8c10f2cd854c0a27630760958bba60c https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-applehelp-1.0.2-pyhd3eb1b0_0.tar.bz2#ac923499f97b9a9ab7c672b27cb2a1a8 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-devhelp-1.0.2-pyhd3eb1b0_0.tar.bz2#bc39c2b70430734b5879d6b504e3311f @@ -42,20 +42,20 @@ https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd3eb1 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-jsmath-1.0.1-pyhd3eb1b0_0.tar.bz2#e43f8de7d6a717935ab220a0c957771d https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-qthelp-1.0.3-pyhd3eb1b0_0.tar.bz2#08d67f73f640b4d1e5e8890a324b60e3 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd3eb1b0_0.conda#0440b84dfd478f340cf14c2d7c24f6c7 -https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.38.4-py310h06a4308_0.conda#fbb0a31c9dbe6a43fd4a8c6abe744890 -https://repo.anaconda.com/pkgs/main/linux-64/babel-2.11.0-py310h06a4308_0.conda#1eff25d9f192342c01d960c6bae79c32 -https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.15.1-py310h5eee18b_3.conda#d65505a7028c5cb1d6a078fa688be2be -https://repo.anaconda.com/pkgs/main/linux-64/jinja2-3.1.2-py310h06a4308_0.conda#f22cc11648fc31b2cebaafed2dd8d5ec -https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.6.3-py310h06a4308_0.conda#d8331a85881df5712194edf67638cf08 -https://repo.anaconda.com/pkgs/main/linux-64/brotlipy-0.7.0-py310h7f8727e_1002.conda#a8dfa5aefcc49d5e78000b16d2b7714e -https://repo.anaconda.com/pkgs/main/linux-64/cryptography-39.0.1-py310h9ce1e76_0.conda#71f493886ed29220fb1b6e60ae511e68 -https://repo.anaconda.com/pkgs/main/linux-64/pip-23.0.1-py310h06a4308_0.conda#f8f27960f21f51c3945fae93e2993e85 -https://repo.anaconda.com/pkgs/main/linux-64/pyopenssl-23.0.0-py310h06a4308_0.conda#be4c8fd04572aabe5c4cf6f80cfcb1b8 -https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.14-py310h06a4308_0.conda#e0b4cfc539954199295eda612157b195 -https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py310h06a4308_1.conda#65a9f765635f12679cbfff91d8ebed8e -https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py310h06a4308_0.conda#9636e58b351ac5c4cc8367bcc0c29321 +https://repo.anaconda.com/pkgs/main/noarch/wheel-0.37.1-pyhd3eb1b0_0.conda#ab85e96e26da8d5797c2458232338b86 +https://repo.anaconda.com/pkgs/main/linux-64/babel-2.11.0-py311h06a4308_0.conda#b0e1c6be7b334706670ed7d203b61775 +https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.15.1-py311h5eee18b_3.conda#82ea1fb8934a7e4b93298cdee7d7628d +https://repo.anaconda.com/pkgs/main/linux-64/jinja2-3.1.2-py311h06a4308_0.conda#1173c148bd36cfc89283992fb37ef859 +https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.5.0-py311h06a4308_0.conda#64fe3e2957dfdb50f32450a9aa6e5346 +https://repo.anaconda.com/pkgs/main/linux-64/brotlipy-0.7.0-py311h5eee18b_1002.conda#d0decdefee9dcf89dcbaad2ffd30b830 +https://repo.anaconda.com/pkgs/main/linux-64/cryptography-38.0.4-py311hbdeaff8_0.conda#b6f1d8d13930d292b38dbb0f00e64f27 +https://repo.anaconda.com/pkgs/main/linux-64/pip-22.3.1-py311h06a4308_0.conda#352428d11ace1b907a0d1933cb21d070 +https://repo.anaconda.com/pkgs/main/linux-64/pyopenssl-23.0.0-py311h06a4308_0.conda#3ba9d6d2f74e89aa80e5bae3966f3a43 +https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.12-py311h06a4308_0.conda#80cbf014853f8260fedb33b362f1013b +https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py311h06a4308_0.conda#cb7be2752ad61f1049f3eff471218ed5 +https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py311h06a4308_0.conda#ed071b775d26745823d958bf3751b044 # pip attrs @ https://files.pythonhosted.org/packages/fb/6e/6f83bf616d2becdf333a1640f1d463fef3150e2e926b7010cb0f81c95e88/attrs-22.2.0-py3-none-any.whl#sha256=29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 -# pip exceptiongroup @ https://files.pythonhosted.org/packages/61/97/17ed81b7a8d24d8f69b62c0db37abbd8c0042d4b3fc429c73dab986e7483/exceptiongroup-1.1.1-py3-none-any.whl#sha256=232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e +# pip coverage @ https://files.pythonhosted.org/packages/d0/94/fa6095cce802c11a53685c5267330caed7ef02e2fb99b9f9f1c892859259/coverage-7.2.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=006ed5582e9cbc8115d2e22d6d2144a0725db542f654d9d4fda86793832f873d # pip execnet @ https://files.pythonhosted.org/packages/81/c0/3072ecc23f4c5e0a1af35e3a222855cfd9c80a1a105ca67be3b6172637dd/execnet-1.9.0-py2.py3-none-any.whl#sha256=a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142 # pip iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl#sha256=b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # pip platformdirs @ https://files.pythonhosted.org/packages/7b/e1/593f693096c50411a2bf9571f66bc3be9d0f79a4a50e95aab581458b0e3c/platformdirs-3.1.1-py3-none-any.whl#sha256=e5986afb596e4bb5bde29a79ac9061aa955b94fca2399b7aaac4090860920dd8 @@ -63,13 +63,10 @@ https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py310h06a4308_0.conda# # pip py @ https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl#sha256=607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 # pip six @ https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl#sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # pip threadpoolctl @ https://files.pythonhosted.org/packages/61/cf/6e354304bcb9c6413c4e02a747b600061c21d38ba51e7e544ac7bc66aecc/threadpoolctl-3.1.0-py3-none-any.whl#sha256=8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b -# pip tomli @ https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl#sha256=939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc -# pip coverage @ https://files.pythonhosted.org/packages/f3/ff/0bf7a9497dc91e4b0f11656a50c95fd1e641d912a281a0b0921d20fa5760/coverage-7.2.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=b2167d116309f564af56f9aa5e75ef710ef871c5f9b313a83050035097b56820 # pip numpydoc @ https://files.pythonhosted.org/packages/c4/81/ad9b8837442ff451eca82515b41ac425f87acff7e2fc016fd1bda13fc01a/numpydoc-1.5.0-py3-none-any.whl#sha256=c997759fb6fc32662801cece76491eedbc0ec619b514932ffd2b270ae89c07f9 # pip pooch @ https://files.pythonhosted.org/packages/84/8c/4da580db7fb4cfce8f5ed78e7d2aa542e6f201edd69d3d8a96917a8ff63c/pooch-1.7.0-py3-none-any.whl#sha256=74258224fc33d58f53113cf955e8d51bf01386b91492927d0d1b6b341a765ad7 # pip pytest @ https://files.pythonhosted.org/packages/b2/68/5321b5793bd506961bd40bdbdd0674e7de4fb873ee7cab33dd27283ad513/pytest-7.2.2-py3-none-any.whl#sha256=130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e # pip python-dateutil @ https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl#sha256=961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 -# pip codecov @ https://files.pythonhosted.org/packages/dc/e2/964d0881eff5a67bf5ddaea79a13c7b34a74bc4efe917b368830b475a0b9/codecov-2.1.12-py2.py3-none-any.whl#sha256=585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47 # pip pytest-cov @ https://files.pythonhosted.org/packages/fe/1f/9ec0ddd33bd2b37d6ec50bb39155bca4fe7085fa78b3b434c05459a860e3/pytest_cov-4.0.0-py3-none-any.whl#sha256=2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b # pip pytest-forked @ https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl#sha256=810958f66a91afb1a1e2ae83089d8dc1cd2437ac96b12963042fbb9fb4d16af0 # pip pytest-xdist @ https://files.pythonhosted.org/packages/21/08/b1945d4b4986eb1aa10cf84efc5293bba39da80a2f95db3573dd90678408/pytest_xdist-2.5.0-py3-none-any.whl#sha256=6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65 diff --git a/build_tools/azure/pypy3_linux-64_conda.lock b/build_tools/azure/pypy3_linux-64_conda.lock index 36843bf98634b..64b81a86da124 100644 --- a/build_tools/azure/pypy3_linux-64_conda.lock +++ b/build_tools/azure/pypy3_linux-64_conda.lock @@ -23,7 +23,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-h0b41bf4_0.conda#2d833be81a21128e317325a01326d36f https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 @@ -34,7 +34,6 @@ https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.ta https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e1c890aebdebbfbf87e2c917187b4416 https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.21-pthreads_h320a7e8_3.tar.bz2#29155b9196b9d78022f11d86733e25a7 https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 @@ -47,6 +46,7 @@ https://conda.anaconda.org/conda-forge/linux-64/gdbm-1.18-h0a1914f_2.tar.bz2#b77 https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openblas.tar.bz2#20bae26d0a1db73f758fc3754cab4719 https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.40.0-h4ff8645_0.tar.bz2#bb11803129cbbb53ed56f9506ff74145 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_8.tar.bz2#2ff08978892a3e8b954397c461f18418 https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d8aca0bc23ca73fa8caa3e7c84c28 @@ -88,7 +88,7 @@ https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.0.0-py39h4d8b378 https://conda.anaconda.org/conda-forge/noarch/zipp-3.15.0-pyhd8ed1ab_0.conda#13018819ca8f5b7cc675a8faf1f5fedf https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py39hfda2a12_3.conda#4156b60c4af658e8a7c45e93360f8855 https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.7-py39haa83c70_0.conda#77595fa3e3dfca46289e3722cb97b29b -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py39h3d6e266_0.conda#88b42bab94be85859cf575dc4d340f66 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.2-py39h3d6e266_0.conda#bcacc2ae22ce7b5b084cd86397bd52a6 https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 diff --git a/build_tools/azure/upload_codecov.sh b/build_tools/azure/upload_codecov.sh index 274106cb19f75..e1fe65d496188 100755 --- a/build_tools/azure/upload_codecov.sh +++ b/build_tools/azure/upload_codecov.sh @@ -13,4 +13,30 @@ coverage combine --append popd cp $TEST_DIR/.coverage $BUILD_REPOSITORY_LOCALPATH -codecov --root $BUILD_REPOSITORY_LOCALPATH -t $CODECOV_TOKEN || echo "codecov upload failed" +# When we update the codecov uploader version, we need to update the checksums. +# The checksum for each codecov binary is available at +# https://uploader.codecov.io e.g. for linux +# https://uploader.codecov.io/v0.4.0/linux/codecov.SHA256SUM. In principle we +# need to check the signatures with the codecov gpg key as well, see +# https://docs.codecov.com/docs/codecov-uploader#integrity-checking-the-uploader +# for more details +CODECOV_UPLOADER_VERSION=0.4.0 +CODECOV_BASE_URL="https://uploader.codecov.io/v$CODECOV_UPLOADER_VERSION" +if [[ $OSTYPE == *"linux"* ]]; then + curl -Os "$CODECOV_BASE_URL/linux/codecov" + SHA256SUM="671cf0d89d1c149f57e1a9a31f3fb567ab4209e4d5829f13ff7b8c104db7131f codecov" + echo "$SHA256SUM" | shasum -a256 -c + chmod +x codecov + ./codecov -t ${CODECOV_TOKEN} --rootDir $BUILD_REPOSITORY_LOCALPATH +elif [[ $OSTYPE == *"darwin"* ]]; then + curl -Os "$CODECOV_BASE_URL/macos/codecov" + SHA256SUM="7549819f0fe115e113ec3538e259d748e87d84f68afa5deadc798967ec716b8d codecov" + echo "$SHA256SUM" | shasum -a256 -c + chmod +x codecov + ./codecov -t ${CODECOV_TOKEN} --rootDir $BUILD_REPOSITORY_LOCALPATH +else + curl -Os "$CODECOV_BASE_URL/windows/codecov.exe" + SHA256SUM="15fb34be4eb9949ad4e964a0e21c4efc79657de05b2c799e041d7293dccf60eb codecov.exe" + echo "$SHA256SUM" | sha256sum -c + ./codecov.exe -t ${CODECOV_TOKEN} --rootDir $BUILD_REPOSITORY_LOCALPATH +fi diff --git a/build_tools/circle/doc_linux-64_conda.lock b/build_tools/circle/doc_linux-64_conda.lock index 74d96ab9de6bb..b05253a984141 100644 --- a/build_tools/circle/doc_linux-64_conda.lock +++ b/build_tools/circle/doc_linux-64_conda.lock @@ -64,10 +64,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.co https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 https://conda.anaconda.org/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2#c66fe2d123249af7651ebde8984c51c2 https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 -https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.2-hcb278e6_0.conda#08efb1e1813f1a151b7a945b972a049b +https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.31.3-hcb278e6_0.conda#141a126675b6d1a4eabb111a4a353898 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.8-h0b41bf4_0.conda#e043403cd18faf815bf7705ab6c1e092 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-h0b41bf4_0.conda#2d833be81a21128e317325a01326d36f https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.10-h9fff704_0.conda#e6d228cd0bb74a51dd18f5bfce0b4115 @@ -83,7 +83,7 @@ https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.0-h27087fc_3.tar.bz2#0428af0510c3fafedf1c66b43102a34b -https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.0.6-h166bdaf_0.tar.bz2#8650e4fb44c4a618e5ab3e1e19607e32 +https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.0.7-h0b41bf4_0.conda#49e8329110001f04923fe7e864990b0c https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-11.3.0-hab1b70f_19.tar.bz2#89ac16d36e66ccb9ca5d34c9217e5799 https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.22-h11f4161_0.conda#504fa9e712b99494a9cf4630e3ca7d78 https://conda.anaconda.org/conda-forge/linux-64/libavif-0.11.1-h5cdd6b5_0.tar.bz2#2040f9067e8852606208cafa66c3563f @@ -101,8 +101,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar. https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-hf14f497_3.tar.bz2#d85acad4b47dff4e3def14a769a97906 https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_3.conda#29474f139e5017090f218ef6b3753efd https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.21-pthreads_h320a7e8_3.tar.bz2#29155b9196b9d78022f11d86733e25a7 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b @@ -124,10 +123,11 @@ https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openbl https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.1-h166bdaf_0.tar.bz2#f967fc95089cd247ceed56eda31de3a9 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz2#ed5349aa96776e00b34eccecf4a948fe https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad -https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_0.conda#70cbb0c2033665f2a7339bf0ec51a67f +https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_1.conda#17d91085ccf5934ce652cb448d0cb65a https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.9.16-h2782a2a_0_cpython.conda#95c9b7c96a7fd7342e0c9d0a917b8f78 @@ -165,7 +165,7 @@ https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py39hf939315_1. https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d8aca0bc23ca73fa8caa3e7c84c28 https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_1.conda#a3a0f7a6f0885f5e1e0ec691566afb77 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c9f4416a34bc91e0eb029f912c68f81f -https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.88.1-hdc1c0ab_0.conda#81eaeb3b35163c8e90e57532bc93754d +https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.88.1-hdc1c0ab_1.conda#3d1189864d1c0ed2a5919cb067b5903d https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_openblas.tar.bz2#823ceb5567e1a595deb643fcd17aed5a https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 @@ -202,7 +202,7 @@ https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2# https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py39hb9d737c_1.tar.bz2#8a7d309b08cff6386fe384aa10dd3748 https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.0.0-py39hb9d737c_0.tar.bz2#230d65004135bf312504a1bbcb0c7a08 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.40.0-pyhd8ed1ab_0.conda#49bb0d9e60ce1db25e151780331bb5f3 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h166bdaf_0.tar.bz2#c9b568bd804cb2903c6be6f5f68182e4 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb @@ -216,10 +216,10 @@ https://conda.anaconda.org/conda-forge/linux-64/cfitsio-4.2.0-hd9d235c_0.conda#8 https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.7-py39h4b4f3f3_0.conda#c5387f3fb1f5b8b71e1c865fc55f4951 https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.5.2-hf52228f_0.conda#6b3b19e359824b97df7145c8c878c8be https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.0-py39hb9d737c_1.tar.bz2#eb31327ace8dac15c2df243d9505a132 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.0-py39h72bdee0_0.conda#7ed17a60087175112fbbf5882bebddc2 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.39.2-py39h72bdee0_0.conda#f87853cd6f76c4b8014b41fa522e5bda https://conda.anaconda.org/conda-forge/linux-64/fortran-compiler-1.5.2-hdb1a99f_0.conda#265323e1bd53709aeb739c9b1794b398 https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.1-h6239696_1.tar.bz2#f3220a9e9d3abcbfca43419a219df7e4 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.0.0-pyha770c72_0.conda#691644becbcdca9f73243450b1c63e62 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.1.0-pyha770c72_0.conda#30b3127c385ca2ed5ef87f3d53d466bc https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37 https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb @@ -254,7 +254,7 @@ https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py39he190548_0.conda#f2a931db797bb58bd335f4a857b4c898 https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e -https://conda.anaconda.org/conda-forge/noarch/tifffile-2023.2.28-pyhd8ed1ab_0.conda#6ed72880d5af877a3c8252bb52d355ae +https://conda.anaconda.org/conda-forge/noarch/tifffile-2023.3.15-pyhd8ed1ab_0.conda#da45d6cc28eac10485aef68c9b0a1e5a https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h67dfc38_7.conda#f140acdc15a0196eef664f120c396266 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py39h5c7b992_3.conda#19e30314fe824605750da905febb8ee6 diff --git a/build_tools/circle/doc_min_dependencies_linux-64_conda.lock b/build_tools/circle/doc_min_dependencies_linux-64_conda.lock index 1919d8f3497b5..540c6cc2cc670 100644 --- a/build_tools/circle/doc_min_dependencies_linux-64_conda.lock +++ b/build_tools/circle/doc_min_dependencies_linux-64_conda.lock @@ -48,7 +48,6 @@ https://conda.anaconda.org/conda-forge/linux-64/libllvm9-9.0.1-default_hc23dcda_ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e1c890aebdebbfbf87e2c917187b4416 https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 @@ -61,14 +60,14 @@ https://conda.anaconda.org/conda-forge/linux-64/libclang-9.0.1-default_hb4e5071_ https://conda.anaconda.org/conda-forge/linux-64/libglib-2.66.3-hbe7bbb4_0.tar.bz2#d5a09a9e981849b751cb75656b7302a0 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-h6adf6a1_2.conda#2e648a34072eb39d7c4fc2a9981c5f0c https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.9.10-hee79883_0.tar.bz2#0217b0926808b1adf93247bba489d733 -https://conda.anaconda.org/conda-forge/linux-64/mkl-2020.4-h726a3e6_304.tar.bz2#b9b35a50e5377b19da6ec0709ae77fc3 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.40.0-h4ff8645_0.tar.bz2#bb11803129cbbb53ed56f9506ff74145 https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.1.1-hc9558a2_0.tar.bz2#1eb7c67eb11eab0c98a87f84174fdde1 https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d https://conda.anaconda.org/conda-forge/linux-64/fortran-compiler-1.1.1-he991be0_0.tar.bz2#e38ac82cc517b9e245c1ae99f9f140da https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-hfd0df8a_0.conda#aa8840cdf17ef0c6084d1e24abc7a28b -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.8.0-20_mkl.tar.bz2#8fbce60932c01d0e193a1a814f2002be +https://conda.anaconda.org/conda-forge/linux-64/mkl-2020.4-h726a3e6_304.tar.bz2#b9b35a50e5377b19da6ec0709ae77fc3 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea https://conda.anaconda.org/conda-forge/linux-64/python-3.8.6-h852b56e_0_cpython.tar.bz2#dd65401dfb61ac030edc0dc4d15c2c51 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.13-pyhd8ed1ab_0.conda#06006184e203b61d3525f90de394471e @@ -90,8 +89,7 @@ https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#3427 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py38h43d8883_1.tar.bz2#41ca56d5cac7bfc7eb4fcdbee878eb84 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.8.0-20_mkl.tar.bz2#14b25490fdcc44e879ac6c10fe764f68 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.8.0-20_mkl.tar.bz2#52c0ae3606eeae7e1d493f37f336f4f5 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.8.0-20_mkl.tar.bz2#8fbce60932c01d0e193a1a814f2002be https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 https://conda.anaconda.org/conda-forge/linux-64/markupsafe-1.1.1-py38h0a891b7_4.tar.bz2#d182e0c60439427453ed4a7abd28ef0d https://conda.anaconda.org/conda-forge/noarch/networkx-3.0-pyhd8ed1ab_0.conda#88e40007414ea9a13f8df20fcffa87e2 @@ -120,7 +118,7 @@ https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5 https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36 https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py38h0a891b7_1.tar.bz2#358beb228a53b5e1031862de3525d1d3 https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.40.0-pyhd8ed1ab_0.conda#49bb0d9e60ce1db25e151780331bb5f3 https://conda.anaconda.org/conda-forge/noarch/babel-2.12.1-pyhd8ed1ab_1.conda#ac432e732804a81ddcf29c92ead57cde https://conda.anaconda.org/conda-forge/linux-64/cffi-1.14.4-py38ha312104_0.tar.bz2#8f82b87522fbb1d4b24e8b5e2b1d0501 https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.0-py38h0a891b7_1.tar.bz2#183f6160ab3498b882e903b06be7d430 @@ -128,9 +126,9 @@ https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-hfdff14a_1.tar.bz2#4 https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.14.5-h36ae1b5_2.tar.bz2#00084ab2657be5bf0ba0757ccde797ef https://conda.anaconda.org/conda-forge/noarch/jinja2-2.11.3-pyhd8ed1ab_2.tar.bz2#bdedf6199eec03402a0c5db1f25e891e https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.8.0-20_mkl.tar.bz2#8274dc30518af9df1de47f5d9e73165c +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.8.0-20_mkl.tar.bz2#14b25490fdcc44e879ac6c10fe764f68 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.8.0-20_mkl.tar.bz2#52c0ae3606eeae7e1d493f37f336f4f5 https://conda.anaconda.org/conda-forge/noarch/memory_profiler-0.61.0-pyhd8ed1ab_0.tar.bz2#8b45f9f2b2f7a98b0ec179c8991a4a9b -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.17.3-py38h95a1406_0.tar.bz2#bc0cbf611fe2f86eab29b98e51404f5e https://conda.anaconda.org/conda-forge/noarch/partd-1.3.0-pyhd8ed1ab_0.tar.bz2#af8c82d121e63082926062d61d9abb54 https://conda.anaconda.org/conda-forge/noarch/pip-23.0.1-pyhd8ed1ab_0.conda#8025ca83b8ba5430b640b83917c2a6f7 https://conda.anaconda.org/conda-forge/noarch/plotly-5.10.0-pyhd8ed1ab_0.tar.bz2#e95502aa0f8e3db05d198214472575de @@ -138,32 +136,34 @@ https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 -https://conda.anaconda.org/conda-forge/linux-64/blas-2.20-mkl.tar.bz2#e7d09a07f5413e53dca5282b8fa50bed https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py38h0a891b7_1005.tar.bz2#e99e08812dfff30fdd17b3f8838e2759 https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.0-py38h1724139_0.conda#24e75282e857cb0641c4f1b82cf6d6ea https://conda.anaconda.org/conda-forge/noarch/dask-core-2023.3.1-pyhd8ed1ab_0.conda#0a3abdbff6e296d056ce01ee3529638d https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.14.5-h0935bb2_2.tar.bz2#eb125ee86480e00a4a1ed45a577c3311 +https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.8.0-20_mkl.tar.bz2#8274dc30518af9df1de47f5d9e73165c +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.17.3-py38h95a1406_0.tar.bz2#bc0cbf611fe2f86eab29b98e51404f5e +https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/linux-64/blas-2.20-mkl.tar.bz2#e7d09a07f5413e53dca5282b8fa50bed https://conda.anaconda.org/conda-forge/noarch/imageio-2.26.0-pyh24c5eb1_0.conda#7158487eb6dbc42fbb5d20f0c5796c48 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.1.3-py38h250f245_0.tar.bz2#eb182969d8ed019d4de6939f393270d2 https://conda.anaconda.org/conda-forge/linux-64/pandas-1.0.5-py38hcb8c335_0.tar.bz2#1e1b4382170fd26cf722ef008ffb651e -https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e -https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 +https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.1.1-py38h5c078b8_3.tar.bz2#dafeef887e68bd18ec84681747ca0fd5 +https://conda.anaconda.org/conda-forge/linux-64/qt-5.12.5-hd8c4c69_1.tar.bz2#0e105d4afe0c3c81c4fbd9937ec4f359 https://conda.anaconda.org/conda-forge/linux-64/scipy-1.3.2-py38h921218d_0.tar.bz2#278670dc2fef5a6309d1635f047bd456 https://conda.anaconda.org/conda-forge/noarch/patsy-0.5.3-pyhd8ed1ab_0.tar.bz2#50ef6b29b1fb0768ca82c5aeb4fb2d96 https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.0.0-py38hf6732f7_1003.tar.bz2#44e00bf7a4b6a564e9313181aaea2615 -https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e -https://conda.anaconda.org/conda-forge/linux-64/qt-5.12.5-hd8c4c69_1.tar.bz2#0e105d4afe0c3c81c4fbd9937ec4f359 +https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.12.3-py38ha8c2ead_3.tar.bz2#242c206b0c30fdc4c18aea16f04c4262 https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.16.2-py38hb3f55d8_0.tar.bz2#468b398fefac8884cd6e6513af66549b https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.12.2-pyhd8ed1ab_0.conda#cf88f3a1c11536bc3c10c14ad00ccc42 -https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.12.3-py38ha8c2ead_3.tar.bz2#242c206b0c30fdc4c18aea16f04c4262 -https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.12.2-py38h5c078b8_0.tar.bz2#33787719ad03d33cffc4e2e3ea82bc9e https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.1.3-py38_0.tar.bz2#1992ab91bbff86ded8d99d1f488d8e8b https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 -https://conda.anaconda.org/conda-forge/noarch/seaborn-0.12.2-hd8ed1ab_0.conda#50847a47c07812f88581081c620f5160 +https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.12.2-py38h5c078b8_0.tar.bz2#33787719ad03d33cffc4e2e3ea82bc9e https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/seaborn-0.12.2-hd8ed1ab_0.conda#50847a47c07812f88581081c620f5160 https://conda.anaconda.org/conda-forge/noarch/sphinx-4.0.1-pyh6c4a22f_2.tar.bz2#c203dcc46f262853ecbb9552c50d664e https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.2-pyhd8ed1ab_0.tar.bz2#025ad7ca2c7f65007ab6b6f5d93a56eb https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.7.0-py_0.tar.bz2#80bad3f857ecc86a4ab73f3e57addd13 diff --git a/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock b/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock index 963e1204e44a3..1e0701763a2de 100644 --- a/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock +++ b/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock @@ -24,7 +24,7 @@ https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.32.1-hf897c2e_100 https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.3.0-hb4cce97_0.conda#53670eaee6d77d9fe60a84f7fd226a4c https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.2.13-h4e544f5_4.tar.bz2#88596b6277fe6d39f046983aae6044db https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.3-headf329_1.tar.bz2#486b68148e121bc8bbadc3cefae4c04f -https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.0.8-hb4cce97_0.conda#268fe30a14a3f40fe54da04fc053fd2d +https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.1.0-hb4cce97_0.conda#bee9334d1f911b1e05aee5bfcc82f04b https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-hb9de7d4_1001.tar.bz2#d0183ec6ce0b5aaa3486df25fa5f0ded https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.9-h3557bc0_0.tar.bz2#e0c187f5ce240897762bbb89a8a407cc https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.3-h3557bc0_0.tar.bz2#a6c9016ae1ca5c47a3603ed4cd65fedd @@ -35,7 +35,6 @@ https://conda.anaconda.org/conda-forge/linux-aarch64/libbrotlienc-1.0.9-h4e544f5 https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.39-hf9034f9_0.conda#5ec9052384a6ac85e9111e9ac7c5ec4c https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.40.0-hf9034f9_0.tar.bz2#9afb0d5dbaa403858a660cd0b4a31d29 https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.13-h3557bc0_1004.tar.bz2#cc973f5f452272c397546eac588cddb3 -https://conda.anaconda.org/conda-forge/linux-aarch64/llvm-openmp-15.0.7-hb3b5123_0.conda#74140d39088be6562a136816c66d155e https://conda.anaconda.org/conda-forge/linux-aarch64/openblas-0.3.21-pthreads_h2d9dd7e_3.tar.bz2#17a824cf9bbf0e31998d2c1a2140204c https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.1.2-h38e3740_0.tar.bz2#3cdbfb7d7b63ae2c2d35bb167d257ecd https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.12-hd8af866_0.tar.bz2#7894e82ff743bd96c76585ddebe28e2a @@ -46,6 +45,7 @@ https://conda.anaconda.org/conda-forge/linux-aarch64/freetype-2.12.1-hbbbf32d_1. https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.9.0-16_linuxaarch64_openblas.tar.bz2#520a3ecbebc63239c27dd6f70c2ababe https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.9.0-16_linuxaarch64_openblas.tar.bz2#62990b2d1efc22d0beb394e893d39541 https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.5.0-h540f74b_5.conda#761deeaa1ea335cdbd65e1ef4b4e4deb +https://conda.anaconda.org/conda-forge/linux-aarch64/llvm-openmp-16.0.0-h45eaed7_0.conda#8de453e7c13b721d0aec91853f7311b8 https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.9.16-hb363c5e_0_cpython.conda#0a7ef29549eaef817898062eeeefebd3 https://conda.anaconda.org/conda-forge/noarch/attrs-22.2.0-pyh71513ae_0.conda#8b76db7818a4e401ed4486c4c1635cd9 https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-1.0.9-h4e544f5_8.tar.bz2#259d82bd990ba225508389509634b157 @@ -77,12 +77,12 @@ https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5 https://conda.anaconda.org/conda-forge/linux-aarch64/tornado-6.2-py39hb9a1dbb_1.tar.bz2#f5f4671e5e76b582263699cb4ab3172c https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac https://conda.anaconda.org/conda-forge/linux-aarch64/unicodedata2-15.0.0-py39h0fd3b05_0.tar.bz2#835f1a9631e600e0176593e95e85f73f -https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.40.0-pyhd8ed1ab_0.conda#49bb0d9e60ce1db25e151780331bb5f3 https://conda.anaconda.org/conda-forge/noarch/zipp-3.15.0-pyhd8ed1ab_0.conda#13018819ca8f5b7cc675a8faf1f5fedf https://conda.anaconda.org/conda-forge/linux-aarch64/blas-devel-3.9.0-16_linuxaarch64_openblas.tar.bz2#5e5a376c40e95ab4b99519dfe6dc8912 https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-1.15.1-py39hb26bf21_3.conda#dee0362c4fde8edce396183fd6390d6e https://conda.anaconda.org/conda-forge/linux-aarch64/contourpy-1.0.7-py39hd9a2fea_0.conda#efa783bf5c2b30aba3cf22599fe0274e -https://conda.anaconda.org/conda-forge/linux-aarch64/fonttools-4.39.0-py39h24fc6b6_0.conda#7d2ae43219725cd4eb35a501e46370e7 +https://conda.anaconda.org/conda-forge/linux-aarch64/fonttools-4.39.2-py39h24fc6b6_0.conda#fe1dddc76a4465cd83874cfba6c55b17 https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed1ab_0.conda#e5fd2260a231ee63b6969f4801082f2b https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-9.4.0-py39h3f802df_2.conda#b3a6f14743d98bde497be57b54c21cce diff --git a/build_tools/update_environments_and_lock_files.py b/build_tools/update_environments_and_lock_files.py index 2c06a298d6e92..f8926f4981156 100644 --- a/build_tools/update_environments_and_lock_files.py +++ b/build_tools/update_environments_and_lock_files.py @@ -65,7 +65,6 @@ ] common_dependencies = common_dependencies_without_coverage + [ - "codecov", "pytest-cov", "coverage", ] From 6d3af44423ee3b5dd5b7fd21325a9b89ec3d83b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Wed, 22 Mar 2023 11:18:30 +0100 Subject: [PATCH 085/230] TST Speed-up test suite when using pytest-xdist (#25918) --- .github/workflows/wheels.yml | 6 +---- build_tools/azure/posix-docker.yml | 6 ----- build_tools/azure/posix.yml | 3 --- build_tools/azure/test_script.sh | 6 +++-- build_tools/azure/windows.yml | 1 - build_tools/cirrus/arm_tests.yml | 2 -- build_tools/cirrus/arm_wheel.yml | 10 ++------ build_tools/github/test_windows_wheels.sh | 2 -- build_tools/wheels/test_wheels.sh | 8 ++++-- sklearn/conftest.py | 31 +++++++---------------- sklearn/utils/_openmp_helpers.pyx | 7 +++-- 11 files changed, 27 insertions(+), 55 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index a1caae9fd5e08..b43f29ffa4f7f 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -116,9 +116,7 @@ jobs: env: CONFTEST_PATH: ${{ github.workspace }}/conftest.py CONFTEST_NAME: conftest.py - CIBW_ENVIRONMENT: OMP_NUM_THREADS=2 - OPENBLAS_NUM_THREADS=2 - SKLEARN_SKIP_NETWORK_TESTS=1 + CIBW_ENVIRONMENT: SKLEARN_SKIP_NETWORK_TESTS=1 SKLEARN_BUILD_PARALLEL=3 CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform_id }} CIBW_ARCHS: all @@ -173,8 +171,6 @@ jobs: - name: Test source distribution run: bash build_tools/github/test_source.sh env: - OMP_NUM_THREADS: 2 - OPENBLAS_NUM_THREADS: 2 SKLEARN_SKIP_NETWORK_TESTS: 1 - name: Store artifacts diff --git a/build_tools/azure/posix-docker.yml b/build_tools/azure/posix-docker.yml index 65904a518fbcb..dff3ccaab1a5e 100644 --- a/build_tools/azure/posix-docker.yml +++ b/build_tools/azure/posix-docker.yml @@ -16,9 +16,6 @@ jobs: VIRTUALENV: 'testvenv' TEST_DIR: '$(Agent.WorkFolder)/tmp_folder' JUNITXML: 'test-data.xml' - OMP_NUM_THREADS: '2' - OPENBLAS_NUM_THREADS: '2' - CPU_COUNT: '2' SKLEARN_SKIP_NETWORK_TESTS: '1' PYTEST_XDIST_VERSION: 'latest' COVERAGE: 'false' @@ -71,11 +68,8 @@ jobs: -e JUNITXML -e VIRTUALENV -e PYTEST_XDIST_VERSION - -e OMP_NUM_THREADS - -e OPENBLAS_NUM_THREADS -e SKLEARN_SKIP_NETWORK_TESTS -e SELECTED_TESTS - -e CPU_COUNT -e CCACHE_COMPRESS -e BUILD_SOURCEVERSIONMESSAGE -e BUILD_REASON diff --git a/build_tools/azure/posix.yml b/build_tools/azure/posix.yml index 6c32ad2f6e76d..9499060d9c3f2 100644 --- a/build_tools/azure/posix.yml +++ b/build_tools/azure/posix.yml @@ -16,9 +16,6 @@ jobs: TEST_DIR: '$(Agent.WorkFolder)/tmp_folder' VIRTUALENV: 'testvenv' JUNITXML: 'test-data.xml' - OMP_NUM_THREADS: '2' - OPENBLAS_NUM_THREADS: '2' - CPU_COUNT: '2' SKLEARN_SKIP_NETWORK_TESTS: '1' CCACHE_DIR: $(Pipeline.Workspace)/ccache CCACHE_COMPRESS: '1' diff --git a/build_tools/azure/test_script.sh b/build_tools/azure/test_script.sh index f2f4690f6633d..52bc7b727e020 100755 --- a/build_tools/azure/test_script.sh +++ b/build_tools/azure/test_script.sh @@ -34,7 +34,8 @@ mkdir -p $TEST_DIR cp setup.cfg $TEST_DIR cd $TEST_DIR -python -c "import joblib; print(f'Number of cores: {joblib.cpu_count()}')" +python -c "import joblib; print(f'Number of cores (physical): \ +{joblib.cpu_count()} ({joblib.cpu_count(only_physical_cores=True)})')" python -c "import sklearn; sklearn.show_versions()" show_installed_libraries @@ -70,7 +71,8 @@ if [[ -n "$CHECK_WARNINGS" ]]; then fi if [[ "$PYTEST_XDIST_VERSION" != "none" ]]; then - TEST_CMD="$TEST_CMD -n$CPU_COUNT" + XDIST_WORKERS=$(python -c "import joblib; print(joblib.cpu_count(only_physical_cores=True))") + TEST_CMD="$TEST_CMD -n$XDIST_WORKERS" fi if [[ "$SHOW_SHORT_SUMMARY" == "true" ]]; then diff --git a/build_tools/azure/windows.yml b/build_tools/azure/windows.yml index 4c93e00901cb8..dc8556c1e09ce 100644 --- a/build_tools/azure/windows.yml +++ b/build_tools/azure/windows.yml @@ -19,7 +19,6 @@ jobs: PYTEST_XDIST_VERSION: 'latest' TEST_DIR: '$(Agent.WorkFolder)/tmp_folder' SHOW_SHORT_SUMMARY: 'false' - CPU_COUNT: '2' strategy: matrix: ${{ insert }}: ${{ parameters.matrix }} diff --git a/build_tools/cirrus/arm_tests.yml b/build_tools/cirrus/arm_tests.yml index 319c727954ea4..a6e5919ecc32f 100644 --- a/build_tools/cirrus/arm_tests.yml +++ b/build_tools/cirrus/arm_tests.yml @@ -8,8 +8,6 @@ linux_aarch64_test_task: memory: 6G env: CONDA_ENV_NAME: testenv - OMP_NUM_THREADS: 2 - OPENBLAS_NUM_THREADS: 2 LOCK_FILE: build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock CONDA_PKGS_DIRS: /root/.conda/pkgs HOME: / # $HOME is not defined in image and is required to install mambaforge diff --git a/build_tools/cirrus/arm_wheel.yml b/build_tools/cirrus/arm_wheel.yml index d09e529c16fe1..ece984c320249 100644 --- a/build_tools/cirrus/arm_wheel.yml +++ b/build_tools/cirrus/arm_wheel.yml @@ -4,11 +4,8 @@ macos_arm64_wheel_task: env: CONFTEST_PATH: ${CIRRUS_WORKING_DIR}/conftest.py CONFTEST_NAME: conftest.py - CIBW_ENVIRONMENT: OMP_NUM_THREADS=2 - OPENBLAS_NUM_THREADS=2 - SKLEARN_SKIP_NETWORK_TESTS=1 + CIBW_ENVIRONMENT: SKLEARN_SKIP_NETWORK_TESTS=1 SKLEARN_BUILD_PARALLEL=5 - CPU_COUNT=2 CIBW_TEST_COMMAND: bash {project}/build_tools/wheels/test_wheels.sh CIBW_TEST_REQUIRES: pytest pandas threadpoolctl pytest-xdist CIBW_BUILD_VERBOSITY: 1 @@ -54,11 +51,8 @@ linux_arm64_wheel_task: env: CONFTEST_PATH: ${CIRRUS_WORKING_DIR}/conftest.py CONFTEST_NAME: conftest.py - CIBW_ENVIRONMENT: OMP_NUM_THREADS=2 - OPENBLAS_NUM_THREADS=2 - SKLEARN_SKIP_NETWORK_TESTS=1 + CIBW_ENVIRONMENT: SKLEARN_SKIP_NETWORK_TESTS=1 SKLEARN_BUILD_PARALLEL=5 - CPU_COUNT=4 CIBW_TEST_COMMAND: bash {project}/build_tools/wheels/test_wheels.sh CIBW_TEST_REQUIRES: pytest pandas threadpoolctl pytest-xdist CIBW_BUILD_VERBOSITY: 1 diff --git a/build_tools/github/test_windows_wheels.sh b/build_tools/github/test_windows_wheels.sh index 43a1a283e652c..07954a7a91970 100755 --- a/build_tools/github/test_windows_wheels.sh +++ b/build_tools/github/test_windows_wheels.sh @@ -11,7 +11,5 @@ docker container run \ docker container run \ -e SKLEARN_SKIP_NETWORK_TESTS=1 \ - -e OMP_NUM_THREADS=2 \ - -e OPENBLAS_NUM_THREADS=2 \ --rm scikit-learn/minimal-windows \ powershell -Command "pytest --pyargs sklearn" diff --git a/build_tools/wheels/test_wheels.sh b/build_tools/wheels/test_wheels.sh index 216ffaab85859..bfbe769add657 100755 --- a/build_tools/wheels/test_wheels.sh +++ b/build_tools/wheels/test_wheels.sh @@ -11,12 +11,16 @@ if [[ "$UNAME" != "Linux" ]]; then cp $CONFTEST_PATH $CONFTEST_NAME fi +python -c "import joblib; print(f'Number of cores (physical): \ +{joblib.cpu_count()} ({joblib.cpu_count(only_physical_cores=True)})')" + # Test that there are no links to system libraries in the # threadpoolctl output section of the show_versions output: python -c "import sklearn; sklearn.show_versions()" -if [ ! -z "$CPU_COUNT" ]; then - pytest --pyargs sklearn -n $CPU_COUNT +if pip show -qq pytest-xdist; then + XDIST_WORKERS=$(python -c "import joblib; print(joblib.cpu_count(only_physical_cores=True))") + pytest --pyargs sklearn -n $XDIST_WORKERS else pytest --pyargs sklearn fi diff --git a/sklearn/conftest.py b/sklearn/conftest.py index 582409760c65b..f2cd5dafa17c2 100644 --- a/sklearn/conftest.py +++ b/sklearn/conftest.py @@ -5,13 +5,13 @@ from contextlib import suppress from unittest import SkipTest +import joblib import pytest import numpy as np from threadpoolctl import threadpool_limits from _pytest.doctest import DoctestItem from sklearn.utils import _IS_32BIT -from sklearn.utils._openmp_helpers import _openmp_effective_n_threads from sklearn._min_dependencies import PYTEST_MIN_VERSION from sklearn.utils.fixes import sp_version from sklearn.utils.fixes import parse_version @@ -233,27 +233,6 @@ def pyplot(): pyplot.close("all") -def pytest_runtest_setup(item): - """Set the number of openmp threads based on the number of workers - xdist is using to prevent oversubscription. - - Parameters - ---------- - item : pytest item - item to be processed - """ - xdist_worker_count = environ.get("PYTEST_XDIST_WORKER_COUNT") - if xdist_worker_count is None: - # returns if pytest-xdist is not installed - return - else: - xdist_worker_count = int(xdist_worker_count) - - openmp_threads = _openmp_effective_n_threads() - threads_per_worker = max(openmp_threads // xdist_worker_count, 1) - threadpool_limits(threads_per_worker, user_api="openmp") - - def pytest_configure(config): # Use matplotlib agg backend during the tests including doctests try: @@ -263,6 +242,14 @@ def pytest_configure(config): except ImportError: pass + allowed_parallelism = joblib.cpu_count(only_physical_cores=True) + xdist_worker_count = environ.get("PYTEST_XDIST_WORKER_COUNT") + if xdist_worker_count is not None: + # Set the number of OpenMP and BLAS threads based on the number of workers + # xdist is using to prevent oversubscription. + allowed_parallelism = max(allowed_parallelism // int(xdist_worker_count), 1) + threadpool_limits(allowed_parallelism) + # Register global_random_seed plugin if it is not already registered if not config.pluginmanager.hasplugin("sklearn.tests.random_seed"): config.pluginmanager.register(random_seed) diff --git a/sklearn/utils/_openmp_helpers.pyx b/sklearn/utils/_openmp_helpers.pyx index f2b2a421e4fae..859bc1b5f322c 100644 --- a/sklearn/utils/_openmp_helpers.pyx +++ b/sklearn/utils/_openmp_helpers.pyx @@ -12,7 +12,7 @@ def _openmp_parallelism_enabled(): return SKLEARN_OPENMP_PARALLELISM_ENABLED -cpdef _openmp_effective_n_threads(n_threads=None): +cpdef _openmp_effective_n_threads(n_threads=None, only_physical_cores=False): """Determine the effective number of threads to be used for OpenMP calls - For ``n_threads = None``, @@ -47,7 +47,10 @@ cpdef _openmp_effective_n_threads(n_threads=None): # to exceed the number of cpus. max_n_threads = omp_get_max_threads() else: - max_n_threads = min(omp_get_max_threads(), cpu_count()) + max_n_threads = min( + omp_get_max_threads(), + cpu_count(only_physical_cores=only_physical_cores) + ) if n_threads is None: return max_n_threads From 1c6ffbf1459aadeadcb8f72d2070eb8fd6d59a96 Mon Sep 17 00:00:00 2001 From: Adrin Jalali Date: Wed, 22 Mar 2023 11:53:10 +0100 Subject: [PATCH 086/230] DOC update license year to 2023 (#25936) --- COPYING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COPYING b/COPYING index bddf6ed887ce9..b161c890897cc 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2007-2022 The scikit-learn developers. +Copyright (c) 2007-2023 The scikit-learn developers. All rights reserved. Redistribution and use in source and binary forms, with or without From b0597e03ba77378fc4a89ec40bcfa4f43b6720c8 Mon Sep 17 00:00:00 2001 From: Yao Xiao <108576690+Charlie-XIAO@users.noreply.github.com> Date: Wed, 22 Mar 2023 21:19:41 +0800 Subject: [PATCH 087/230] FIX Remove spurious feature names warning in IsolationForest (#25931) --- doc/whats_new/v1.3.rst | 5 +++++ sklearn/ensemble/_iforest.py | 24 ++++++++++++++++-------- sklearn/ensemble/tests/test_iforest.py | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index dac97146be221..99cbaadf9b76a 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -232,6 +232,11 @@ Changelog when `max_samples` is a float and `round(n_samples * max_samples) < 1`. :pr:`25601` by :user:`Jan Fidor `. +- |Fix| :meth:`ensemble.IsolationForest.fit` no longer warns about missing + feature names when called with `contamination` not `"auto"` on a pandas + dataframe. + :pr:`25931` by :user:`Yao Xiao `. + :mod:`sklearn.exception` ........................ - |Feature| Added :class:`exception.InconsistentVersionWarning` which is raised diff --git a/sklearn/ensemble/_iforest.py b/sklearn/ensemble/_iforest.py index 4d6c1c3f0b7f9..cc0f3cf09dee7 100644 --- a/sklearn/ensemble/_iforest.py +++ b/sklearn/ensemble/_iforest.py @@ -344,8 +344,10 @@ def fit(self, X, y=None, sample_weight=None): self.offset_ = -0.5 return self - # else, define offset_ wrt contamination parameter - self.offset_ = np.percentile(self.score_samples(X), 100.0 * self.contamination) + # Else, define offset_ wrt contamination parameter + # To avoid performing input validation a second time we call + # _score_samples rather than score_samples + self.offset_ = np.percentile(self._score_samples(X), 100.0 * self.contamination) return self @@ -428,15 +430,21 @@ def score_samples(self, X): The anomaly score of the input samples. The lower, the more abnormal. """ - # code structure from ForestClassifier/predict_proba - - check_is_fitted(self) - # Check data X = self._validate_data(X, accept_sparse="csr", dtype=np.float32, reset=False) - # Take the opposite of the scores as bigger is better (here less - # abnormal) + return self._score_samples(X) + + def _score_samples(self, X): + """Private version of score_samples without input validation. + + Input validation would remove feature names, so we disable it. + """ + # Code structure from ForestClassifier/predict_proba + + check_is_fitted(self) + + # Take the opposite of the scores as bigger is better (here less abnormal) return -self._compute_chunked_score_samples(X) def _compute_chunked_score_samples(self, X): diff --git a/sklearn/ensemble/tests/test_iforest.py b/sklearn/ensemble/tests/test_iforest.py index 5f046540fffdc..7650dd5c14ce4 100644 --- a/sklearn/ensemble/tests/test_iforest.py +++ b/sklearn/ensemble/tests/test_iforest.py @@ -339,3 +339,21 @@ def test_base_estimator_property_deprecated(): ) with pytest.warns(FutureWarning, match=warn_msg): model.base_estimator_ + + +def test_iforest_preserve_feature_names(): + """Check that feature names are preserved when contamination is not "auto". + + Feature names are required for consistency checks during scoring. + + Non-regression test for Issue #25844 + """ + pd = pytest.importorskip("pandas") + rng = np.random.RandomState(0) + + X = pd.DataFrame(data=rng.randn(4), columns=["a"]) + model = IsolationForest(random_state=0, contamination=0.05) + + with warnings.catch_warnings(): + warnings.simplefilter("error", UserWarning) + model.fit(X) From 0583408fa432c397f5c90f6d29d4d5577d151b2e Mon Sep 17 00:00:00 2001 From: Olivier Grisel Date: Wed, 22 Mar 2023 16:05:40 +0100 Subject: [PATCH 088/230] TST fix unstable test_newrand_set_seed (#25940) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/svm/tests/test_bounds.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/sklearn/svm/tests/test_bounds.py b/sklearn/svm/tests/test_bounds.py index 23d6be2f44e98..d51865717e2fa 100644 --- a/sklearn/svm/tests/test_bounds.py +++ b/sklearn/svm/tests/test_bounds.py @@ -72,13 +72,24 @@ def test_ill_posed_min_c(): _MAX_UNSIGNED_INT = 4294967295 -@pytest.mark.parametrize("seed, val", [(None, 81), (0, 54), (_MAX_UNSIGNED_INT, 9)]) -def test_newrand_set_seed(seed, val): +def test_newrand_default(): + """Test that bounded_rand_int_wrap without seeding respects the range + + Note this test should pass either if executed alone, or in conjunctions + with other tests that call set_seed explicit in any order: it checks + invariants on the RNG instead of specific values. + """ + generated = [bounded_rand_int_wrap(100) for _ in range(10)] + assert all(0 <= x < 100 for x in generated) + assert not all(x == generated[0] for x in generated) + + +@pytest.mark.parametrize("seed, expected", [(0, 54), (_MAX_UNSIGNED_INT, 9)]) +def test_newrand_set_seed(seed, expected): """Test that `set_seed` produces deterministic results""" - if seed is not None: - set_seed_wrap(seed) - x = bounded_rand_int_wrap(100) - assert x == val, f"Expected {val} but got {x} instead" + set_seed_wrap(seed) + generated = bounded_rand_int_wrap(100) + assert generated == expected @pytest.mark.parametrize("seed", [-1, _MAX_UNSIGNED_INT + 1]) @@ -91,6 +102,9 @@ def test_newrand_set_seed_overflow(seed): @pytest.mark.parametrize("range_, n_pts", [(_MAX_UNSIGNED_INT, 10000), (100, 25)]) def test_newrand_bounded_rand_int(range_, n_pts): """Test that `bounded_rand_int` follows a uniform distribution""" + # XXX: this test is very seed sensitive: either it is wrong (too strict?) + # or the wrapped RNG is not uniform enough, at least on some platforms. + set_seed_wrap(42) n_iter = 100 ks_pvals = [] uniform_dist = stats.uniform(loc=0, scale=range_) From a27437e1bd633dfe1878be6f0a36680f9a9d0d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Wed, 22 Mar 2023 16:30:19 +0100 Subject: [PATCH 089/230] MAINT Clean-up deprecated max_features="auto" in trees/forests/gb (#25941) --- sklearn/ensemble/_base.py | 15 ------- sklearn/ensemble/_forest.py | 44 +------------------ sklearn/ensemble/_gb.py | 6 +-- sklearn/ensemble/tests/test_forest.py | 29 ------------ .../ensemble/tests/test_gradient_boosting.py | 10 ++--- sklearn/tree/_classes.py | 22 +--------- sklearn/tree/tests/test_tree.py | 33 -------------- 7 files changed, 8 insertions(+), 151 deletions(-) diff --git a/sklearn/ensemble/_base.py b/sklearn/ensemble/_base.py index 5ee48b5645a64..fa1041799afcf 100644 --- a/sklearn/ensemble/_base.py +++ b/sklearn/ensemble/_base.py @@ -15,11 +15,6 @@ from ..base import is_classifier, is_regressor from ..base import BaseEstimator from ..base import MetaEstimatorMixin -from ..tree import ( - DecisionTreeRegressor, - BaseDecisionTree, - DecisionTreeClassifier, -) from ..utils import Bunch, _print_elapsed_time, deprecated from ..utils import check_random_state from ..utils.metaestimators import _BaseComposition @@ -192,16 +187,6 @@ def _make_estimator(self, append=True, random_state=None): estimator = clone(self.estimator_) estimator.set_params(**{p: getattr(self, p) for p in self.estimator_params}) - # TODO(1.3): Remove - # max_features = 'auto' would cause warnings in every call to - # Tree.fit(..) - if isinstance(estimator, BaseDecisionTree): - if getattr(estimator, "max_features", None) == "auto": - if isinstance(estimator, DecisionTreeClassifier): - estimator.set_params(max_features="sqrt") - elif isinstance(estimator, DecisionTreeRegressor): - estimator.set_params(max_features=1.0) - if random_state is not None: _set_random_states(estimator, random_state) diff --git a/sklearn/ensemble/_forest.py b/sklearn/ensemble/_forest.py index c33d833aeb95f..19203da4fce1f 100644 --- a/sklearn/ensemble/_forest.py +++ b/sklearn/ensemble/_forest.py @@ -408,28 +408,6 @@ def fit(self, X, y, sample_weight=None): n_samples_bootstrap = None self._validate_estimator() - if isinstance(self, (RandomForestRegressor, ExtraTreesRegressor)): - # TODO(1.3): Remove "auto" - if self.max_features == "auto": - warn( - "`max_features='auto'` has been deprecated in 1.1 " - "and will be removed in 1.3. To keep the past behaviour, " - "explicitly set `max_features=1.0` or remove this " - "parameter as it is also the default value for " - "RandomForestRegressors and ExtraTreesRegressors.", - FutureWarning, - ) - elif isinstance(self, (RandomForestClassifier, ExtraTreesClassifier)): - # TODO(1.3): Remove "auto" - if self.max_features == "auto": - warn( - "`max_features='auto'` has been deprecated in 1.1 " - "and will be removed in 1.3. To keep the past behaviour, " - "explicitly set `max_features='sqrt'` or remove this " - "parameter as it is also the default value for " - "RandomForestClassifiers and ExtraTreesClassifiers.", - FutureWarning, - ) if not self.bootstrap and self.oob_score: raise ValueError("Out of bag estimation only available if bootstrap=True") @@ -1172,7 +1150,6 @@ class RandomForestClassifier(ForestClassifier): - If float, then `max_features` is a fraction and `max(1, int(max_features * n_features_in_))` features are considered at each split. - - If "auto", then `max_features=sqrt(n_features)`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None, then `max_features=n_features`. @@ -1180,10 +1157,6 @@ class RandomForestClassifier(ForestClassifier): .. versionchanged:: 1.1 The default of `max_features` changed from `"auto"` to `"sqrt"`. - .. deprecated:: 1.1 - The `"auto"` option was deprecated in 1.1 and will be removed - in 1.3. - Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than ``max_features`` features. @@ -1547,7 +1520,6 @@ class RandomForestRegressor(ForestRegressor): - If float, then `max_features` is a fraction and `max(1, int(max_features * n_features_in_))` features are considered at each split. - - If "auto", then `max_features=n_features`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None or 1.0, then `max_features=n_features`. @@ -1559,10 +1531,6 @@ class RandomForestRegressor(ForestRegressor): .. versionchanged:: 1.1 The default of `max_features` changed from `"auto"` to 1.0. - .. deprecated:: 1.1 - The `"auto"` option was deprecated in 1.1 and will be removed - in 1.3. - Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than ``max_features`` features. @@ -1716,7 +1684,7 @@ class RandomForestRegressor(ForestRegressor): search of the best split. To obtain a deterministic behaviour during fitting, ``random_state`` has to be fixed. - The default value ``max_features="auto"`` uses ``n_features`` + The default value ``max_features=1.0`` uses ``n_features`` rather than ``n_features / 3``. The latter was originally suggested in [1], whereas the former was more recently justified empirically in [2]. @@ -1871,7 +1839,6 @@ class ExtraTreesClassifier(ForestClassifier): - If float, then `max_features` is a fraction and `max(1, int(max_features * n_features_in_))` features are considered at each split. - - If "auto", then `max_features=sqrt(n_features)`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None, then `max_features=n_features`. @@ -1879,10 +1846,6 @@ class ExtraTreesClassifier(ForestClassifier): .. versionchanged:: 1.1 The default of `max_features` changed from `"auto"` to `"sqrt"`. - .. deprecated:: 1.1 - The `"auto"` option was deprecated in 1.1 and will be removed - in 1.3. - Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than ``max_features`` features. @@ -2237,7 +2200,6 @@ class ExtraTreesRegressor(ForestRegressor): - If float, then `max_features` is a fraction and `max(1, int(max_features * n_features_in_))` features are considered at each split. - - If "auto", then `max_features=n_features`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None or 1.0, then `max_features=n_features`. @@ -2249,10 +2211,6 @@ class ExtraTreesRegressor(ForestRegressor): .. versionchanged:: 1.1 The default of `max_features` changed from `"auto"` to 1.0. - .. deprecated:: 1.1 - The `"auto"` option was deprecated in 1.1 and will be removed - in 1.3. - Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than ``max_features`` features. diff --git a/sklearn/ensemble/_gb.py b/sklearn/ensemble/_gb.py index fff35ab6c33b4..fab8d8710a868 100644 --- a/sklearn/ensemble/_gb.py +++ b/sklearn/ensemble/_gb.py @@ -965,13 +965,12 @@ class GradientBoostingClassifier(ClassifierMixin, BaseGradientBoosting): Pass an int for reproducible output across multiple function calls. See :term:`Glossary `. - max_features : {'auto', 'sqrt', 'log2'}, int or float, default=None + max_features : {'sqrt', 'log2'}, int or float, default=None The number of features to consider when looking for the best split: - If int, values must be in the range `[1, inf)`. - If float, values must be in the range `(0.0, 1.0]` and the features considered at each split will be `max(1, int(max_features * n_features_in_))`. - - If 'auto', then `max_features=sqrt(n_features)`. - If 'sqrt', then `max_features=sqrt(n_features)`. - If 'log2', then `max_features=log2(n_features)`. - If None, then `max_features=n_features`. @@ -1531,13 +1530,12 @@ class GradientBoostingRegressor(RegressorMixin, BaseGradientBoosting): Pass an int for reproducible output across multiple function calls. See :term:`Glossary `. - max_features : {'auto', 'sqrt', 'log2'}, int or float, default=None + max_features : {'sqrt', 'log2'}, int or float, default=None The number of features to consider when looking for the best split: - If int, values must be in the range `[1, inf)`. - If float, values must be in the range `(0.0, 1.0]` and the features considered at each split will be `max(1, int(max_features * n_features_in_))`. - - If "auto", then `max_features=n_features`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None, then `max_features=n_features`. diff --git a/sklearn/ensemble/tests/test_forest.py b/sklearn/ensemble/tests/test_forest.py index f063026a6ba33..9bf0bb2becd9b 100644 --- a/sklearn/ensemble/tests/test_forest.py +++ b/sklearn/ensemble/tests/test_forest.py @@ -1700,35 +1700,6 @@ def test_little_tree_with_small_max_samples(ForestClass): assert tree1.node_count > tree2.node_count, msg -# TODO: Remove in v1.3 -@pytest.mark.parametrize( - "Estimator", - [ - ExtraTreesClassifier, - ExtraTreesRegressor, - RandomForestClassifier, - RandomForestRegressor, - ], -) -def test_max_features_deprecation(Estimator): - """Check warning raised for max_features="auto" deprecation.""" - X = np.array([[1, 2], [3, 4]]) - y = np.array([1, 0]) - est = Estimator(max_features="auto") - - err_msg = ( - r"`max_features='auto'` has been deprecated in 1.1 " - r"and will be removed in 1.3. To keep the past behaviour, " - r"explicitly set `max_features=(1.0|'sqrt')` or remove this " - r"parameter as it is also the default value for RandomForest" - r"(Regressors|Classifiers) and ExtraTrees(Regressors|" - r"Classifiers)\." - ) - - with pytest.warns(FutureWarning, match=err_msg): - est.fit(X, y) - - @pytest.mark.parametrize("Forest", FOREST_REGRESSORS) def test_mse_criterion_object_segfault_smoke_test(Forest): # This is a smoke test to ensure that passing a mutable criterion diff --git a/sklearn/ensemble/tests/test_gradient_boosting.py b/sklearn/ensemble/tests/test_gradient_boosting.py index 3f2a1aae31bcb..ad31b2ed732e9 100644 --- a/sklearn/ensemble/tests/test_gradient_boosting.py +++ b/sklearn/ensemble/tests/test_gradient_boosting.py @@ -345,9 +345,7 @@ def test_feature_importance_regression( assert set(sorted_features[1:4]) == {"Longitude", "AveOccup", "Latitude"} -# TODO(1.3): Remove warning filter -@pytest.mark.filterwarnings("ignore:`max_features='auto'` has been deprecated in 1.1") -def test_max_feature_auto(): +def test_max_features(): # Test if max features is set properly for floats and str. X, y = datasets.make_hastie_10_2(n_samples=12000, random_state=1) _, n_features = X.shape @@ -355,11 +353,11 @@ def test_max_feature_auto(): X_train = X[:2000] y_train = y[:2000] - gbrt = GradientBoostingClassifier(n_estimators=1, max_features="auto") + gbrt = GradientBoostingClassifier(n_estimators=1, max_features=None) gbrt.fit(X_train, y_train) - assert gbrt.max_features_ == int(np.sqrt(n_features)) + assert gbrt.max_features_ == n_features - gbrt = GradientBoostingRegressor(n_estimators=1, max_features="auto") + gbrt = GradientBoostingRegressor(n_estimators=1, max_features=None) gbrt.fit(X_train, y_train) assert gbrt.max_features_ == n_features diff --git a/sklearn/tree/_classes.py b/sklearn/tree/_classes.py index e0e341d9a89f6..b175275ea92dc 100644 --- a/sklearn/tree/_classes.py +++ b/sklearn/tree/_classes.py @@ -110,7 +110,7 @@ class BaseDecisionTree(MultiOutputMixin, BaseEstimator, metaclass=ABCMeta): "max_features": [ Interval(Integral, 1, None, closed="left"), Interval(RealNotInt, 0.0, 1.0, closed="right"), - StrOptions({"auto", "sqrt", "log2"}, deprecated={"auto"}), + StrOptions({"sqrt", "log2"}), None, ], "random_state": ["random_state"], @@ -653,15 +653,10 @@ class DecisionTreeClassifier(ClassifierMixin, BaseDecisionTree): - If float, then `max_features` is a fraction and `max(1, int(max_features * n_features_in_))` features are considered at each split. - - If "auto", then `max_features=sqrt(n_features)`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None, then `max_features=n_features`. - .. deprecated:: 1.1 - The `"auto"` option was deprecated in 1.1 and will be removed - in 1.3. - Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than ``max_features`` features. @@ -1047,15 +1042,10 @@ class DecisionTreeRegressor(RegressorMixin, BaseDecisionTree): - If float, then `max_features` is a fraction and `max(1, int(max_features * n_features_in_))` features are considered at each split. - - If "auto", then `max_features=n_features`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None, then `max_features=n_features`. - .. deprecated:: 1.1 - The `"auto"` option was deprecated in 1.1 and will be removed - in 1.3. - Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than ``max_features`` features. @@ -1350,7 +1340,6 @@ class ExtraTreeClassifier(DecisionTreeClassifier): - If float, then `max_features` is a fraction and `max(1, int(max_features * n_features_in_))` features are considered at each split. - - If "auto", then `max_features=sqrt(n_features)`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None, then `max_features=n_features`. @@ -1358,10 +1347,6 @@ class ExtraTreeClassifier(DecisionTreeClassifier): .. versionchanged:: 1.1 The default of `max_features` changed from `"auto"` to `"sqrt"`. - .. deprecated:: 1.1 - The `"auto"` option was deprecated in 1.1 and will be removed - in 1.3. - Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than ``max_features`` features. @@ -1620,7 +1605,6 @@ class ExtraTreeRegressor(DecisionTreeRegressor): - If float, then `max_features` is a fraction and `max(1, int(max_features * n_features_in_))` features are considered at each split. - - If "auto", then `max_features=n_features`. - If "sqrt", then `max_features=sqrt(n_features)`. - If "log2", then `max_features=log2(n_features)`. - If None, then `max_features=n_features`. @@ -1628,10 +1612,6 @@ class ExtraTreeRegressor(DecisionTreeRegressor): .. versionchanged:: 1.1 The default of `max_features` changed from `"auto"` to `1.0`. - .. deprecated:: 1.1 - The `"auto"` option was deprecated in 1.1 and will be removed - in 1.3. - Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than ``max_features`` features. diff --git a/sklearn/tree/tests/test_tree.py b/sklearn/tree/tests/test_tree.py index c796177ad814c..1f3a9bf394b9b 100644 --- a/sklearn/tree/tests/test_tree.py +++ b/sklearn/tree/tests/test_tree.py @@ -503,20 +503,8 @@ def test_importances_gini_equal_squared_error(): assert_array_equal(clf.tree_.n_node_samples, reg.tree_.n_node_samples) -# TODO(1.3): Remove warning filter -@pytest.mark.filterwarnings("ignore:`max_features='auto'` has been deprecated in 1.1") def test_max_features(): # Check max_features. - for name, TreeRegressor in REG_TREES.items(): - reg = TreeRegressor(max_features="auto") - reg.fit(diabetes.data, diabetes.target) - assert reg.max_features_ == diabetes.data.shape[1] - - for name, TreeClassifier in CLF_TREES.items(): - clf = TreeClassifier(max_features="auto") - clf.fit(iris.data, iris.target) - assert clf.max_features_ == 2 - for name, TreeEstimator in ALL_TREES.items(): est = TreeEstimator(max_features="sqrt") est.fit(iris.data, iris.target) @@ -2369,27 +2357,6 @@ def test_check_node_ndarray(): _check_node_ndarray(problematic_node_ndarray, expected_dtype=expected_dtype) -# TODO(1.3): Remove -def test_max_features_auto_deprecated(): - for Tree in CLF_TREES.values(): - tree = Tree(max_features="auto") - msg = ( - "`max_features='auto'` has been deprecated in 1.1 and will be removed in" - " 1.3. To keep the past behaviour, explicitly set `max_features='sqrt'`." - ) - with pytest.warns(FutureWarning, match=msg): - tree.fit(X, y) - - for Tree in REG_TREES.values(): - tree = Tree(max_features="auto") - msg = ( - "`max_features='auto'` has been deprecated in 1.1 and will be removed in" - " 1.3. To keep the past behaviour, explicitly set `max_features=1.0'`." - ) - with pytest.warns(FutureWarning, match=msg): - tree.fit(X, y) - - @pytest.mark.parametrize( "Splitter", chain(DENSE_SPLITTERS.values(), SPARSE_SPLITTERS.values()) ) From fde42238a22ab111a0a323db96f8112cbcc81f04 Mon Sep 17 00:00:00 2001 From: Joey Ortiz Date: Wed, 22 Mar 2023 09:14:06 -0700 Subject: [PATCH 090/230] MAINT LogisticRegression informative error msg when penaly=elasticnet and l1_ratio is None (#25925) Co-authored-by: jeremiedbb --- sklearn/linear_model/_logistic.py | 3 +++ sklearn/linear_model/tests/test_logistic.py | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/sklearn/linear_model/_logistic.py b/sklearn/linear_model/_logistic.py index 6680d60cb4b1c..3390c4adf000b 100644 --- a/sklearn/linear_model/_logistic.py +++ b/sklearn/linear_model/_logistic.py @@ -1168,6 +1168,9 @@ def fit(self, X, y, sample_weight=None): "(penalty={})".format(self.penalty) ) + if self.penalty == "elasticnet" and self.l1_ratio is None: + raise ValueError("l1_ratio must be specified when penalty is elasticnet.") + # TODO(1.4): Remove "none" option if self.penalty == "none": warnings.warn( diff --git a/sklearn/linear_model/tests/test_logistic.py b/sklearn/linear_model/tests/test_logistic.py index 4353ba2388014..c3f439bd4f150 100644 --- a/sklearn/linear_model/tests/test_logistic.py +++ b/sklearn/linear_model/tests/test_logistic.py @@ -227,6 +227,15 @@ def test_check_solver_option(LR): lr.fit(X, y) +@pytest.mark.parametrize("LR", [LogisticRegression, LogisticRegressionCV]) +def test_elasticnet_l1_ratio_err_helpful(LR): + # Check that an informative error message is raised when penalty="elasticnet" + # but l1_ratio is not specified. + model = LR(penalty="elasticnet", solver="saga") + with pytest.raises(ValueError, match=r".*l1_ratio.*"): + model.fit(np.array([[1, 2], [3, 4]]), np.array([0, 1])) + + @pytest.mark.parametrize("solver", ["lbfgs", "newton-cg", "sag", "saga"]) def test_multinomial_binary(solver): # Test multinomial LR on a binary problem. From 564d35f9f6cfad9a4123d1952a8dcb7de59c1ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Wed, 22 Mar 2023 17:37:13 +0100 Subject: [PATCH 091/230] MAINT Clean-up remaining SGDClassifier(loss="log") (#25938) --- benchmarks/bench_rcv1_logreg_convergence.py | 2 +- sklearn/linear_model/_logistic.py | 2 +- sklearn/tests/test_multioutput.py | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/benchmarks/bench_rcv1_logreg_convergence.py b/benchmarks/bench_rcv1_logreg_convergence.py index e8fce1c414abf..2254ab81f30a4 100644 --- a/benchmarks/bench_rcv1_logreg_convergence.py +++ b/benchmarks/bench_rcv1_logreg_convergence.py @@ -240,7 +240,7 @@ def get_max_squared_sum(X): SGDClassifier( alpha=1.0 / C / n_samples, penalty="l2", - loss="log", + loss="log_loss", fit_intercept=fit_intercept, verbose=0, ), diff --git a/sklearn/linear_model/_logistic.py b/sklearn/linear_model/_logistic.py index 3390c4adf000b..861e716a531d9 100644 --- a/sklearn/linear_model/_logistic.py +++ b/sklearn/linear_model/_logistic.py @@ -1013,7 +1013,7 @@ class LogisticRegression(LinearClassifierMixin, SparseCoefMixin, BaseEstimator): See Also -------- SGDClassifier : Incrementally trained logistic regression (when given - the parameter ``loss="log"``). + the parameter ``loss="log_loss"``). LogisticRegressionCV : Logistic regression with built-in cross validation. Notes diff --git a/sklearn/tests/test_multioutput.py b/sklearn/tests/test_multioutput.py index ad95282fa6614..371c516f197c5 100644 --- a/sklearn/tests/test_multioutput.py +++ b/sklearn/tests/test_multioutput.py @@ -202,8 +202,8 @@ def test_hasattr_multi_output_predict_proba(): # check predict_proba passes def test_multi_output_predict_proba(): - sgd_linear_clf = SGDClassifier(random_state=1, max_iter=5, loss="log_loss") - param = {"loss": ("hinge", "log", "modified_huber")} + sgd_linear_clf = SGDClassifier(random_state=1, max_iter=5) + param = {"loss": ("hinge", "log_loss", "modified_huber")} # inner function for custom scoring def custom_scorer(estimator, X, y): @@ -213,7 +213,11 @@ def custom_scorer(estimator, X, y): return 0.0 grid_clf = GridSearchCV( - sgd_linear_clf, param_grid=param, scoring=custom_scorer, cv=3 + sgd_linear_clf, + param_grid=param, + scoring=custom_scorer, + cv=3, + error_score="raise", ) multi_target_linear = MultiOutputClassifier(grid_clf) multi_target_linear.fit(X, y) From f3cf046f74df81a9ad24dd5c9d1965964387e80b Mon Sep 17 00:00:00 2001 From: "Thomas J. Fan" Date: Wed, 22 Mar 2023 12:41:32 -0400 Subject: [PATCH 092/230] FIX Fixes pandas extension arrays in check_array (#25813) --- doc/whats_new/v1.3.rst | 3 +++ sklearn/preprocessing/tests/test_label.py | 8 ++++++-- sklearn/utils/tests/test_validation.py | 19 +++++++++++++++++++ sklearn/utils/validation.py | 13 ++++++++++++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 99cbaadf9b76a..7f8dd00fe2d7c 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -407,6 +407,9 @@ Changelog :pr:`25733` by :user:`Brigitta SipÅ‘cz ` and :user:`Jérémie du Boisberranger `. +- |FIX| Fixes :func:`utils.validation.check_array` to properly convert pandas + extension arrays. :pr:`25813` by `Thomas Fan`_. + :mod:`sklearn.semi_supervised` .............................. diff --git a/sklearn/preprocessing/tests/test_label.py b/sklearn/preprocessing/tests/test_label.py index b90218a97016b..d8566c85e7b73 100644 --- a/sklearn/preprocessing/tests/test_label.py +++ b/sklearn/preprocessing/tests/test_label.py @@ -118,15 +118,19 @@ def test_label_binarizer_set_label_encoding(): @pytest.mark.parametrize("dtype", ["Int64", "Float64", "boolean"]) -def test_label_binarizer_pandas_nullable(dtype): +@pytest.mark.parametrize("unique_first", [True, False]) +def test_label_binarizer_pandas_nullable(dtype, unique_first): """Checks that LabelBinarizer works with pandas nullable dtypes. Non-regression test for gh-25637. """ pd = pytest.importorskip("pandas") - from sklearn.preprocessing import LabelBinarizer y_true = pd.Series([1, 0, 0, 1, 0, 1, 1, 0, 1], dtype=dtype) + if unique_first: + # Calling unique creates a pandas array which has a different interface + # compared to a pandas Series. Specifically, pandas arrays do not have "iloc". + y_true = y_true.unique() lb = LabelBinarizer().fit(y_true) y_out = lb.transform([1, 0]) diff --git a/sklearn/utils/tests/test_validation.py b/sklearn/utils/tests/test_validation.py index 5c9379facf366..028a5ee3042bf 100644 --- a/sklearn/utils/tests/test_validation.py +++ b/sklearn/utils/tests/test_validation.py @@ -1762,6 +1762,25 @@ def test_boolean_series_remains_boolean(): assert_array_equal(res, expected) +@pytest.mark.parametrize("input_values", [[0, 1, 0, 1, 0, np.nan], [0, 1, 0, 1, 0, 1]]) +def test_pandas_array_returns_ndarray(input_values): + """Check pandas array with extensions dtypes returns a numeric ndarray. + + Non-regression test for gh-25637. + """ + pd = importorskip("pandas") + input_series = pd.array(input_values, dtype="Int32") + result = check_array( + input_series, + dtype=None, + ensure_2d=False, + allow_nd=False, + force_all_finite=False, + ) + assert np.issubdtype(result.dtype.kind, np.floating) + assert_allclose(result, input_values) + + @pytest.mark.parametrize("array_namespace", ["numpy.array_api", "cupy.array_api"]) def test_check_array_array_api_has_non_finite(array_namespace): """Checks that Array API arrays checks non-finite correctly.""" diff --git a/sklearn/utils/validation.py b/sklearn/utils/validation.py index eb56caa5e65e4..2d5f323195e97 100644 --- a/sklearn/utils/validation.py +++ b/sklearn/utils/validation.py @@ -626,6 +626,15 @@ def _pandas_dtype_needs_early_conversion(pd_dtype): return False +def _is_extension_array_dtype(array): + try: + from pandas.api.types import is_extension_array_dtype + + return is_extension_array_dtype(array) + except ImportError: + return False + + def check_array( array, accept_sparse=False, @@ -777,7 +786,9 @@ def check_array( if all(isinstance(dtype_iter, np.dtype) for dtype_iter in dtypes_orig): dtype_orig = np.result_type(*dtypes_orig) - elif hasattr(array, "iloc") and hasattr(array, "dtype"): + elif (_is_extension_array_dtype(array) or hasattr(array, "iloc")) and hasattr( + array, "dtype" + ): # array is a pandas series pandas_requires_conversion = _pandas_dtype_needs_early_conversion(array.dtype) if isinstance(array.dtype, np.dtype): From 9a8defd279335834d33e7a5743447758223ade4d Mon Sep 17 00:00:00 2001 From: "Thomas J. Fan" Date: Wed, 22 Mar 2023 14:31:29 -0400 Subject: [PATCH 093/230] FIX Fixes pandas extension arrays with objects in check_array (#25814) --- doc/whats_new/v1.3.rst | 4 ++++ sklearn/utils/tests/test_validation.py | 31 ++++++++++++++++++++++++++ sklearn/utils/validation.py | 3 +++ 3 files changed, 38 insertions(+) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 7f8dd00fe2d7c..c50672a712f93 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -410,6 +410,10 @@ Changelog - |FIX| Fixes :func:`utils.validation.check_array` to properly convert pandas extension arrays. :pr:`25813` by `Thomas Fan`_. +- |Fix| :func:`utils.validation.check_array` now suports pandas DataFrames with + extension arrays and object dtypes by return an ndarray with object dtype. + :pr:`25814` by `Thomas Fan`_. + :mod:`sklearn.semi_supervised` .............................. diff --git a/sklearn/utils/tests/test_validation.py b/sklearn/utils/tests/test_validation.py index 028a5ee3042bf..ca522af287513 100644 --- a/sklearn/utils/tests/test_validation.py +++ b/sklearn/utils/tests/test_validation.py @@ -1795,3 +1795,34 @@ def test_check_array_array_api_has_non_finite(array_namespace): with config_context(array_api_dispatch=True): with pytest.raises(ValueError, match="infinity or a value too large"): check_array(X_inf) + + +@pytest.mark.parametrize( + "extension_dtype, regular_dtype", + [ + ("boolean", "bool"), + ("Int64", "int64"), + ("Float64", "float64"), + ("category", "object"), + ], +) +@pytest.mark.parametrize("include_object", [True, False]) +def test_check_array_multiple_extensions( + extension_dtype, regular_dtype, include_object +): + """Check pandas extension arrays give the same result as non-extension arrays.""" + pd = pytest.importorskip("pandas") + X_regular = pd.DataFrame( + { + "a": pd.Series([1, 0, 1, 0], dtype=regular_dtype), + "c": pd.Series([9, 8, 7, 6], dtype="int64"), + } + ) + if include_object: + X_regular["b"] = pd.Series(["a", "b", "c", "d"], dtype="object") + + X_extension = X_regular.assign(a=X_regular["a"].astype(extension_dtype)) + + X_regular_checked = check_array(X_regular, dtype=None) + X_extension_checked = check_array(X_extension, dtype=None) + assert_array_equal(X_regular_checked, X_extension_checked) diff --git a/sklearn/utils/validation.py b/sklearn/utils/validation.py index 2d5f323195e97..e8978a086d001 100644 --- a/sklearn/utils/validation.py +++ b/sklearn/utils/validation.py @@ -785,6 +785,9 @@ def check_array( ) if all(isinstance(dtype_iter, np.dtype) for dtype_iter in dtypes_orig): dtype_orig = np.result_type(*dtypes_orig) + elif pandas_requires_conversion and any(d == object for d in dtypes_orig): + # Force object if any of the dtypes is an object + dtype_orig = object elif (_is_extension_array_dtype(array) or hasattr(array, "iloc")) and hasattr( array, "dtype" From 078d8ec9f387f0a6709b58186348b30aa7131585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Thu, 23 Mar 2023 11:10:00 +0100 Subject: [PATCH 094/230] CI Disable pytest-xdist in pylatest_pip_openblas_pandas build (#25943) --- azure-pipelines.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index af25f0e09862f..66e00ee54b07d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -199,6 +199,10 @@ jobs: CHECK_PYTEST_SOFT_DEPENDENCY: 'true' CHECK_WARNINGS: 'true' SKLEARN_TESTS_GLOBAL_RANDOM_SEED: '3' # non-default seed + # disable pytest-xdist to have 1 job where OpenMP and BLAS are not single + # threaded because by default the tests configuration (sklearn/conftest.py) + # makes sure that they are single threaded in each xdist subprocess. + PYTEST_XDIST_VERSION: 'none' - template: build_tools/azure/posix-docker.yml parameters: From d795e2461f13841fb6853671e2ccd5ab4377b4b3 Mon Sep 17 00:00:00 2001 From: Guillaume Lemaitre Date: Thu, 23 Mar 2023 15:13:48 +0100 Subject: [PATCH 095/230] MAINT remove deprecated call to resources.content (#25951) --- sklearn/datasets/_base.py | 5 ++--- sklearn/utils/fixes.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sklearn/datasets/_base.py b/sklearn/datasets/_base.py index 902deae119c48..6331582cffb4a 100644 --- a/sklearn/datasets/_base.py +++ b/sklearn/datasets/_base.py @@ -14,14 +14,13 @@ import os from os import environ, listdir, makedirs from os.path import expanduser, isdir, join, splitext -from importlib import resources from pathlib import Path from ..preprocessing import scale from ..utils import Bunch from ..utils import check_random_state from ..utils import check_pandas_support -from ..utils.fixes import _open_binary, _open_text, _read_text +from ..utils.fixes import _open_binary, _open_text, _read_text, _contents import numpy as np @@ -1216,7 +1215,7 @@ def load_sample_images(): descr = load_descr("README.txt", descr_module=IMAGES_MODULE) filenames, images = [], [] - for filename in sorted(resources.contents(IMAGES_MODULE)): + for filename in sorted(_contents(IMAGES_MODULE)): if filename.endswith(".jpg"): filenames.append(filename) with _open_binary(IMAGES_MODULE, filename) as image_file: diff --git a/sklearn/utils/fixes.py b/sklearn/utils/fixes.py index 587a03fadc76d..d3eaf0540d7ab 100644 --- a/sklearn/utils/fixes.py +++ b/sklearn/utils/fixes.py @@ -215,3 +215,14 @@ def _is_resource(data_module, data_file_name): return resources.files(data_module).joinpath(data_file_name).is_file() else: return resources.is_resource(data_module, data_file_name) + + +def _contents(data_module): + if sys.version_info >= (3, 9): + return ( + resource.name + for resource in resources.files(data_module).iterdir() + if resource.is_file() + ) + else: + return resources.contents(data_module) From bb8573ce55ac43e46ecdeeefe2a12d201a579656 Mon Sep 17 00:00:00 2001 From: Christian Lorentzen Date: Thu, 23 Mar 2023 15:49:30 +0100 Subject: [PATCH 096/230] DOC note on calibration impact on ranking (#25900) --- doc/developers/contributing.rst | 2 +- doc/modules/calibration.rst | 93 ++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/doc/developers/contributing.rst b/doc/developers/contributing.rst index 9a3efd3d2c8db..8ff924fa04a9f 100644 --- a/doc/developers/contributing.rst +++ b/doc/developers/contributing.rst @@ -714,7 +714,7 @@ Building the documentation requires installing some additional packages: pip install sphinx sphinx-gallery numpydoc matplotlib Pillow pandas \ scikit-image packaging seaborn sphinx-prompt \ - sphinxext-opengraph plotly + sphinxext-opengraph plotly pooch To build the documentation, you need to be in the ``doc`` folder: diff --git a/doc/modules/calibration.rst b/doc/modules/calibration.rst index e35a4a12cbb8a..081b3e9a0a883 100644 --- a/doc/modules/calibration.rst +++ b/doc/modules/calibration.rst @@ -20,10 +20,24 @@ prediction. Well calibrated classifiers are probabilistic classifiers for which the output of the :term:`predict_proba` method can be directly interpreted as a confidence level. -For instance, a well calibrated (binary) classifier should classify the samples -such that among the samples to which it gave a :term:`predict_proba` value -close to 0.8, -approximately 80% actually belong to the positive class. +For instance, a well calibrated (binary) classifier should classify the samples such +that among the samples to which it gave a :term:`predict_proba` value close to, say, +0.8, approximately 80% actually belong to the positive class. + +Before we show how to re-calibrate a classifier, we first need a way to detect how +good a classifier is calibrated. + +.. note:: + Strictly proper scoring rules for probabilistic predictions like + :func:`sklearn.metrics.brier_score_loss` and + :func:`sklearn.metrics.log_loss` assess calibration (reliability) and + discriminative power (resolution) of a model, as well as the randomness of the data + (uncertainty) at the same time. This follows from the well-known Brier score + decomposition of Murphy [1]_. As it is not clear which term dominates, the score is + of limited use for assessing calibration alone (unless one computes each term of + the decomposition). A lower Brier loss, for instance, does not necessarily + mean a better calibrated model, it could also mean a worse calibrated model with much + more discriminatory power, e.g. using many more features. .. _calibration_curve: @@ -33,7 +47,7 @@ Calibration curves Calibration curves, also referred to as *reliability diagrams* (Wilks 1995 [2]_), compare how well the probabilistic predictions of a binary classifier are calibrated. It plots the frequency of the positive label (to be more precise, an estimation of the -*conditional event probability* :math:`P(Y=1|\text{predict\_proba})`) on the y-axis +*conditional event probability* :math:`P(Y=1|\text{predict_proba})`) on the y-axis against the predicted probability :term:`predict_proba` of a model on the x-axis. The tricky part is to get values for the y-axis. In scikit-learn, this is accomplished by binning the predictions such that the x-axis @@ -62,7 +76,7 @@ by showing the number of samples in each predicted probability bin. :class:`LogisticRegression` returns well calibrated predictions by default as it has a canonical link function for its loss, i.e. the logit-link for the :ref:`log_loss`. -This leads to the so-called **balance property**, see [7]_ and +This leads to the so-called **balance property**, see [8]_ and :ref:`Logistic_regression`. In contrast to that, the other shown models return biased probabilities; with different biases per model. @@ -79,7 +93,7 @@ case in this dataset which contains 2 redundant features. :class:`RandomForestClassifier` shows the opposite behavior: the histograms show peaks at probabilities approximately 0.2 and 0.9, while probabilities close to 0 or 1 are very rare. An explanation for this is given by -Niculescu-Mizil and Caruana [1]_: "Methods such as bagging and random +Niculescu-Mizil and Caruana [3]_: "Methods such as bagging and random forests that average predictions from a base set of models can have difficulty making predictions near 0 and 1 because variance in the underlying base models will bias predictions that should be near zero or one @@ -99,7 +113,7 @@ to 0 or 1 typically. .. currentmodule:: sklearn.svm :class:`LinearSVC` (SVC) shows an even more sigmoid curve than the random forest, which -is typical for maximum-margin methods (compare Niculescu-Mizil and Caruana [1]_), which +is typical for maximum-margin methods (compare Niculescu-Mizil and Caruana [3]_), which focus on difficult to classify samples that are close to the decision boundary (the support vectors). @@ -167,29 +181,18 @@ fit the regressor. It is up to the user to make sure that the data used for fitting the classifier is disjoint from the data used for fitting the regressor. -:func:`sklearn.metrics.brier_score_loss` may be used to assess how -well a classifier is calibrated. However, this metric should be used with care -because a lower Brier score does not always mean a better calibrated model. -This is because the Brier score metric is a combination of calibration loss -and refinement loss. Calibration loss is defined as the mean squared deviation -from empirical probabilities derived from the slope of ROC segments. -Refinement loss can be defined as the expected optimal loss as measured by the -area under the optimal cost curve. As refinement loss can change -independently from calibration loss, a lower Brier score does not necessarily -mean a better calibrated model. - -:class:`CalibratedClassifierCV` supports the use of two 'calibration' -regressors: 'sigmoid' and 'isotonic'. +:class:`CalibratedClassifierCV` supports the use of two regression techniques +for calibration via the `method` parameter: `"sigmoid"` and `"isotonic"`. .. _sigmoid_regressor: Sigmoid ^^^^^^^ -The sigmoid regressor is based on Platt's logistic model [3]_: +The sigmoid regressor, `method="sigmoid"` is based on Platt's logistic model [4]_: .. math:: - p(y_i = 1 | f_i) = \frac{1}{1 + \exp(A f_i + B)} + p(y_i = 1 | f_i) = \frac{1}{1 + \exp(A f_i + B)} \,, where :math:`y_i` is the true label of sample :math:`i` and :math:`f_i` is the output of the un-calibrated classifier for sample :math:`i`. :math:`A` @@ -200,10 +203,10 @@ The sigmoid method assumes the :ref:`calibration curve ` can be corrected by applying a sigmoid function to the raw predictions. This assumption has been empirically justified in the case of :ref:`svm` with common kernel functions on various benchmark datasets in section 2.1 of Platt -1999 [3]_ but does not necessarily hold in general. Additionally, the +1999 [4]_ but does not necessarily hold in general. Additionally, the logistic model works best if the calibration error is symmetrical, meaning the classifier output for each binary class is normally distributed with -the same variance [6]_. This can be a problem for highly imbalanced +the same variance [7]_. This can be a problem for highly imbalanced classification problems, where outputs do not have equal variance. In general this method is most effective for small sample sizes or when the @@ -213,7 +216,7 @@ high and low outputs. Isotonic ^^^^^^^^ -The 'isotonic' method fits a non-parametric isotonic regressor, which outputs +The `method="isotonic"` fits a non-parametric isotonic regressor, which outputs a step-wise non-decreasing function, see :mod:`sklearn.isotonic`. It minimizes: .. math:: @@ -226,10 +229,20 @@ calibrated classifier for sample :math:`i` (i.e., the calibrated probability). This method is more general when compared to 'sigmoid' as the only restriction is that the mapping function is monotonically increasing. It is thus more powerful as it can correct any monotonic distortion of the un-calibrated model. -However, it is more prone to overfitting, especially on small datasets [5]_. +However, it is more prone to overfitting, especially on small datasets [6]_. Overall, 'isotonic' will perform as well as or better than 'sigmoid' when -there is enough data (greater than ~ 1000 samples) to avoid overfitting [1]_. +there is enough data (greater than ~ 1000 samples) to avoid overfitting [3]_. + +.. note:: Impact on ranking metrics like AUC + + It is generally expected that calibration does not affect ranking metrics such as + ROC-AUC. However, these metrics might differ after calibration when using + `method="isotonic"` since isotonic regression introduces ties in the predicted + probabilities. This can be seen as within the uncertainty of the model predictions. + In case, you strictly want to keep the ranking and thus AUC scores, use + `method="logistic"` which is a strictly monotonic transformation and thus keeps + the ranking. Multiclass support ^^^^^^^^^^^^^^^^^^ @@ -239,7 +252,7 @@ support 1-dimensional data (e.g., binary classification output) but are extended for multiclass classification if the `base_estimator` supports multiclass predictions. For multiclass predictions, :class:`CalibratedClassifierCV` calibrates for -each class separately in a :ref:`ovr_classification` fashion [4]_. When +each class separately in a :ref:`ovr_classification` fashion [5]_. When predicting probabilities, the calibrated probabilities for each class are predicted separately. As those probabilities do not necessarily sum to @@ -254,36 +267,42 @@ one, a postprocessing is performed to normalize them. .. topic:: References: - .. [1] `Predicting Good Probabilities with Supervised Learning - `_, - A. Niculescu-Mizil & R. Caruana, ICML 2005 + .. [1] Allan H. Murphy (1973). + :doi:`"A New Vector Partition of the Probability Score" + <10.1175/1520-0450(1973)012%3C0595:ANVPOT%3E2.0.CO;2>` + Journal of Applied Meteorology and Climatology .. [2] `On the combination of forecast probabilities for consecutive precipitation periods. `_ Wea. Forecasting, 5, 640–650., Wilks, D. S., 1990a - .. [3] `Probabilistic Outputs for Support Vector Machines and Comparisons + .. [3] `Predicting Good Probabilities with Supervised Learning + `_, + A. Niculescu-Mizil & R. Caruana, ICML 2005 + + + .. [4] `Probabilistic Outputs for Support Vector Machines and Comparisons to Regularized Likelihood Methods. `_ J. Platt, (1999) - .. [4] `Transforming Classifier Scores into Accurate Multiclass + .. [5] `Transforming Classifier Scores into Accurate Multiclass Probability Estimates. `_ B. Zadrozny & C. Elkan, (KDD 2002) - .. [5] `Predicting accurate probabilities with a ranking loss. + .. [6] `Predicting accurate probabilities with a ranking loss. `_ Menon AK, Jiang XJ, Vembu S, Elkan C, Ohno-Machado L. Proc Int Conf Mach Learn. 2012;2012:703-710 - .. [6] `Beyond sigmoids: How to obtain well-calibrated probabilities from + .. [7] `Beyond sigmoids: How to obtain well-calibrated probabilities from binary classifiers with beta calibration `_ Kull, M., Silva Filho, T. M., & Flach, P. (2017). - .. [7] Mario V. Wüthrich, Michael Merz (2023). + .. [8] Mario V. Wüthrich, Michael Merz (2023). :doi:`"Statistical Foundations of Actuarial Learning and its Applications" <10.1007/978-3-031-12409-9>` Springer Actuarial From 0ab0661658c35da7b5a1104b3fb05990a20f188a Mon Sep 17 00:00:00 2001 From: Tim Head Date: Thu, 23 Mar 2023 16:52:14 +0100 Subject: [PATCH 097/230] Remove loguniform fix, use scipy.stats instead (#24665) Co-authored-by: Olivier Grisel --- README.rst | 2 +- azure-pipelines.yml | 21 ++++++-- ...38_conda_defaults_openblas_environment.yml | 2 +- ...onda_defaults_openblas_linux-64_conda.lock | 4 +- .../py38_conda_forge_mkl_win-64_conda.lock | 4 +- ...e_openblas_ubuntu_2204_linux-64_conda.lock | 22 +++++---- ...latest_conda_forge_mkl_linux-64_conda.lock | 22 +++++---- ..._forge_mkl_no_coverage_linux-64_conda.lock | 22 +++++---- ...pylatest_conda_forge_mkl_osx-64_conda.lock | 14 +++--- ...st_pip_openblas_pandas_linux-64_conda.lock | 4 +- ...pylatest_pip_scipy_dev_linux-64_conda.lock | 12 ++--- build_tools/azure/pypy3_linux-64_conda.lock | 6 +-- build_tools/azure/ubuntu_atlas_lock.txt | 2 +- build_tools/circle/doc_linux-64_conda.lock | 22 +++++---- .../doc_min_dependencies_environment.yml | 2 +- .../doc_min_dependencies_linux-64_conda.lock | 8 +-- .../py39_conda_forge_linux-aarch64_conda.lock | 6 +-- .../update_environments_and_lock_files.py | 6 +-- doc/install.rst | 5 -- doc/modules/grid_search.rst | 11 ++--- .../applications/plot_face_recognition.py | 2 +- .../gaussian_process/plot_compare_gpr_krr.py | 2 +- .../model_selection/plot_randomized_search.py | 3 +- pyproject.toml | 2 +- sklearn/_min_dependencies.py | 2 +- sklearn/utils/fixes.py | 49 ------------------- sklearn/utils/tests/test_fixes.py | 27 +--------- 27 files changed, 109 insertions(+), 175 deletions(-) diff --git a/README.rst b/README.rst index 108cb331821cd..5e2de6a6d8b46 100644 --- a/README.rst +++ b/README.rst @@ -34,7 +34,7 @@ .. |PythonMinVersion| replace:: 3.8 .. |NumPyMinVersion| replace:: 1.17.3 -.. |SciPyMinVersion| replace:: 1.3.2 +.. |SciPyMinVersion| replace:: 1.5.0 .. |JoblibMinVersion| replace:: 1.1.1 .. |ThreadpoolctlMinVersion| replace:: 2.0.0 .. |MatplotlibMinVersion| replace:: 3.1.3 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 66e00ee54b07d..0ba11773a978d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -166,8 +166,8 @@ jobs: - template: build_tools/azure/posix.yml parameters: - name: Linux - vmImage: ubuntu-20.04 + name: Ubuntu_Atlas + vmImage: ubuntu-22.04 dependsOn: [linting, git_commit, Ubuntu_Jammy_Jellyfish] # Runs when dependencies succeeded or skipped condition: | @@ -177,13 +177,26 @@ jobs: ) matrix: # Linux environment to test that scikit-learn can be built against - # versions of numpy, scipy with ATLAS that comes with Ubuntu Focal 20.04 - # i.e. numpy 1.17.4 and scipy 1.3.3 + # versions of numpy, scipy with ATLAS that comes with Ubuntu Jammy Jellyfish 22.04 + # i.e. numpy 1.21.5 and scipy 1.8.0 ubuntu_atlas: DISTRIB: 'ubuntu' LOCK_FILE: './build_tools/azure/ubuntu_atlas_lock.txt' COVERAGE: 'false' SKLEARN_TESTS_GLOBAL_RANDOM_SEED: '1' # non-default seed + +- template: build_tools/azure/posix.yml + parameters: + name: Linux + vmImage: ubuntu-20.04 + dependsOn: [linting, git_commit, Ubuntu_Jammy_Jellyfish] + # Runs when dependencies succeeded or skipped + condition: | + and( + not(or(failed(), canceled())), + not(contains(dependencies['git_commit']['outputs']['commit.message'], '[ci skip]')) + ) + matrix: # Linux + Python 3.8 build with OpenBLAS py38_conda_defaults_openblas: DISTRIB: 'conda' diff --git a/build_tools/azure/py38_conda_defaults_openblas_environment.yml b/build_tools/azure/py38_conda_defaults_openblas_environment.yml index 68d860e720830..2d5b657e91e40 100644 --- a/build_tools/azure/py38_conda_defaults_openblas_environment.yml +++ b/build_tools/azure/py38_conda_defaults_openblas_environment.yml @@ -7,7 +7,7 @@ dependencies: - python=3.8 - numpy=1.17.3 # min - blas[build=openblas] - - scipy=1.3.2 # min + - scipy=1.5.0 # min - joblib - threadpoolctl=2.2.0 - matplotlib=3.1.3 # min diff --git a/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock b/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock index b19ba3b8133eb..347c649583c23 100644 --- a/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock +++ b/build_tools/azure/py38_conda_defaults_openblas_linux-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: b2abf7313453f4c215a430bad6b188860065331448105408976274d4b5370848 +# input_hash: 76d585ef182a71dd7720b12def6ce000de54a0d8dbf575b74d82033ad81e8cc2 @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 https://repo.anaconda.com/pkgs/main/linux-64/blas-1.0-openblas.conda#9ddfcaef10d79366c90128f5dc444be8 @@ -92,7 +92,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/pyqt5-sip-12.11.0-py38h6a678d5_1.co https://repo.anaconda.com/pkgs/main/noarch/pytest-cov-3.0.0-pyhd3eb1b0_0.conda#bbdaac2947f507399816d509107945c2 https://repo.anaconda.com/pkgs/main/noarch/pytest-forked-1.3.0-pyhd3eb1b0_0.tar.bz2#07970bffdc78f417d7f8f1c7e620f5c4 https://repo.anaconda.com/pkgs/main/linux-64/qtwebkit-5.212-h4eab89a_4.conda#7317bbf3f3e66a0a02b07b860783ecff -https://repo.anaconda.com/pkgs/main/linux-64/scipy-1.3.2-py38he2b7bc3_0.conda#a9df91d5a41c1f39524fc8a53c56bc29 +https://repo.anaconda.com/pkgs/main/linux-64/scipy-1.5.0-py38habc2bb6_0.conda#a27a97fc2377ab74cbd33ce22d3c3353 https://repo.anaconda.com/pkgs/main/linux-64/pyamg-4.2.3-py38h79cecc1_0.conda#6e7f4f94000b244396de8bf4e6ae8dc4 https://repo.anaconda.com/pkgs/main/linux-64/pyqt-5.15.7-py38h6a678d5_1.conda#62232dc285be8e7e85ae9596d89b3b95 https://repo.anaconda.com/pkgs/main/noarch/pytest-xdist-2.5.0-pyhd3eb1b0_0.conda#d15cdc4207bcf8ca920822597f1d138d diff --git a/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock b/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock index b60485a906c33..943acaf0c109a 100644 --- a/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock +++ b/build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock @@ -37,7 +37,7 @@ https://conda.anaconda.org/conda-forge/win-64/libbrotlienc-1.0.9-hcfcfb64_8.tar. https://conda.anaconda.org/conda-forge/win-64/libclang13-15.0.7-default_h77d9078_1.conda#799890c6c093e7a64ea0dcb3d4f90115 https://conda.anaconda.org/conda-forge/win-64/libpng-1.6.39-h19919ed_0.conda#ab6febdb2dbd9c00803609079db4de71 https://conda.anaconda.org/conda-forge/win-64/libvorbis-1.3.7-h0e60522_0.tar.bz2#e1a22282de0169c93e4ffe6ce6acc212 -https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.3-hc3477c8_3.conda#1f37656230ab24d79970fe82594440f2 +https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.3-hc3477c8_6.conda#a56f8a52bc13d7eee23457f0e253e055 https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2#fe759119b8b3bfa720b8762c6fdc35de https://conda.anaconda.org/conda-forge/win-64/pcre2-10.40-h17e33f8_0.tar.bz2#2519de0d9620dc2bc7e19caf6867136d https://conda.anaconda.org/conda-forge/win-64/python-3.8.16-h4de0772_1_cpython.conda#461d9fc92cfde68f2ca7ef0988f6326a @@ -122,7 +122,7 @@ https://conda.anaconda.org/conda-forge/win-64/qt-main-5.15.8-h88fe7eb_7.conda#e3 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/win-64/blas-devel-3.9.0-16_win64_mkl.tar.bz2#dc89c75a7dd26c88ac77d64bf313973e https://conda.anaconda.org/conda-forge/win-64/contourpy-1.0.7-py38hb1fd069_0.conda#6b53200dddcec578cdd90cac146eeadd -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/win-64/pyqt-5.15.7-py38hd6c051e_3.conda#9b17c0bbf19c6e265c3967e33df8770a https://conda.anaconda.org/conda-forge/win-64/blas-2.116-mkl.tar.bz2#7529860b43278247a278c6f56a191d2e https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.7.1-py38h528a6c7_0.conda#0aebccad15d74ec7f1bc3d62497ad1a8 diff --git a/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock b/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock index c2596de2a0b43..f58766eb24f76 100644 --- a/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock +++ b/build_tools/azure/py38_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock @@ -41,7 +41,6 @@ https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2# https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a6416_3.tar.bz2#8c5963a49b6035c40646a763293fbb35 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_0.conda#6c2addbd9aa4ee47c76d50c9f0df8cd6 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 @@ -66,7 +65,7 @@ https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.22-h11f4161_0.conda#504 https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.tar.bz2#04bac51ba35ea023dc48af73c1c88c25 -https://conda.anaconda.org/conda-forge/linux-64/libcap-2.66-ha37c62d_0.tar.bz2#2d7665abd0997f1a6d4b7596bc27b657 +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.67-he9d0100_0.conda#d05556c80caffff164d17bdea0105a1a https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.10-h28343ad_4.tar.bz2#4a049fc560e00e43151dc51368915fdd https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.2-h27087fc_0.tar.bz2#7daf72d8e2a8e848e11d63ed6d1026e0 @@ -75,17 +74,17 @@ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_3.conda#29474f139e5017090f218ef6b3753efd -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_4.conda#bb808b654bdc3c783deaf107a2ffb503 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_1.conda#2c18a7a26ec0d0c23a917f37a65fc9a2 https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.21-pthreads_h320a7e8_3.tar.bz2#29155b9196b9d78022f11d86733e25a7 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b -https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa +https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 -https://conda.anaconda.org/conda-forge/linux-64/ccache-4.7.3-h2599c5e_0.tar.bz2#4feea9466084c6948bd59539f1c0bb72 +https://conda.anaconda.org/conda-forge/linux-64/ccache-4.8-hfcdc2af_0.conda#3ee0c6924765807b9ab785377a130c4d https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a41adce7106749573d883b2f657d78 https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openblas.tar.bz2#20bae26d0a1db73f758fc3754cab4719 @@ -95,9 +94,10 @@ https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openb https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_1.conda#17d91085ccf5934ce652cb448d0cb65a https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_1.conda#bb38b19a41bb94e8a19dbfb062d499c7 https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_1.conda#a69fa6f218cfed8e2d61753eeacaf034 https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.8.16-he550d4f_1_cpython.conda#9de84cccfbc5f8350a3667bb6ef6fc30 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 @@ -125,7 +125,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d5 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c9f4416a34bc91e0eb029f912c68f81f https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_openblas.tar.bz2#823ceb5567e1a595deb643fcd17aed5a https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc -https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-253-h8c4010b_1.conda#9176b1e2cb8beca37a7510b0e801e38f https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.2-py38h10c12cc_0.conda#05592c85b9f6931dc2df1e80c0d56294 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea @@ -159,7 +159,7 @@ https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.12.0-pyhd8ed https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py38h961100d_2.conda#26a5eb5d9f097e5011d54aa5cc1571c8 -https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-ha8d29e2_1.conda#dbfc2a8d63a43a11acf4c704e1ef9d0c +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-16.1-h5195f5e_3.conda#caeb3302ef1dc8b342b20c710a86f8a9 https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.7-py38h8dc9893_0.conda#ea242937718f3dacf253355e1d634535 @@ -172,10 +172,12 @@ https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-6.0.0-h8e241bc_0.conda# https://conda.anaconda.org/conda-forge/noarch/importlib-resources-5.12.0-pyhd8ed1ab_0.conda#3544c818f0720c89eb16ae6940ab440b https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.3-py38hdc8b05c_0.conda#5073966d63a54434d2a2fc41d325b072 https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-daemon-16.1-ha8d29e2_3.conda#34d9d75ca896f5919c372a34e25f23ea https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py38h8dc9893_3.conda#7bb0328b4a0f857aeb432426b9a5f908 https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0_2.conda#0d0c6604c8ac4ad5e51efa7bb58da05c https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py38hd6c3c57_0.conda#3b8ba76acae09fbd4b2247c4ee4c0324 +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-hcb278e6_3.conda#8b452ab959166d91949af4c2d28f81db https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h67dfc38_7.conda#f140acdc15a0196eef664f120c396266 @@ -183,6 +185,6 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py38ha0d8c90_3.conda#e965dc172d67920d058ac2b3a0e27565 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py38h578d9bd_0.conda#50ff9e0a3dd459a0ca365741072bf9a2 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py38h10c12cc_0.conda#1cbc47bb9a600ce4a49d8da797d375bf https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py38h507a481_2.conda#8b7ce7db24bbe8f2f230b6b0523dde50 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock index b5a6711268661..f3b23884d3746 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock @@ -42,7 +42,6 @@ https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2# https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_0.conda#6c2addbd9aa4ee47c76d50c9f0df8cd6 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 @@ -66,7 +65,7 @@ https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161 https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.22-h11f4161_0.conda#504fa9e712b99494a9cf4630e3ca7d78 https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.tar.bz2#04bac51ba35ea023dc48af73c1c88c25 -https://conda.anaconda.org/conda-forge/linux-64/libcap-2.66-ha37c62d_0.tar.bz2#2d7665abd0997f1a6d4b7596bc27b657 +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.67-he9d0100_0.conda#d05556c80caffff164d17bdea0105a1a https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.10-h28343ad_4.tar.bz2#4a049fc560e00e43151dc51368915fdd https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.2-h27087fc_0.tar.bz2#7daf72d8e2a8e848e11d63ed6d1026e0 @@ -75,16 +74,16 @@ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_3.conda#29474f139e5017090f218ef6b3753efd -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_4.conda#bb808b654bdc3c783deaf107a2ffb503 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_1.conda#2c18a7a26ec0d0c23a917f37a65fc9a2 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b -https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa +https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 -https://conda.anaconda.org/conda-forge/linux-64/ccache-4.7.3-h2599c5e_0.tar.bz2#4feea9466084c6948bd59539f1c0bb72 +https://conda.anaconda.org/conda-forge/linux-64/ccache-4.8-hfcdc2af_0.conda#3ee0c6924765807b9ab785377a130c4d https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a41adce7106749573d883b2f657d78 https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.1-h166bdaf_0.tar.bz2#f967fc95089cd247ceed56eda31de3a9 @@ -93,9 +92,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.0-hd6dc26d_0.conda# https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_1.conda#17d91085ccf5934ce652cb448d0cb65a https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_1.conda#bb38b19a41bb94e8a19dbfb062d499c7 https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_1.conda#a69fa6f218cfed8e2d61753eeacaf034 https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-he550d4f_1_cpython.conda#8d14fc2aa12db370a443753c8230be1e https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 @@ -122,7 +122,7 @@ https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_1.conda#a3a0f7a6f0885f5e1e0ec691566afb77 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c9f4416a34bc91e0eb029f912c68f81f https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc -https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-253-h8c4010b_1.conda#9176b1e2cb8beca37a7510b0e801e38f https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b @@ -153,7 +153,7 @@ https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2# https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d https://conda.anaconda.org/conda-forge/linux-64/mkl-2022.1.0-h84fe81f_915.tar.bz2#b9c8f925797a93dbff45e1626b025a6b https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py311h573f0d3_2.conda#7321881b545202cf9ab8bd24b4151dcb -https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-ha8d29e2_1.conda#dbfc2a8d63a43a11acf4c704e1ef9d0c +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-16.1-h5195f5e_3.conda#caeb3302ef1dc8b342b20c710a86f8a9 https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.7-py311hcafe171_0.conda#cf1adb3a0138cca4bbab415ddf2f57f1 @@ -165,12 +165,14 @@ https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-6.0.0-h8e241bc_0.conda# https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_mkl.tar.bz2#85f61af03fd291dae33150ffe89dc09a https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2022.1.0-ha770c72_916.tar.bz2#69ba49e445f87aea2cba343a71a35ca2 https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-daemon-16.1-ha8d29e2_3.conda#34d9d75ca896f5919c372a34e25f23ea https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py311hcafe171_3.conda#0d79df2a96f6572fed2883374400b235 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.0.0-pyhd8ed1ab_0.tar.bz2#c9e3f8bfdb9bfc34aa1836a6ed4b25d7 https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0_2.conda#0d0c6604c8ac4ad5e51efa7bb58da05c https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_mkl.tar.bz2#361bf757b95488de76c4f123805742d3 https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_mkl.tar.bz2#a2f166748917d6d6e4707841ca1f519e +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-hcb278e6_3.conda#8b452ab959166d91949af4c2d28f81db https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_mkl.tar.bz2#44ccc4d4dca6a8d57fa17442bc64b5a1 @@ -184,7 +186,7 @@ https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py311ha74522f_3.cond https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-mkl.tar.bz2#c196a26abf6b4f132c88828ab7c2231c https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py311h8597a09_0.conda#70c3b734ffe82c16b6d121aaa11929a8 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py311h38be061_0.conda#8fd462c8bcbba5a3affcb2d04e387476 https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py311h8e6699e_0.conda#a9dba1242a54275e4914a2540f4eb233 https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py311hcb41070_2.conda#bcf32a1a23df6e4ae047f90d401b7517 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock index 0865c9331c5e7..f014e94c80691 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_no_coverage_linux-64_conda.lock @@ -42,7 +42,6 @@ https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2# https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_0.conda#6c2addbd9aa4ee47c76d50c9f0df8cd6 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 @@ -66,7 +65,7 @@ https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161 https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.22-h11f4161_0.conda#504fa9e712b99494a9cf4630e3ca7d78 https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.tar.bz2#04bac51ba35ea023dc48af73c1c88c25 -https://conda.anaconda.org/conda-forge/linux-64/libcap-2.66-ha37c62d_0.tar.bz2#2d7665abd0997f1a6d4b7596bc27b657 +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.67-he9d0100_0.conda#d05556c80caffff164d17bdea0105a1a https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.10-h28343ad_4.tar.bz2#4a049fc560e00e43151dc51368915fdd https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.2-h27087fc_0.tar.bz2#7daf72d8e2a8e848e11d63ed6d1026e0 @@ -75,16 +74,16 @@ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_3.conda#29474f139e5017090f218ef6b3753efd -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_4.conda#bb808b654bdc3c783deaf107a2ffb503 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_1.conda#2c18a7a26ec0d0c23a917f37a65fc9a2 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b -https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa +https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 -https://conda.anaconda.org/conda-forge/linux-64/ccache-4.7.3-h2599c5e_0.tar.bz2#4feea9466084c6948bd59539f1c0bb72 +https://conda.anaconda.org/conda-forge/linux-64/ccache-4.8-hfcdc2af_0.conda#3ee0c6924765807b9ab785377a130c4d https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a41adce7106749573d883b2f657d78 https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.1-h166bdaf_0.tar.bz2#f967fc95089cd247ceed56eda31de3a9 @@ -93,9 +92,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.0-hd6dc26d_0.conda# https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_1.conda#17d91085ccf5934ce652cb448d0cb65a https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_1.conda#bb38b19a41bb94e8a19dbfb062d499c7 https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_1.conda#a69fa6f218cfed8e2d61753eeacaf034 https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-he550d4f_1_cpython.conda#8d14fc2aa12db370a443753c8230be1e https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 @@ -122,7 +122,7 @@ https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h3e3d535_1.conda#a3a0f7a6f0885f5e1e0ec691566afb77 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c9f4416a34bc91e0eb029f912c68f81f https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc -https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-253-h8c4010b_1.conda#9176b1e2cb8beca37a7510b0e801e38f https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea https://conda.anaconda.org/conda-forge/noarch/packaging-23.0-pyhd8ed1ab_0.conda#1ff2e3ca41f0ce16afec7190db28288b @@ -152,7 +152,7 @@ https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2# https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_had23c3d_1.conda#36c65ed73b7c92589bd9562ef8a6023d https://conda.anaconda.org/conda-forge/linux-64/mkl-2022.1.0-h84fe81f_915.tar.bz2#b9c8f925797a93dbff45e1626b025a6b https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py311h573f0d3_2.conda#7321881b545202cf9ab8bd24b4151dcb -https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-ha8d29e2_1.conda#dbfc2a8d63a43a11acf4c704e1ef9d0c +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-16.1-h5195f5e_3.conda#caeb3302ef1dc8b342b20c710a86f8a9 https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.7-py311hcafe171_0.conda#cf1adb3a0138cca4bbab415ddf2f57f1 @@ -164,11 +164,13 @@ https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-6.0.0-h8e241bc_0.conda# https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_mkl.tar.bz2#85f61af03fd291dae33150ffe89dc09a https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2022.1.0-ha770c72_916.tar.bz2#69ba49e445f87aea2cba343a71a35ca2 https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-daemon-16.1-ha8d29e2_3.conda#34d9d75ca896f5919c372a34e25f23ea https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py311hcafe171_3.conda#0d79df2a96f6572fed2883374400b235 https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0_2.conda#0d0c6604c8ac4ad5e51efa7bb58da05c https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_mkl.tar.bz2#361bf757b95488de76c4f123805742d3 https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_mkl.tar.bz2#a2f166748917d6d6e4707841ca1f519e +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-hcb278e6_3.conda#8b452ab959166d91949af4c2d28f81db https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_mkl.tar.bz2#44ccc4d4dca6a8d57fa17442bc64b5a1 @@ -182,7 +184,7 @@ https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py311ha74522f_3.cond https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-mkl.tar.bz2#c196a26abf6b4f132c88828ab7c2231c https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py311h8597a09_0.conda#70c3b734ffe82c16b6d121aaa11929a8 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py311h38be061_0.conda#8fd462c8bcbba5a3affcb2d04e387476 https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py311h8e6699e_0.conda#a9dba1242a54275e4914a2540f4eb233 https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py311hcb41070_2.conda#bcf32a1a23df6e4ae047f90d401b7517 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock index bbffdb910ed00..eadd0bc912743 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock @@ -33,7 +33,7 @@ https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.39-ha978bb4_0.conda#35e https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_0.tar.bz2#ceb13b6726534b96e3b4e3dda91e9050 https://conda.anaconda.org/conda-forge/osx-64/libxcb-1.13-h0d85af4_1004.tar.bz2#eb7860935e14aec936065cbc21a1a962 https://conda.anaconda.org/conda-forge/osx-64/openssl-3.1.0-hfd90126_0.conda#a7df3470c748a517663bf095c2ac0235 -https://conda.anaconda.org/conda-forge/osx-64/readline-8.1.2-h3899abd_0.tar.bz2#89fa404901fa8fb7d4f4e07083b8d635 +https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda#f17f77f2acf4d344734bda76829ce14e https://conda.anaconda.org/conda-forge/osx-64/tapi-1100.0.11-h9ce4665_0.tar.bz2#f9ff42ccf809a21ba6f8607f8de36108 https://conda.anaconda.org/conda-forge/osx-64/tbb-2021.8.0-hb8565cd_0.conda#17cc6d45a28433867fc74bf67c3d5459 https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.12-h5dbffcc_0.tar.bz2#8e9480d9c47061db2ed1b4ecce519a7f @@ -63,7 +63,7 @@ https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#3427 https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.4-py311hd2070f0_1.tar.bz2#5219e72a43e53e8f6af4fdf76a0f90ef https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.15-h2dcdeff_1.conda#f1df9b0c2d9fbe985e62f4b24773a9e4 -https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-609-hfd63004_12.conda#a906b0296ce3ef06fe49ae5f3a0bc2ba +https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-609-hfd63004_13.conda#58fcda6a84fb42f51c6c2d6d175b435d https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-16_osx64_mkl.tar.bz2#96b23c2ca3208c5cb1ed34270448af5c https://conda.anaconda.org/conda-forge/osx-64/libhiredis-1.0.2-h2beb688_0.tar.bz2#524282b2c46c9dedf051b3bc2ae05494 https://conda.anaconda.org/conda-forge/osx-64/mkl-devel-2022.1.0-h694c41f_929.tar.bz2#041ceef009fe6d29cbd2555907c23ab3 @@ -84,15 +84,15 @@ https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 https://conda.anaconda.org/conda-forge/osx-64/tornado-6.2-py311h5547dcb_1.tar.bz2#bc9918caedfa2de9e582104bf605d57d https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.5.0-pyha770c72_0.conda#43e7d9e50261fb11deb76e17d8431aac -https://conda.anaconda.org/conda-forge/osx-64/ccache-4.7.3-h2822714_0.tar.bz2#a119676fd25b0268da665107f7176ec6 -https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-973.0.1-hcc6d90d_12.conda#5e2c08283fa0292e0e40776a2b9ebb1c +https://conda.anaconda.org/conda-forge/osx-64/ccache-4.8-h2822714_0.conda#49faf2a66ad44fd6628ae03a69d1046b +https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-973.0.1-hcc6d90d_13.conda#76e5fa849e2042cd657d9eec96095680 https://conda.anaconda.org/conda-forge/osx-64/cffi-1.15.1-py311ha86e640_3.conda#5967be4da33261eada7cc79593f71088 https://conda.anaconda.org/conda-forge/osx-64/clang-14.0.6-h694c41f_0.tar.bz2#77667c3c75b88f12782f628d171ffeda https://conda.anaconda.org/conda-forge/osx-64/coverage-7.2.2-py311h5547dcb_0.conda#912eec0baf21527e058cff24f2bc6794 https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.39.2-py311h5547dcb_0.conda#b108bcc7df5a90356ca9934261d84536 https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-11.3.0-h1f927f5_31.conda#926da9259d77f6a95d60c5a956425c2f https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb -https://conda.anaconda.org/conda-forge/osx-64/ld64-609-hc6ad406_12.conda#5a29a02594a0420c065a9605f9584dff +https://conda.anaconda.org/conda-forge/osx-64/ld64-609-hc6ad406_13.conda#5d7676eee44dfa3e48bf21700e044aa9 https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-16_osx64_mkl.tar.bz2#430c4d18fd8bbc987c4367f5d16135cf https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-16_osx64_mkl.tar.bz2#757f1ae46973ce6542784d99b9984d8d https://conda.anaconda.org/conda-forge/osx-64/pillow-9.4.0-py311hf47c0a6_2.conda#4607ae953e3b427be289048f8314b778 @@ -100,7 +100,7 @@ https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392 https://conda.anaconda.org/conda-forge/osx-64/brotlipy-0.7.0-py311h5547dcb_1005.tar.bz2#5f97ac938a90d06eebea42c321abe0d7 -https://conda.anaconda.org/conda-forge/osx-64/cctools-973.0.1-h76f1dac_12.conda#4ee6ac722f14547eca4e6127fa58c2d2 +https://conda.anaconda.org/conda-forge/osx-64/cctools-973.0.1-h76f1dac_13.conda#802cae917abdc5a7cdfa699ff02da42d https://conda.anaconda.org/conda-forge/osx-64/clangxx-14.0.6-default_h55ffa42_0.tar.bz2#6a46064b0506895d090302433e70397b https://conda.anaconda.org/conda-forge/osx-64/cryptography-39.0.2-py311h61927ef_0.conda#46ed09cb9666419cc7f3547ecb03037f https://conda.anaconda.org/conda-forge/osx-64/liblapacke-3.9.0-16_osx64_mkl.tar.bz2#ba52eebcca282a5abaa3d3ac79cf2b05 @@ -124,7 +124,7 @@ https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.5.2-hbf74d83_0.conda#c1413ef5a20d658923e12dd3b566d8f3 https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-14.0.6-h6f97653_5.conda#45b992b3f628805b2105868a96e87b20 https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-11.3.0-h18f7dce_1.conda#4e066d81dd3b86556b723021980f4ed8 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.5.2-hb8565cd_0.conda#349ae14723b98f76ea0fcb8e532b2ead https://conda.anaconda.org/conda-forge/osx-64/gfortran-11.3.0-h2c809b3_1.conda#0d856a032891847a9e61dd68149dd889 https://conda.anaconda.org/conda-forge/osx-64/scipy-1.10.1-py311h939689b_0.conda#c0ba4b8d033cd4b2af087ef96e98db04 diff --git a/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock b/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock index 4fade961151a6..bebc0a15a8212 100644 --- a/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock +++ b/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock @@ -63,7 +63,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py39h06a4308_0.conda#8 # pip iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl#sha256=b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # pip joblib @ https://files.pythonhosted.org/packages/91/d4/3b4c8e5a30604df4c7518c562d4bf0502f2fa29221459226e140cf846512/joblib-1.2.0-py3-none-any.whl#sha256=091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385 # pip kiwisolver @ https://files.pythonhosted.org/packages/a4/36/c414d75be311ce97ef7248edcc4fc05afae2998641bf6b592d43a9dee581/kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f -# pip lazy-loader @ https://files.pythonhosted.org/packages/bc/bf/58dbe1f382ecac2c0571c43b6e95028b14e159d67d75e49a00c26ef63d8f/lazy_loader-0.1-py3-none-any.whl#sha256=623bd4831a40ce659d74472af40a58d016f2a5a047685409affbc2ba5c044641 +# pip lazy-loader @ https://files.pythonhosted.org/packages/a1/a8/c41f46b47a381bd60a40c0ef00d2fd1722b743b178f9c1cec0da949043de/lazy_loader-0.2-py3-none-any.whl#sha256=c35875f815c340f823ce3271ed645045397213f961b40ad0c0d395c3f5218eeb # pip networkx @ https://files.pythonhosted.org/packages/11/eb/929b1a04b1778f4dd606c739c93c134306e4a31012e31e184c8308f3d985/networkx-3.0-py3-none-any.whl#sha256=58058d66b1818043527244fab9d41a51fcd7dcc271748015f3c181b8a90c8e2e # pip numpy @ https://files.pythonhosted.org/packages/f4/f4/45e6e3f7a23b9023554903a122c95585e9787f9403d386bafb7a95d24c9b/numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780 # pip pillow @ https://files.pythonhosted.org/packages/f2/cc/71b11ec996744b704637d9ef53ff924b7d208c41be1d251cca33991f6833/Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e @@ -84,7 +84,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py39h06a4308_0.conda#8 # pip pywavelets @ https://files.pythonhosted.org/packages/5a/98/4549479a32972bdfdd5e75e168219e97f4dfaee535a8308efef7291e8398/PyWavelets-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=71ab30f51ee4470741bb55fc6b197b4a2b612232e30f6ac069106f0156342356 # pip scipy @ https://files.pythonhosted.org/packages/5d/30/b2a2a5bf1a3beefb7609fb871dcc6aef7217c69cef19a4631b7ab5622a8a/scipy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601 # pip setuptools-scm @ https://files.pythonhosted.org/packages/1d/66/8f42c941be949ef2b22fe905d850c794e7c170a526023612aad5f3a121ad/setuptools_scm-7.1.0-py3-none-any.whl#sha256=73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e -# pip tifffile @ https://files.pythonhosted.org/packages/87/4d/f4f4834ca37da0f1106fd0437f40931c91c26acba7d2db3535de5cb66649/tifffile-2023.3.15-py3-none-any.whl#sha256=0ad708d0d5a45d068444e9036a20f1f8a237da008e35cc9cbc69bbb5602d6987 +# pip tifffile @ https://files.pythonhosted.org/packages/06/53/e8cd66fbfc121036a6ba2597c139bd25bc5d6cc11c00aee9adb8899e121c/tifffile-2023.3.21-py3-none-any.whl#sha256=b83af3dbe914663aeaf250e9751ae503154f2599dd27ed7a4df1b2dc7c148efa # pip matplotlib @ https://files.pythonhosted.org/packages/9f/77/0cd22f92f7103383cb1ce3b3efc77411b9cc3a495242c8f2a623b498f586/matplotlib-3.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=f883a22a56a84dba3b588696a2b8a1ab0d2c3d41be53264115c71b0a942d8fdb # pip pandas @ https://files.pythonhosted.org/packages/e1/4d/3eb96e53a9208350ee21615f850c4be9a246d32bf1d34cd36682cb58c3b7/pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5 # pip pyamg @ https://files.pythonhosted.org/packages/8e/08/d512b6e34d502152723b5a4ad9d962a6141dfe83cd8bcd01af4cb6e84f28/pyamg-4.2.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=18af99d2551df07951c35cf270dc76703f8c5d30b16ea8e61657fda098f57dd7 diff --git a/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock b/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock index 0f6560ebf94e5..91a65e030c91f 100644 --- a/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock +++ b/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock @@ -42,17 +42,17 @@ https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd3eb1 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-jsmath-1.0.1-pyhd3eb1b0_0.tar.bz2#e43f8de7d6a717935ab220a0c957771d https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-qthelp-1.0.3-pyhd3eb1b0_0.tar.bz2#08d67f73f640b4d1e5e8890a324b60e3 https://repo.anaconda.com/pkgs/main/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd3eb1b0_0.conda#0440b84dfd478f340cf14c2d7c24f6c7 -https://repo.anaconda.com/pkgs/main/noarch/wheel-0.37.1-pyhd3eb1b0_0.conda#ab85e96e26da8d5797c2458232338b86 +https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.38.4-py311h06a4308_0.conda#b3d14884810655c572ea9a91df7de205 https://repo.anaconda.com/pkgs/main/linux-64/babel-2.11.0-py311h06a4308_0.conda#b0e1c6be7b334706670ed7d203b61775 https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.15.1-py311h5eee18b_3.conda#82ea1fb8934a7e4b93298cdee7d7628d https://repo.anaconda.com/pkgs/main/linux-64/jinja2-3.1.2-py311h06a4308_0.conda#1173c148bd36cfc89283992fb37ef859 -https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.5.0-py311h06a4308_0.conda#64fe3e2957dfdb50f32450a9aa6e5346 +https://repo.anaconda.com/pkgs/main/linux-64/setuptools-65.6.3-py311h06a4308_0.conda#a8c4e794496c77ff7f0e53c23db9c3a6 https://repo.anaconda.com/pkgs/main/linux-64/brotlipy-0.7.0-py311h5eee18b_1002.conda#d0decdefee9dcf89dcbaad2ffd30b830 -https://repo.anaconda.com/pkgs/main/linux-64/cryptography-38.0.4-py311hbdeaff8_0.conda#b6f1d8d13930d292b38dbb0f00e64f27 -https://repo.anaconda.com/pkgs/main/linux-64/pip-22.3.1-py311h06a4308_0.conda#352428d11ace1b907a0d1933cb21d070 +https://repo.anaconda.com/pkgs/main/linux-64/cryptography-39.0.1-py311h9ce1e76_0.conda#16bea2216f03f039e182fd62fd53d51c +https://repo.anaconda.com/pkgs/main/linux-64/pip-23.0.1-py311h06a4308_0.conda#06ec6690fc9814ab769a62dfeeb26419 https://repo.anaconda.com/pkgs/main/linux-64/pyopenssl-23.0.0-py311h06a4308_0.conda#3ba9d6d2f74e89aa80e5bae3966f3a43 -https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.12-py311h06a4308_0.conda#80cbf014853f8260fedb33b362f1013b -https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py311h06a4308_0.conda#cb7be2752ad61f1049f3eff471218ed5 +https://repo.anaconda.com/pkgs/main/linux-64/urllib3-1.26.14-py311h06a4308_0.conda#cdaf74fa5fd5a72e563f0025ba75ac2c +https://repo.anaconda.com/pkgs/main/linux-64/requests-2.28.1-py311h06a4308_1.conda#deca44a599adac76faf50691fd19ec5d https://repo.anaconda.com/pkgs/main/linux-64/sphinx-5.0.2-py311h06a4308_0.conda#ed071b775d26745823d958bf3751b044 # pip attrs @ https://files.pythonhosted.org/packages/fb/6e/6f83bf616d2becdf333a1640f1d463fef3150e2e926b7010cb0f81c95e88/attrs-22.2.0-py3-none-any.whl#sha256=29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 # pip coverage @ https://files.pythonhosted.org/packages/d0/94/fa6095cce802c11a53685c5267330caed7ef02e2fb99b9f9f1c892859259/coverage-7.2.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=006ed5582e9cbc8115d2e22d6d2144a0725db542f654d9d4fda86793832f873d diff --git a/build_tools/azure/pypy3_linux-64_conda.lock b/build_tools/azure/pypy3_linux-64_conda.lock index 64b81a86da124..c73800254aa2b 100644 --- a/build_tools/azure/pypy3_linux-64_conda.lock +++ b/build_tools/azure/pypy3_linux-64_conda.lock @@ -35,12 +35,12 @@ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.21-pthreads_h320a7e8_3.tar.bz2#29155b9196b9d78022f11d86733e25a7 -https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa +https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_8.tar.bz2#e5613f2bc717e9945840ff474419b8e4 -https://conda.anaconda.org/conda-forge/linux-64/ccache-4.7.3-h2599c5e_0.tar.bz2#4feea9466084c6948bd59539f1c0bb72 +https://conda.anaconda.org/conda-forge/linux-64/ccache-4.8-hfcdc2af_0.conda#3ee0c6924765807b9ab785377a130c4d https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_1.conda#e1232042de76d24539a436d37597eb06 https://conda.anaconda.org/conda-forge/linux-64/gdbm-1.18-h0a1914f_2.tar.bz2#b77bc399b07a19c00fe12fdc95ee0297 https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openblas.tar.bz2#20bae26d0a1db73f758fc3754cab4719 @@ -104,6 +104,6 @@ https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.ta https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py39h4162558_0.conda#b6ca076a90a7f2a8d7ff976d243dd4c5 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py39h60c9533_0.conda#5ffadbb1f4fa2758c57ec1579bc3e953 https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py39hcf8a7be_2.conda#f7a209fe66831b3e3d216b90c2fc9d8a diff --git a/build_tools/azure/ubuntu_atlas_lock.txt b/build_tools/azure/ubuntu_atlas_lock.txt index e5233159eb8b6..a78d3f597ac02 100644 --- a/build_tools/azure/ubuntu_atlas_lock.txt +++ b/build_tools/azure/ubuntu_atlas_lock.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.8 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --output-file=build_tools/azure/ubuntu_atlas_lock.txt build_tools/azure/ubuntu_atlas_requirements.txt diff --git a/build_tools/circle/doc_linux-64_conda.lock b/build_tools/circle/doc_linux-64_conda.lock index b05253a984141..1b44a49ab03ac 100644 --- a/build_tools/circle/doc_linux-64_conda.lock +++ b/build_tools/circle/doc_linux-64_conda.lock @@ -58,7 +58,6 @@ https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-11.3.0-h239ccf8_19.tar.bz2#d17fd55aed84ab6592c5419b6600501c https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_0.conda#6c2addbd9aa4ee47c76d50c9f0df8cd6 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.0-h0b41bf4_0.conda#0d4a7508d8c6c65314f2b9c1f56ad408 https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-h166bdaf_4.tar.bz2#f3f9de449d32ca9b9c66a22863c96f41 @@ -90,7 +89,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libavif-0.11.1-h5cdd6b5_0.tar.bz https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.tar.bz2#04bac51ba35ea023dc48af73c1c88c25 -https://conda.anaconda.org/conda-forge/linux-64/libcap-2.66-ha37c62d_0.tar.bz2#2d7665abd0997f1a6d4b7596bc27b657 +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.67-he9d0100_0.conda#d05556c80caffff164d17bdea0105a1a https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.10-h28343ad_4.tar.bz2#4a049fc560e00e43151dc51368915fdd https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.2-h27087fc_0.tar.bz2#7daf72d8e2a8e848e11d63ed6d1026e0 @@ -101,11 +100,11 @@ https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar. https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-hf14f497_3.tar.bz2#d85acad4b47dff4e3def14a769a97906 https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_3.conda#29474f139e5017090f218ef6b3753efd -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_0.conda#6a39818710235826181e104aada40c75 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-hca2bb57_4.conda#bb808b654bdc3c783deaf107a2ffb503 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.32-ha901b37_1.conda#2c18a7a26ec0d0c23a917f37a65fc9a2 https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.21-pthreads_h320a7e8_3.tar.bz2#29155b9196b9d78022f11d86733e25a7 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b -https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa +https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 @@ -126,9 +125,10 @@ https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openb https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hadd5161_1.conda#17d91085ccf5934ce652cb448d0cb65a https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.0-hb75c966_0.conda#c648d19cd9c8625898d5d370414de7c7 https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.0-hddfeb54_5.conda#d2343e6594c2a4a654a475a6131ef20d +https://conda.anaconda.org/conda-forge/linux-64/libudev1-253-h0b41bf4_1.conda#bb38b19a41bb94e8a19dbfb062d499c7 https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.5.0-h79f4944_1.conda#04a39cdd663f295653fc143851830563 https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-16.0.0-h417c0b6_0.conda#8ac4c157172ea816f5c9a0dc33df69d8 -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_0.conda#b05d7ea8b76f1172d5fe4f30e03277ea +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.32-hd7da12d_1.conda#a69fa6f218cfed8e2d61753eeacaf034 https://conda.anaconda.org/conda-forge/linux-64/nss-3.89-he45b914_0.conda#2745719a58eeaab6657256a3f142f099 https://conda.anaconda.org/conda-forge/linux-64/python-3.9.16-h2782a2a_0_cpython.conda#95c9b7c96a7fd7342e0c9d0a917b8f78 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 @@ -168,7 +168,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h36d4200_3.conda#c https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.88.1-hdc1c0ab_1.conda#3d1189864d1c0ed2a5919cb067b5903d https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_openblas.tar.bz2#823ceb5567e1a595deb643fcd17aed5a https://conda.anaconda.org/conda-forge/linux-64/libpq-15.2-hb675445_0.conda#4654b17eccaba55b8581d6b9c77f53cc -https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-252-h2a991cd_0.tar.bz2#3c5ae9f61f663b3d5e1bf7f7da0c85f5 +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-253-h8c4010b_1.conda#9176b1e2cb8beca37a7510b0e801e38f https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.2-py39h72bdee0_0.conda#35514f5320206df9f4661c138c02e1c1 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 @@ -229,7 +229,7 @@ https://conda.anaconda.org/conda-forge/noarch/partd-1.3.0-pyhd8ed1ab_0.tar.bz2#a https://conda.anaconda.org/conda-forge/linux-64/pillow-9.4.0-py39h7207d5c_2.conda#58d50d33cf1abe2055d2a1c90c7179a5 https://conda.anaconda.org/conda-forge/noarch/pip-23.0.1-pyhd8ed1ab_0.conda#8025ca83b8ba5430b640b83917c2a6f7 https://conda.anaconda.org/conda-forge/noarch/plotly-5.13.1-pyhd8ed1ab_0.conda#761501a3de96c5855d840f4287a65e77 -https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-ha8d29e2_1.conda#dbfc2a8d63a43a11acf4c704e1ef9d0c +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-16.1-h5195f5e_3.conda#caeb3302ef1dc8b342b20c710a86f8a9 https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1 https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.2-pyhd8ed1ab_0.conda#60958b19354e0ec295b43f6ab5cfab86 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 @@ -248,19 +248,21 @@ https://conda.anaconda.org/conda-forge/noarch/imageio-2.26.0-pyh24c5eb1_0.conda# https://conda.anaconda.org/conda-forge/noarch/importlib-resources-5.12.0-pyhd8ed1ab_0.conda#3544c818f0720c89eb16ae6940ab440b https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.3-py39h2ad29b5_0.conda#3ea96adbbc2a66fa45178102a9cfbecc https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.1.1-pyhd8ed1ab_0.conda#1d1a27f637808c76dd83e3f469aa6f7e +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-daemon-16.1-ha8d29e2_3.conda#34d9d75ca896f5919c372a34e25f23ea https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py39h227be39_3.conda#9e381db00691e26bcf670c3586397be1 https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.6.0-pyhd8ed1ab_0.conda#a46947638b6e005b63d2d6271da529b0 https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.0-h4243ec0_2.conda#0d0c6604c8ac4ad5e51efa7bb58da05c https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.7.1-py39he190548_0.conda#f2a931db797bb58bd335f4a857b4c898 +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-16.1-hcb278e6_3.conda#8b452ab959166d91949af4c2d28f81db https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e -https://conda.anaconda.org/conda-forge/noarch/tifffile-2023.3.15-pyhd8ed1ab_0.conda#da45d6cc28eac10485aef68c9b0a1e5a +https://conda.anaconda.org/conda-forge/noarch/tifffile-2023.3.21-pyhd8ed1ab_0.conda#46b79291d783ae327ffcaa342e8d7571 https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h67dfc38_7.conda#f140acdc15a0196eef664f120c396266 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py39h5c7b992_3.conda#19e30314fe824605750da905febb8ee6 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.7.1-py39hf3d152e_0.conda#682772fa385911fb5efffbce21b269c5 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/noarch/sphinx-6.0.0-pyhd8ed1ab_2.conda#ac1d3b55da1669ee3a56973054fd7efb https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.5.0-pyhd8ed1ab_0.tar.bz2#3c275d7168a6a135329f4acb364c229a https://conda.anaconda.org/conda-forge/linux-64/scipy-1.10.1-py39h7360e5f_0.conda#7584d1bc5499d25eccfd24a7f656e3ee diff --git a/build_tools/circle/doc_min_dependencies_environment.yml b/build_tools/circle/doc_min_dependencies_environment.yml index 4667fb1fa74cc..930634b5091c6 100644 --- a/build_tools/circle/doc_min_dependencies_environment.yml +++ b/build_tools/circle/doc_min_dependencies_environment.yml @@ -7,7 +7,7 @@ dependencies: - python=3.8 - numpy=1.17.3 # min - blas - - scipy=1.3.2 # min + - scipy=1.5.0 # min - cython=0.29.33 # min - joblib - threadpoolctl diff --git a/build_tools/circle/doc_min_dependencies_linux-64_conda.lock b/build_tools/circle/doc_min_dependencies_linux-64_conda.lock index 540c6cc2cc670..6850878545e2e 100644 --- a/build_tools/circle/doc_min_dependencies_linux-64_conda.lock +++ b/build_tools/circle/doc_min_dependencies_linux-64_conda.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 238bbbc8d5b6c170ef44d61c232d9b6255fb0379c58a2ede8e0cfc8f3eeb6b29 +# input_hash: 252ccd433e79a67f834caaea9da99946773503bd964d12afa2ea4bdd9368ef77 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080 @@ -48,7 +48,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libllvm9-9.0.1-default_hc23dcda_ https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e1c890aebdebbfbf87e2c917187b4416 https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa +https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-h166bdaf_4.tar.bz2#4b11e365c0275b808be78b30f904e295 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h3eb15da_6.conda#6b63daed8feeca47be78f323e793d555 @@ -152,7 +152,7 @@ https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.cond https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.1.1-py38h5c078b8_3.tar.bz2#dafeef887e68bd18ec84681747ca0fd5 https://conda.anaconda.org/conda-forge/linux-64/qt-5.12.5-hd8c4c69_1.tar.bz2#0e105d4afe0c3c81c4fbd9937ec4f359 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.3.2-py38h921218d_0.tar.bz2#278670dc2fef5a6309d1635f047bd456 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.5.0-py38h18bccfc_0.tar.bz2#b6fda3b4ee494afef756621daa115d4d https://conda.anaconda.org/conda-forge/noarch/patsy-0.5.3-pyhd8ed1ab_0.tar.bz2#50ef6b29b1fb0768ca82c5aeb4fb2d96 https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.0.0-py38hf6732f7_1003.tar.bz2#44e00bf7a4b6a564e9313181aaea2615 https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.12.3-py38ha8c2ead_3.tar.bz2#242c206b0c30fdc4c18aea16f04c4262 @@ -162,7 +162,7 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.1.3-py38_0.tar.bz2#1992ab91bbff86ded8d99d1f488d8e8b https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.12.2-py38h5c078b8_0.tar.bz2#33787719ad03d33cffc4e2e3ea82bc9e -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/noarch/seaborn-0.12.2-hd8ed1ab_0.conda#50847a47c07812f88581081c620f5160 https://conda.anaconda.org/conda-forge/noarch/sphinx-4.0.1-pyh6c4a22f_2.tar.bz2#c203dcc46f262853ecbb9552c50d664e https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.2-pyhd8ed1ab_0.tar.bz2#025ad7ca2c7f65007ab6b6f5d93a56eb diff --git a/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock b/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock index 1e0701763a2de..2b7f69c2965ab 100644 --- a/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock +++ b/build_tools/cirrus/py39_conda_forge_linux-aarch64_conda.lock @@ -36,11 +36,11 @@ https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.39-hf9034f9_0.co https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.40.0-hf9034f9_0.tar.bz2#9afb0d5dbaa403858a660cd0b4a31d29 https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.13-h3557bc0_1004.tar.bz2#cc973f5f452272c397546eac588cddb3 https://conda.anaconda.org/conda-forge/linux-aarch64/openblas-0.3.21-pthreads_h2d9dd7e_3.tar.bz2#17a824cf9bbf0e31998d2c1a2140204c -https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.1.2-h38e3740_0.tar.bz2#3cdbfb7d7b63ae2c2d35bb167d257ecd +https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.2-h8fc344f_1.conda#105eb1e16bf83bfb2eb380a48032b655 https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.12-hd8af866_0.tar.bz2#7894e82ff743bd96c76585ddebe28e2a https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.2-h44f6412_6.conda#6d0d1cd6d184129eabb96bb220afb5b2 https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-bin-1.0.9-h4e544f5_8.tar.bz2#0980429a0148a53edd0f1f207ec28a39 -https://conda.anaconda.org/conda-forge/linux-aarch64/ccache-4.7.3-hb064cd7_0.tar.bz2#8e71c7d1731d80d773cdafaa2ddcde50 +https://conda.anaconda.org/conda-forge/linux-aarch64/ccache-4.8-h788f45c_0.conda#28b5b515efa8ac5fec2e1f187b00c810 https://conda.anaconda.org/conda-forge/linux-aarch64/freetype-2.12.1-hbbbf32d_1.conda#e0891290982420d67651589c8584eec3 https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.9.0-16_linuxaarch64_openblas.tar.bz2#520a3ecbebc63239c27dd6f70c2ababe https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.9.0-16_linuxaarch64_openblas.tar.bz2#62990b2d1efc22d0beb394e893d39541 @@ -102,5 +102,5 @@ https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.ta https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-3.7.1-py39ha65689a_0.conda#ba11d081599ada176b3ca99821e1b753 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda#27db656619a55d727eaf5a6ece3d2fd6 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.2-pyhd8ed1ab_0.conda#11d178fc55199482ee48d6812ea83983 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyhd8ed1ab_0.conda#eb2e0fc33ad0d04b51f9280360c13c1e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.7.0-pyha770c72_2.conda#2794d1b53ad3ddb1e61f27d1151ccfc7 https://conda.anaconda.org/conda-forge/linux-aarch64/scipy-1.10.1-py39hafab3e7_0.conda#d5364063c02425a7faa8aca680bdf146 diff --git a/build_tools/update_environments_and_lock_files.py b/build_tools/update_environments_and_lock_files.py index f8926f4981156..ec375078bfab8 100644 --- a/build_tools/update_environments_and_lock_files.py +++ b/build_tools/update_environments_and_lock_files.py @@ -350,11 +350,7 @@ def remove_from(alist, to_remove): "pytest-xdist", ], "package_constraints": {"joblib": "min", "threadpoolctl": "min"}, - # Ubuntu 20.04 has 3.8.2 but only 3.8.5 is available for osx-arm64 on - # conda-forge. Chosing 3.8.5 so that this script can be run locally on - # osx-arm64 machines. This should not matter for pining versions with - # pip-compile - "python_version": "3.8.5", + "python_version": "3.10.4", }, ] diff --git a/doc/install.rst b/doc/install.rst index c97078245f274..d8ea0c964c15c 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -146,11 +146,6 @@ purpose. Scikit-learn 1.1 and later requires Python 3.8 or newer. -.. note:: - - For installing on PyPy, PyPy3-v5.10+, Numpy 1.14.0+, and scipy 1.1.0+ - are required. - .. _install_on_apple_silicon_m1: Installing on Apple Silicon M1 hardware diff --git a/doc/modules/grid_search.rst b/doc/modules/grid_search.rst index ab84f872bb263..851f9a202fa2f 100644 --- a/doc/modules/grid_search.rst +++ b/doc/modules/grid_search.rst @@ -128,7 +128,7 @@ discrete choices (which will be sampled uniformly) can be specified:: This example uses the ``scipy.stats`` module, which contains many useful distributions for sampling parameters, such as ``expon``, ``gamma``, -``uniform`` or ``randint``. +``uniform``, ``loguniform`` or ``randint``. In principle, any function can be passed that provides a ``rvs`` (random variate sample) method to sample a value. A call to the ``rvs`` function should @@ -148,12 +148,9 @@ For continuous parameters, such as ``C`` above, it is important to specify a continuous distribution to take full advantage of the randomization. This way, increasing ``n_iter`` will always lead to a finer search. -A continuous log-uniform random variable is available through -:class:`~sklearn.utils.fixes.loguniform`. This is a continuous version of -log-spaced parameters. For example to specify ``C`` above, ``loguniform(1, -100)`` can be used instead of ``[1, 10, 100]`` or ``np.logspace(0, 2, -num=1000)``. This is an alias to `scipy.stats.loguniform -`_. +A continuous log-uniform random variable is the continuous version of +a log-spaced parameter. For example to specify the equivalent of ``C`` from above, +``loguniform(1, 100)`` can be used instead of ``[1, 10, 100]``. Mirroring the example above in grid search, we can specify a continuous random variable that is log-uniformly distributed between ``1e0`` and ``1e3``:: diff --git a/examples/applications/plot_face_recognition.py b/examples/applications/plot_face_recognition.py index 069f0f5aad202..878d889f52ce3 100644 --- a/examples/applications/plot_face_recognition.py +++ b/examples/applications/plot_face_recognition.py @@ -23,7 +23,7 @@ from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA from sklearn.svm import SVC -from sklearn.utils.fixes import loguniform +from scipy.stats import loguniform # %% diff --git a/examples/gaussian_process/plot_compare_gpr_krr.py b/examples/gaussian_process/plot_compare_gpr_krr.py index 42c013523f79c..7a58ba437278f 100644 --- a/examples/gaussian_process/plot_compare_gpr_krr.py +++ b/examples/gaussian_process/plot_compare_gpr_krr.py @@ -177,7 +177,7 @@ # %% from sklearn.model_selection import RandomizedSearchCV -from sklearn.utils.fixes import loguniform +from scipy.stats import loguniform param_distributions = { "alpha": loguniform(1e0, 1e3), diff --git a/examples/model_selection/plot_randomized_search.py b/examples/model_selection/plot_randomized_search.py index d5514a9b1c278..9ffc26a5abc84 100644 --- a/examples/model_selection/plot_randomized_search.py +++ b/examples/model_selection/plot_randomized_search.py @@ -24,7 +24,6 @@ from time import time import scipy.stats as stats -from sklearn.utils.fixes import loguniform from sklearn.model_selection import GridSearchCV, RandomizedSearchCV from sklearn.datasets import load_digits @@ -57,7 +56,7 @@ def report(results, n_top=3): param_dist = { "average": [True, False], "l1_ratio": stats.uniform(0, 1), - "alpha": loguniform(1e-2, 1e0), + "alpha": stats.loguniform(1e-2, 1e0), } # run randomized search diff --git a/pyproject.toml b/pyproject.toml index 298eded146149..fbb1d53ef6602 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ requires = [ # https://github.com/scipy/scipy/blob/c58b608c83d30800aceee6a4dab5c3464cb1de7d/pyproject.toml#L38-L41 "numpy==1.22.3; python_version=='3.10' and platform_system=='Windows' and platform_python_implementation != 'PyPy'", - "scipy>=1.3.2", + "scipy>=1.5.0", ] [tool.black] diff --git a/sklearn/_min_dependencies.py b/sklearn/_min_dependencies.py index c2314528f5745..aa24bb4b9a762 100644 --- a/sklearn/_min_dependencies.py +++ b/sklearn/_min_dependencies.py @@ -14,7 +14,7 @@ else: NUMPY_MIN_VERSION = "1.17.3" -SCIPY_MIN_VERSION = "1.3.2" +SCIPY_MIN_VERSION = "1.5.0" JOBLIB_MIN_VERSION = "1.1.1" THREADPOOLCTL_MIN_VERSION = "2.0.0" PYTEST_MIN_VERSION = "5.3.1" diff --git a/sklearn/utils/fixes.py b/sklearn/utils/fixes.py index d3eaf0540d7ab..c135323f2b94a 100644 --- a/sklearn/utils/fixes.py +++ b/sklearn/utils/fixes.py @@ -46,55 +46,6 @@ def _object_dtype_isnan(X): return X != X -class loguniform(scipy.stats.reciprocal): - """A class supporting log-uniform random variables. - - Parameters - ---------- - low : float - The minimum value - high : float - The maximum value - - Methods - ------- - rvs(self, size=None, random_state=None) - Generate log-uniform random variables - - The most useful method for Scikit-learn usage is highlighted here. - For a full list, see - `scipy.stats.reciprocal - `_. - This list includes all functions of ``scipy.stats`` continuous - distributions such as ``pdf``. - - Notes - ----- - This class generates values between ``low`` and ``high`` or - - low <= loguniform(low, high).rvs() <= high - - The logarithmic probability density function (PDF) is uniform. When - ``x`` is a uniformly distributed random variable between 0 and 1, ``10**x`` - are random variables that are equally likely to be returned. - - This class is an alias to ``scipy.stats.reciprocal``, which uses the - reciprocal distribution: - https://en.wikipedia.org/wiki/Reciprocal_distribution - - Examples - -------- - - >>> from sklearn.utils.fixes import loguniform - >>> rv = loguniform(1e-3, 1e1) - >>> rvs = rv.rvs(random_state=42, size=1000) - >>> rvs.min() # doctest: +SKIP - 0.0010435856341129003 - >>> rvs.max() # doctest: +SKIP - 9.97403052786026 - """ - - # TODO: remove when the minimum scipy version is >= 1.5 if sp_version >= parse_version("1.5"): from scipy.linalg import eigh as _eigh # noqa diff --git a/sklearn/utils/tests/test_fixes.py b/sklearn/utils/tests/test_fixes.py index 64db4006b5f1a..39c60b9b416ea 100644 --- a/sklearn/utils/tests/test_fixes.py +++ b/sklearn/utils/tests/test_fixes.py @@ -3,15 +3,12 @@ # Lars Buitinck # License: BSD 3 clause -import math - import numpy as np import pytest -import scipy.stats from sklearn.utils._testing import assert_array_equal -from sklearn.utils.fixes import _object_dtype_isnan, delayed, loguniform +from sklearn.utils.fixes import _object_dtype_isnan, delayed @pytest.mark.parametrize("dtype, val", ([object, 1], [object, "a"], [float, 1])) @@ -25,28 +22,6 @@ def test_object_dtype_isnan(dtype, val): assert_array_equal(mask, expected_mask) -@pytest.mark.parametrize("low,high,base", [(-1, 0, 10), (0, 2, np.exp(1)), (-1, 1, 2)]) -def test_loguniform(low, high, base): - rv = loguniform(base**low, base**high) - assert isinstance(rv, scipy.stats._distn_infrastructure.rv_frozen) - rvs = rv.rvs(size=2000, random_state=0) - - # Test the basics; right bounds, right size - assert (base**low <= rvs).all() and (rvs <= base**high).all() - assert len(rvs) == 2000 - - # Test that it's actually (fairly) uniform - log_rvs = np.array([math.log(x, base) for x in rvs]) - counts, _ = np.histogram(log_rvs) - assert counts.mean() == 200 - assert np.abs(counts - counts.mean()).max() <= 40 - - # Test that random_state works - assert loguniform(base**low, base**high).rvs(random_state=0) == loguniform( - base**low, base**high - ).rvs(random_state=0) - - def test_delayed_deprecation(): """Check that we issue the FutureWarning regarding the deprecation of delayed.""" From 8ddd7f8a3ce5475e992c5d88c87d9eb5e99d668b Mon Sep 17 00:00:00 2001 From: Christian Veenhuis Date: Fri, 24 Mar 2023 15:40:30 +0100 Subject: [PATCH 098/230] MAINT Fix broken links in cluster.dbscan module (#25958) --- sklearn/cluster/_dbscan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sklearn/cluster/_dbscan.py b/sklearn/cluster/_dbscan.py index a1cd96263e056..aa81ef27702e6 100644 --- a/sklearn/cluster/_dbscan.py +++ b/sklearn/cluster/_dbscan.py @@ -141,7 +141,7 @@ def dbscan( ---------- Ester, M., H. P. Kriegel, J. Sander, and X. Xu, `"A Density-Based Algorithm for Discovering Clusters in Large Spatial Databases with Noise" - `_. + `_. In: Proceedings of the 2nd International Conference on Knowledge Discovery and Data Mining, Portland, OR, AAAI Press, pp. 226-231. 1996 @@ -281,7 +281,7 @@ class DBSCAN(ClusterMixin, BaseEstimator): ---------- Ester, M., H. P. Kriegel, J. Sander, and X. Xu, `"A Density-Based Algorithm for Discovering Clusters in Large Spatial Databases with Noise" - `_. + `_. In: Proceedings of the 2nd International Conference on Knowledge Discovery and Data Mining, Portland, OR, AAAI Press, pp. 226-231. 1996 From 70ff6b3dfb2f664faa4a0e84d8068b3ce86cc5e5 Mon Sep 17 00:00:00 2001 From: adienes <51664769+adienes@users.noreply.github.com> Date: Fri, 24 Mar 2023 10:44:08 -0400 Subject: [PATCH 099/230] DOC Fix lars Xy shape (#25952) --- sklearn/linear_model/_least_angle.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sklearn/linear_model/_least_angle.py b/sklearn/linear_model/_least_angle.py index 7ed7b27811ec6..35af5dab30267 100644 --- a/sklearn/linear_model/_least_angle.py +++ b/sklearn/linear_model/_least_angle.py @@ -69,7 +69,7 @@ def lars_path( y : None or array-like of shape (n_samples,) Input targets. - Xy : array-like of shape (n_samples,) or (n_samples, n_targets), \ + Xy : array-like of shape (n_features,) or (n_features, n_targets), \ default=None `Xy = np.dot(X.T, y)` that can be precomputed. It is useful only when the Gram matrix is precomputed. @@ -215,7 +215,7 @@ def lars_path_gram( Parameters ---------- - Xy : array-like of shape (n_samples,) or (n_samples, n_targets) + Xy : array-like of shape (n_features,) or (n_features, n_targets) Xy = np.dot(X.T, y). Gram : array-like of shape (n_features, n_features) @@ -362,7 +362,7 @@ def _lars_path_solver( y : None or ndarray of shape (n_samples,) Input targets. - Xy : array-like of shape (n_samples,) or (n_samples, n_targets), \ + Xy : array-like of shape (n_features,) or (n_features, n_targets), \ default=None `Xy = np.dot(X.T, y)` that can be precomputed. It is useful only when the Gram matrix is precomputed. @@ -1110,7 +1110,7 @@ def fit(self, X, y, Xy=None): y : array-like of shape (n_samples,) or (n_samples, n_targets) Target values. - Xy : array-like of shape (n_samples,) or (n_samples, n_targets), \ + Xy : array-like of shape (n_features,) or (n_features, n_targets), \ default=None Xy = np.dot(X.T, y) that can be precomputed. It is useful only when the Gram matrix is precomputed. From 998bbda504faca346020b6b87c92c39108a61ae3 Mon Sep 17 00:00:00 2001 From: Dave Berenbaum Date: Fri, 24 Mar 2023 12:30:23 -0400 Subject: [PATCH 100/230] ENH Add drop_intermediate parameter to metrics.precision_recall_curve (#24668) Co-authored-by: Guillaume Lemaitre --- doc/whats_new/v1.3.rst | 8 ++ .../metrics/_plot/precision_recall_curve.py | 23 +++++- .../tests/test_precision_recall_display.py | 17 +++- sklearn/metrics/_ranking.py | 27 ++++++- sklearn/metrics/tests/test_ranking.py | 81 ++++++++++++++----- 5 files changed, 131 insertions(+), 25 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index c50672a712f93..c2e9113ef2f33 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -306,6 +306,14 @@ Changelog :pr:`18723` by :user:`Sahil Gupta ` and :pr:`24677` by :user:`Ashwin Mathur `. +- |Enhancement| A new parameter `drop_intermediate` was added to + :func:`metrics.precision_recall_curve`, + :func:`metrics.PrecisionRecallDisplay.from_estimator`, + :func:`metrics.PrecisionRecallDisplay.from_predictions`, + which drops some suboptimal thresholds to create lighter precision-recall + curves. + :pr:`24668` by :user:`dberenbaum`. + - |Fix| :func:`log_loss` raises a warning if the values of the parameter `y_pred` are not normalized, instead of actually normalizing them in the metric. Starting from 1.5 this will raise an error. :pr:`25299` by :user:`Omar Salman 2: + # Drop thresholds corresponding to points where true positives (tps) + # do not change from the previous or subsequent point. This will keep + # only the first and last point for each tps value. All points + # with the same tps value have the same recall and thus x coordinate. + # They appear as a vertical line on the plot. + optimal_idxs = np.where( + np.concatenate( + [[True], np.logical_or(np.diff(tps[:-1]), np.diff(tps[1:])), [True]] + ) + )[0] + fps = fps[optimal_idxs] + tps = tps[optimal_idxs] + thresholds = thresholds[optimal_idxs] + ps = tps + fps # Initialize the result array with zeros to make sure that precision[ps == 0] # does not contain uninitialized values. diff --git a/sklearn/metrics/tests/test_ranking.py b/sklearn/metrics/tests/test_ranking.py index 62ba79e3cea2f..8778ca8a95b9b 100644 --- a/sklearn/metrics/tests/test_ranking.py +++ b/sklearn/metrics/tests/test_ranking.py @@ -891,35 +891,41 @@ def test_binary_clf_curve_zero_sample_weight(curve_func): assert_allclose(arr_1, arr_2) -def test_precision_recall_curve(): +@pytest.mark.parametrize("drop", [True, False]) +def test_precision_recall_curve(drop): y_true, _, y_score = make_prediction(binary=True) - _test_precision_recall_curve(y_true, y_score) + _test_precision_recall_curve(y_true, y_score, drop) # Make sure the first point of the Precision-Recall on the right is: # (p=1.0, r=class balance) on a non-balanced dataset [1:] - p, r, t = precision_recall_curve(y_true[1:], y_score[1:]) + p, r, t = precision_recall_curve(y_true[1:], y_score[1:], drop_intermediate=drop) assert r[0] == 1.0 assert p[0] == y_true[1:].mean() # Use {-1, 1} for labels; make sure original labels aren't modified y_true[np.where(y_true == 0)] = -1 y_true_copy = y_true.copy() - _test_precision_recall_curve(y_true, y_score) + _test_precision_recall_curve(y_true, y_score, drop) assert_array_equal(y_true_copy, y_true) labels = [1, 0, 0, 1] predict_probas = [1, 2, 3, 4] - p, r, t = precision_recall_curve(labels, predict_probas) - assert_array_almost_equal(p, np.array([0.5, 0.33333333, 0.5, 1.0, 1.0])) - assert_array_almost_equal(r, np.array([1.0, 0.5, 0.5, 0.5, 0.0])) - assert_array_almost_equal(t, np.array([1, 2, 3, 4])) + p, r, t = precision_recall_curve(labels, predict_probas, drop_intermediate=drop) + if drop: + assert_allclose(p, [0.5, 0.33333333, 1.0, 1.0]) + assert_allclose(r, [1.0, 0.5, 0.5, 0.0]) + assert_allclose(t, [1, 2, 4]) + else: + assert_allclose(p, [0.5, 0.33333333, 0.5, 1.0, 1.0]) + assert_allclose(r, [1.0, 0.5, 0.5, 0.5, 0.0]) + assert_allclose(t, [1, 2, 3, 4]) assert p.size == r.size assert p.size == t.size + 1 -def _test_precision_recall_curve(y_true, y_score): +def _test_precision_recall_curve(y_true, y_score, drop): # Test Precision-Recall and area under PR curve - p, r, thresholds = precision_recall_curve(y_true, y_score) + p, r, thresholds = precision_recall_curve(y_true, y_score, drop_intermediate=drop) precision_recall_auc = _average_precision_slow(y_true, y_score) assert_array_almost_equal(precision_recall_auc, 0.859, 3) assert_array_almost_equal( @@ -932,17 +938,20 @@ def _test_precision_recall_curve(y_true, y_score): assert p.size == r.size assert p.size == thresholds.size + 1 # Smoke test in the case of proba having only one value - p, r, thresholds = precision_recall_curve(y_true, np.zeros_like(y_score)) + p, r, thresholds = precision_recall_curve( + y_true, np.zeros_like(y_score), drop_intermediate=drop + ) assert p.size == r.size assert p.size == thresholds.size + 1 -def test_precision_recall_curve_toydata(): +@pytest.mark.parametrize("drop", [True, False]) +def test_precision_recall_curve_toydata(drop): with np.errstate(all="raise"): # Binary classification y_true = [0, 1] y_score = [0, 1] - p, r, _ = precision_recall_curve(y_true, y_score) + p, r, _ = precision_recall_curve(y_true, y_score, drop_intermediate=drop) auc_prc = average_precision_score(y_true, y_score) assert_array_almost_equal(p, [0.5, 1, 1]) assert_array_almost_equal(r, [1, 1, 0]) @@ -950,7 +959,7 @@ def test_precision_recall_curve_toydata(): y_true = [0, 1] y_score = [1, 0] - p, r, _ = precision_recall_curve(y_true, y_score) + p, r, _ = precision_recall_curve(y_true, y_score, drop_intermediate=drop) auc_prc = average_precision_score(y_true, y_score) assert_array_almost_equal(p, [0.5, 0.0, 1.0]) assert_array_almost_equal(r, [1.0, 0.0, 0.0]) @@ -961,7 +970,7 @@ def test_precision_recall_curve_toydata(): y_true = [1, 0] y_score = [1, 1] - p, r, _ = precision_recall_curve(y_true, y_score) + p, r, _ = precision_recall_curve(y_true, y_score, drop_intermediate=drop) auc_prc = average_precision_score(y_true, y_score) assert_array_almost_equal(p, [0.5, 1]) assert_array_almost_equal(r, [1.0, 0]) @@ -969,7 +978,7 @@ def test_precision_recall_curve_toydata(): y_true = [1, 0] y_score = [1, 0] - p, r, _ = precision_recall_curve(y_true, y_score) + p, r, _ = precision_recall_curve(y_true, y_score, drop_intermediate=drop) auc_prc = average_precision_score(y_true, y_score) assert_array_almost_equal(p, [0.5, 1, 1]) assert_array_almost_equal(r, [1, 1, 0]) @@ -977,7 +986,7 @@ def test_precision_recall_curve_toydata(): y_true = [1, 0] y_score = [0.5, 0.5] - p, r, _ = precision_recall_curve(y_true, y_score) + p, r, _ = precision_recall_curve(y_true, y_score, drop_intermediate=drop) auc_prc = average_precision_score(y_true, y_score) assert_array_almost_equal(p, [0.5, 1]) assert_array_almost_equal(r, [1, 0.0]) @@ -986,7 +995,7 @@ def test_precision_recall_curve_toydata(): y_true = [0, 0] y_score = [0.25, 0.75] with pytest.warns(UserWarning, match="No positive class found in y_true"): - p, r, _ = precision_recall_curve(y_true, y_score) + p, r, _ = precision_recall_curve(y_true, y_score, drop_intermediate=drop) with pytest.warns(UserWarning, match="No positive class found in y_true"): auc_prc = average_precision_score(y_true, y_score) assert_allclose(p, [0, 0, 1]) @@ -995,7 +1004,7 @@ def test_precision_recall_curve_toydata(): y_true = [1, 1] y_score = [0.25, 0.75] - p, r, _ = precision_recall_curve(y_true, y_score) + p, r, _ = precision_recall_curve(y_true, y_score, drop_intermediate=drop) assert_almost_equal(average_precision_score(y_true, y_score), 1.0) assert_array_almost_equal(p, [1.0, 1.0, 1.0]) assert_array_almost_equal(r, [1, 0.5, 0.0]) @@ -1100,6 +1109,40 @@ def test_precision_recall_curve_toydata(): ) +def test_precision_recall_curve_drop_intermediate(): + """Check the behaviour of the `drop_intermediate` parameter.""" + y_true = [0, 0, 0, 0, 1, 1] + y_score = [0.0, 0.2, 0.5, 0.6, 0.7, 1.0] + precision, recall, thresholds = precision_recall_curve( + y_true, y_score, drop_intermediate=True + ) + assert_allclose(thresholds, [0.0, 0.7, 1.0]) + + # Test dropping thresholds with repeating scores + y_true = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1] + y_score = [0.0, 0.1, 0.6, 0.6, 0.7, 0.8, 0.9, 0.6, 0.7, 0.8, 0.9, 0.9, 1.0] + precision, recall, thresholds = precision_recall_curve( + y_true, y_score, drop_intermediate=True + ) + assert_allclose(thresholds, [0.0, 0.6, 0.7, 0.8, 0.9, 1.0]) + + # Test all false keeps only endpoints + y_true = [0, 0, 0, 0] + y_score = [0.0, 0.1, 0.2, 0.3] + precision, recall, thresholds = precision_recall_curve( + y_true, y_score, drop_intermediate=True + ) + assert_allclose(thresholds, [0.0, 0.3]) + + # Test all true keeps all thresholds + y_true = [1, 1, 1, 1] + y_score = [0.0, 0.1, 0.2, 0.3] + precision, recall, thresholds = precision_recall_curve( + y_true, y_score, drop_intermediate=True + ) + assert_allclose(thresholds, [0.0, 0.1, 0.2, 0.3]) + + def test_average_precision_constant_values(): # Check the average_precision_score of a constant predictor is # the TPR From e5175a04a51dd3320d0fd2f4aa98baf5205b8172 Mon Sep 17 00:00:00 2001 From: Lene Preuss Date: Fri, 24 Mar 2023 17:33:00 +0100 Subject: [PATCH 101/230] FIX improve error message when computing NDCG with a single document (#25672) Co-authored-by: Guillaume Lemaitre --- doc/whats_new/v1.3.rst | 4 ++++ sklearn/metrics/_ranking.py | 10 ++++++++-- sklearn/metrics/tests/test_ranking.py | 12 +++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index c2e9113ef2f33..51b4214145216 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -301,6 +301,10 @@ Changelog both return `np.nan`. :pr:`25531` by :user:`Marc Torrellas Socastro `. +- |Fix| :func:`metric.ndcg_score` now gives a meaningful error message for input of + length 1. + :pr:`25672` by :user:`Lene Preuss ` and :user:`Wei-Chun Chu `. + - |Enhancement| :class:`metrics.silhouette_samples` nows accepts a sparse matrix of pairwise distances between samples, or a feature array. :pr:`18723` by :user:`Sahil Gupta ` and diff --git a/sklearn/metrics/_ranking.py b/sklearn/metrics/_ranking.py index 15803941eb0e6..6693a6391919e 100644 --- a/sklearn/metrics/_ranking.py +++ b/sklearn/metrics/_ranking.py @@ -1758,10 +1758,16 @@ def ndcg_score(y_true, y_score, *, k=None, sample_weight=None, ignore_ties=False if y_true.min() < 0: # TODO(1.4): Replace warning w/ ValueError warnings.warn( - "ndcg_score should not be used on negative y_true values. ndcg_score will" - " raise a ValueError on negative y_true values starting from version 1.4.", + "ndcg_score should not be used on negative y_true values. ndcg_score" + " will raise a ValueError on negative y_true values starting from" + " version 1.4.", FutureWarning, ) + if y_true.ndim > 1 and y_true.shape[1] <= 1: + raise ValueError( + "Computing NDCG is only meaningful when there is more than 1 document. " + f"Got {y_true.shape[1]} instead." + ) _check_dcg_target_type(y_true) gain = _ndcg_sample_scores(y_true, y_score, k=k, ignore_ties=ignore_ties) return np.average(gain, weights=sample_weight) diff --git a/sklearn/metrics/tests/test_ranking.py b/sklearn/metrics/tests/test_ranking.py index 8778ca8a95b9b..c6504644f5a91 100644 --- a/sklearn/metrics/tests/test_ranking.py +++ b/sklearn/metrics/tests/test_ranking.py @@ -1578,7 +1578,6 @@ def test_lrap_error_raised(): @pytest.mark.parametrize("n_classes", (2, 5, 10)) @pytest.mark.parametrize("random_state", range(1)) def test_alternative_lrap_implementation(n_samples, n_classes, random_state): - check_alternative_lrap_implementation( label_ranking_average_precision_score, n_classes, n_samples, random_state ) @@ -1878,6 +1877,17 @@ def test_ndcg_toy_examples(ignore_ties): assert ndcg_score(y_true, y_score, ignore_ties=ignore_ties) == pytest.approx(1.0) +def test_ndcg_error_single_document(): + """Check that we raise an informative error message when trying to + compute NDCG with a single document.""" + err_msg = ( + "Computing NDCG is only meaningful when there is more than 1 document. " + "Got 1 instead." + ) + with pytest.raises(ValueError, match=err_msg): + ndcg_score([[1]], [[1]]) + + def test_ndcg_score(): _, y_true = make_multilabel_classification(random_state=0, n_classes=10) y_score = -y_true + 1 From 2119bfb4f90a4e540f443ee132f49537224965e0 Mon Sep 17 00:00:00 2001 From: Guillaume Lemaitre Date: Fri, 24 Mar 2023 18:15:08 +0100 Subject: [PATCH 102/230] MAINT introduce _get_response_values and _check_response_methods (#23073) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Thomas J. Fan Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/calibration.py | 23 +- sklearn/ensemble/_stacking.py | 32 ++- sklearn/ensemble/tests/test_stacking.py | 8 +- sklearn/metrics/_plot/base.py | 116 --------- sklearn/metrics/_plot/det_curve.py | 7 +- .../metrics/_plot/precision_recall_curve.py | 11 +- sklearn/metrics/_plot/roc_curve.py | 7 +- sklearn/metrics/_plot/tests/test_base.py | 75 ------ .../_plot/tests/test_common_curve_display.py | 16 +- .../tests/test_precision_recall_display.py | 4 +- sklearn/tests/test_calibration.py | 14 +- sklearn/utils/_mocking.py | 42 ++++ sklearn/utils/_response.py | 177 ++++++++++++++ sklearn/utils/tests/test_mocking.py | 31 ++- sklearn/utils/tests/test_response.py | 229 ++++++++++++++++++ sklearn/utils/tests/test_validation.py | 60 ++++- sklearn/utils/validation.py | 48 +++- 17 files changed, 644 insertions(+), 256 deletions(-) delete mode 100644 sklearn/metrics/_plot/base.py delete mode 100644 sklearn/metrics/_plot/tests/test_base.py create mode 100644 sklearn/utils/_response.py create mode 100644 sklearn/utils/tests/test_response.py diff --git a/sklearn/calibration.py b/sklearn/calibration.py index d54aa158f5328..31f8b67458f78 100644 --- a/sklearn/calibration.py +++ b/sklearn/calibration.py @@ -25,16 +25,17 @@ RegressorMixin, clone, MetaEstimatorMixin, - is_classifier, ) from .preprocessing import label_binarize, LabelEncoder from .utils import ( column_or_1d, indexable, check_matplotlib_support, + _safe_indexing, ) +from .utils._response import _get_response_values_binary -from .utils.multiclass import check_classification_targets +from .utils.multiclass import check_classification_targets, type_of_target from .utils.parallel import delayed, Parallel from .utils._param_validation import StrOptions, HasMethods, Hidden from .utils.validation import ( @@ -44,12 +45,10 @@ check_consistent_length, check_is_fitted, ) -from .utils import _safe_indexing from .isotonic import IsotonicRegression from .svm import LinearSVC from .model_selection import check_cv, cross_val_predict from .metrics._base import _check_pos_label_consistency -from .metrics._plot.base import _get_response class CalibratedClassifierCV(ClassifierMixin, MetaEstimatorMixin, BaseEstimator): @@ -1264,11 +1263,9 @@ def from_estimator( method_name = f"{cls.__name__}.from_estimator" check_matplotlib_support(method_name) - if not is_classifier(estimator): - raise ValueError("'estimator' should be a fitted classifier.") - - y_prob, pos_label = _get_response( - X, estimator, response_method="predict_proba", pos_label=pos_label + check_is_fitted(estimator) + y_prob, pos_label = _get_response_values_binary( + estimator, X, response_method="predict_proba", pos_label=pos_label ) name = name if name is not None else estimator.__class__.__name__ @@ -1381,9 +1378,15 @@ def from_predictions( >>> disp = CalibrationDisplay.from_predictions(y_test, y_prob) >>> plt.show() """ - method_name = f"{cls.__name__}.from_estimator" + method_name = f"{cls.__name__}.from_predictions" check_matplotlib_support(method_name) + target_type = type_of_target(y_true) + if target_type != "binary": + raise ValueError( + f"The target y is not binary. Got {target_type} type of target." + ) + prob_true, prob_pred = calibration_curve( y_true, y_prob, n_bins=n_bins, strategy=strategy, pos_label=pos_label ) diff --git a/sklearn/ensemble/_stacking.py b/sklearn/ensemble/_stacking.py index e19ef3960ac2c..81f8ef9c087a3 100644 --- a/sklearn/ensemble/_stacking.py +++ b/sklearn/ensemble/_stacking.py @@ -30,11 +30,14 @@ from ..utils import Bunch from ..utils.multiclass import check_classification_targets, type_of_target from ..utils.metaestimators import available_if -from ..utils.validation import check_is_fitted -from ..utils.validation import column_or_1d from ..utils.parallel import delayed, Parallel from ..utils._param_validation import HasMethods, StrOptions -from ..utils.validation import _check_feature_names_in +from ..utils.validation import ( + _check_feature_names_in, + _check_response_method, + check_is_fitted, + column_or_1d, +) def _estimator_has(attr): @@ -146,20 +149,15 @@ def _method_name(name, estimator, method): if estimator == "drop": return None if method == "auto": - if getattr(estimator, "predict_proba", None): - return "predict_proba" - elif getattr(estimator, "decision_function", None): - return "decision_function" - else: - return "predict" - else: - if not hasattr(estimator, method): - raise ValueError( - "Underlying estimator {} does not implement the method {}.".format( - name, method - ) - ) - return method + method = ["predict_proba", "decision_function", "predict"] + try: + method_name = _check_response_method(estimator, method).__name__ + except AttributeError as e: + raise ValueError( + f"Underlying estimator {name} does not implement the method {method}." + ) from e + + return method_name def fit(self, X, y, sample_weight=None): """Fit the estimators. diff --git a/sklearn/ensemble/tests/test_stacking.py b/sklearn/ensemble/tests/test_stacking.py index f237961ed7606..956997156b455 100644 --- a/sklearn/ensemble/tests/test_stacking.py +++ b/sklearn/ensemble/tests/test_stacking.py @@ -572,9 +572,13 @@ def test_stacking_prefit(Stacker, Estimator, stack_method, final_estimator, X, y # mock out fit and stack_method to be asserted later for _, estimator in estimators: - estimator.fit = Mock() + estimator.fit = Mock(name="fit") stack_func = getattr(estimator, stack_method) - setattr(estimator, stack_method, Mock(side_effect=stack_func)) + predict_method_mocked = Mock(side_effect=stack_func) + # Mocking a method will not provide a `__name__` while Python methods + # do and we are using it in `_get_response_method`. + predict_method_mocked.__name__ = stack_method + setattr(estimator, stack_method, predict_method_mocked) stacker = Stacker( estimators=estimators, cv="prefit", final_estimator=final_estimator diff --git a/sklearn/metrics/_plot/base.py b/sklearn/metrics/_plot/base.py deleted file mode 100644 index 60377e3b10f66..0000000000000 --- a/sklearn/metrics/_plot/base.py +++ /dev/null @@ -1,116 +0,0 @@ -from ...base import is_classifier - - -def _check_classifier_response_method(estimator, response_method): - """Return prediction method from the response_method - - Parameters - ---------- - estimator: object - Classifier to check - - response_method: {'auto', 'predict_proba', 'decision_function'} - Specifies whether to use :term:`predict_proba` or - :term:`decision_function` as the target response. If set to 'auto', - :term:`predict_proba` is tried first and if it does not exist - :term:`decision_function` is tried next. - - Returns - ------- - prediction_method: callable - prediction method of estimator - """ - - if response_method not in ("predict_proba", "decision_function", "auto"): - raise ValueError( - "response_method must be 'predict_proba', 'decision_function' or 'auto'" - ) - - error_msg = "response method {} is not defined in {}" - if response_method != "auto": - prediction_method = getattr(estimator, response_method, None) - if prediction_method is None: - raise ValueError( - error_msg.format(response_method, estimator.__class__.__name__) - ) - else: - predict_proba = getattr(estimator, "predict_proba", None) - decision_function = getattr(estimator, "decision_function", None) - prediction_method = predict_proba or decision_function - if prediction_method is None: - raise ValueError( - error_msg.format( - "decision_function or predict_proba", estimator.__class__.__name__ - ) - ) - - return prediction_method - - -def _get_response(X, estimator, response_method, pos_label=None): - """Return response and positive label. - - Parameters - ---------- - X : {array-like, sparse matrix} of shape (n_samples, n_features) - Input values. - - estimator : estimator instance - Fitted classifier or a fitted :class:`~sklearn.pipeline.Pipeline` - in which the last estimator is a classifier. - - response_method: {'auto', 'predict_proba', 'decision_function'} - Specifies whether to use :term:`predict_proba` or - :term:`decision_function` as the target response. If set to 'auto', - :term:`predict_proba` is tried first and if it does not exist - :term:`decision_function` is tried next. - - pos_label : str or int, default=None - The class considered as the positive class when computing - the metrics. By default, `estimators.classes_[1]` is - considered as the positive class. - - Returns - ------- - y_pred: ndarray of shape (n_samples,) - Target scores calculated from the provided response_method - and pos_label. - - pos_label: str or int - The class considered as the positive class when computing - the metrics. - """ - classification_error = ( - "Expected 'estimator' to be a binary classifier, but got" - f" {estimator.__class__.__name__}" - ) - - if not is_classifier(estimator): - raise ValueError(classification_error) - - prediction_method = _check_classifier_response_method(estimator, response_method) - y_pred = prediction_method(X) - if pos_label is not None: - try: - class_idx = estimator.classes_.tolist().index(pos_label) - except ValueError as e: - raise ValueError( - "The class provided by 'pos_label' is unknown. Got " - f"{pos_label} instead of one of {set(estimator.classes_)}" - ) from e - else: - class_idx = 1 - pos_label = estimator.classes_[class_idx] - - if y_pred.ndim != 1: # `predict_proba` - y_pred_shape = y_pred.shape[1] - if y_pred_shape != 2: - raise ValueError( - f"{classification_error} fit on multiclass ({y_pred_shape} classes)" - " data" - ) - y_pred = y_pred[:, class_idx] - elif pos_label == estimator.classes_[0]: # `decision_function` - y_pred *= -1 - - return y_pred, pos_label diff --git a/sklearn/metrics/_plot/det_curve.py b/sklearn/metrics/_plot/det_curve.py index b4a868b195dd0..f9832fed41847 100644 --- a/sklearn/metrics/_plot/det_curve.py +++ b/sklearn/metrics/_plot/det_curve.py @@ -1,11 +1,10 @@ import scipy as sp -from .base import _get_response - from .. import det_curve from .._base import _check_pos_label_consistency from ...utils import check_matplotlib_support +from ...utils._response import _get_response_values_binary class DetCurveDisplay: @@ -168,9 +167,9 @@ def from_estimator( name = estimator.__class__.__name__ if name is None else name - y_pred, pos_label = _get_response( - X, + y_pred, pos_label = _get_response_values_binary( estimator, + X, response_method, pos_label=pos_label, ) diff --git a/sklearn/metrics/_plot/precision_recall_curve.py b/sklearn/metrics/_plot/precision_recall_curve.py index f1e79584b416c..209f4dd0c3862 100644 --- a/sklearn/metrics/_plot/precision_recall_curve.py +++ b/sklearn/metrics/_plot/precision_recall_curve.py @@ -1,12 +1,10 @@ -from sklearn.base import is_classifier -from .base import _get_response - from .. import average_precision_score from .. import precision_recall_curve from .._base import _check_pos_label_consistency from .._classification import check_consistent_length from ...utils import check_matplotlib_support +from ...utils._response import _get_response_values_binary class PrecisionRecallDisplay: @@ -277,11 +275,10 @@ def from_estimator( """ method_name = f"{cls.__name__}.from_estimator" check_matplotlib_support(method_name) - if not is_classifier(estimator): - raise ValueError(f"{method_name} only supports classifiers") - y_pred, pos_label = _get_response( - X, + + y_pred, pos_label = _get_response_values_binary( estimator, + X, response_method, pos_label=pos_label, ) diff --git a/sklearn/metrics/_plot/roc_curve.py b/sklearn/metrics/_plot/roc_curve.py index 256183787e470..65d639679449d 100644 --- a/sklearn/metrics/_plot/roc_curve.py +++ b/sklearn/metrics/_plot/roc_curve.py @@ -1,10 +1,9 @@ -from .base import _get_response - from .. import auc from .. import roc_curve from .._base import _check_pos_label_consistency from ...utils import check_matplotlib_support +from ...utils._response import _get_response_values_binary class RocCurveDisplay: @@ -231,9 +230,9 @@ def from_estimator( name = estimator.__class__.__name__ if name is None else name - y_pred, pos_label = _get_response( - X, + y_pred, pos_label = _get_response_values_binary( estimator, + X, response_method=response_method, pos_label=pos_label, ) diff --git a/sklearn/metrics/_plot/tests/test_base.py b/sklearn/metrics/_plot/tests/test_base.py deleted file mode 100644 index 2f67d7dd223f4..0000000000000 --- a/sklearn/metrics/_plot/tests/test_base.py +++ /dev/null @@ -1,75 +0,0 @@ -import numpy as np -import pytest - -from sklearn.datasets import load_iris -from sklearn.linear_model import LogisticRegression -from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor - -from sklearn.metrics._plot.base import _get_response - - -@pytest.mark.parametrize( - "estimator, err_msg, params", - [ - ( - DecisionTreeRegressor(), - "Expected 'estimator' to be a binary classifier", - {"response_method": "auto"}, - ), - ( - DecisionTreeClassifier(), - "The class provided by 'pos_label' is unknown.", - {"response_method": "auto", "pos_label": "unknown"}, - ), - ( - DecisionTreeClassifier(), - "fit on multiclass", - {"response_method": "predict_proba"}, - ), - ], -) -def test_get_response_error(estimator, err_msg, params): - """Check that we raise the proper error messages in `_get_response`.""" - X, y = load_iris(return_X_y=True) - - estimator.fit(X, y) - with pytest.raises(ValueError, match=err_msg): - _get_response(X, estimator, **params) - - -def test_get_response_predict_proba(): - """Check the behaviour of `_get_response` using `predict_proba`.""" - X, y = load_iris(return_X_y=True) - X_binary, y_binary = X[:100], y[:100] - - classifier = DecisionTreeClassifier().fit(X_binary, y_binary) - y_proba, pos_label = _get_response( - X_binary, classifier, response_method="predict_proba" - ) - np.testing.assert_allclose(y_proba, classifier.predict_proba(X_binary)[:, 1]) - assert pos_label == 1 - - y_proba, pos_label = _get_response( - X_binary, classifier, response_method="predict_proba", pos_label=0 - ) - np.testing.assert_allclose(y_proba, classifier.predict_proba(X_binary)[:, 0]) - assert pos_label == 0 - - -def test_get_response_decision_function(): - """Check the behaviour of `get_response` using `decision_function`.""" - X, y = load_iris(return_X_y=True) - X_binary, y_binary = X[:100], y[:100] - - classifier = LogisticRegression().fit(X_binary, y_binary) - y_score, pos_label = _get_response( - X_binary, classifier, response_method="decision_function" - ) - np.testing.assert_allclose(y_score, classifier.decision_function(X_binary)) - assert pos_label == 1 - - y_score, pos_label = _get_response( - X_binary, classifier, response_method="decision_function", pos_label=0 - ) - np.testing.assert_allclose(y_score, classifier.decision_function(X_binary) * -1) - assert pos_label == 0 diff --git a/sklearn/metrics/_plot/tests/test_common_curve_display.py b/sklearn/metrics/_plot/tests/test_common_curve_display.py index 5ed036b77f4d0..27730893bb05c 100644 --- a/sklearn/metrics/_plot/tests/test_common_curve_display.py +++ b/sklearn/metrics/_plot/tests/test_common_curve_display.py @@ -36,9 +36,7 @@ def test_display_curve_error_non_binary(pyplot, data, Display): X, y = data clf = DecisionTreeClassifier().fit(X, y) - msg = ( - "Expected 'estimator' to be a binary classifier, but got DecisionTreeClassifier" - ) + msg = "Expected 'estimator' to be a binary classifier. Got 3 classes instead." with pytest.raises(ValueError, match=msg): Display.from_estimator(clf, X, y) @@ -48,20 +46,20 @@ def test_display_curve_error_non_binary(pyplot, data, Display): [ ( "predict_proba", - "response method predict_proba is not defined in MyClassifier", + "MyClassifier has none of the following attributes: predict_proba.", ), ( "decision_function", - "response method decision_function is not defined in MyClassifier", + "MyClassifier has none of the following attributes: decision_function.", ), ( "auto", - "response method decision_function or predict_proba is not " - "defined in MyClassifier", + "MyClassifier has none of the following attributes: predict_proba," + " decision_function.", ), ( "bad_method", - "response_method must be 'predict_proba', 'decision_function' or 'auto'", + "MyClassifier has none of the following attributes: bad_method.", ), ], ) @@ -86,7 +84,7 @@ def fit(self, X, y): clf = MyClassifier().fit(X, y) - with pytest.raises(ValueError, match=msg): + with pytest.raises(AttributeError, match=msg): Display.from_estimator(clf, X, y, response_method=response_method) diff --git a/sklearn/metrics/_plot/tests/test_precision_recall_display.py b/sklearn/metrics/_plot/tests/test_precision_recall_display.py index 8cad8d70a7071..e7e1917c79776 100644 --- a/sklearn/metrics/_plot/tests/test_precision_recall_display.py +++ b/sklearn/metrics/_plot/tests/test_precision_recall_display.py @@ -35,11 +35,11 @@ def test_precision_recall_display_validation(pyplot): classifier = SVC(probability=True).fit(X, y) y_pred_classifier = classifier.predict_proba(X)[:, -1] - err_msg = "PrecisionRecallDisplay.from_estimator only supports classifiers" + err_msg = "Expected 'estimator' to be a binary classifier. Got SVR instead." with pytest.raises(ValueError, match=err_msg): PrecisionRecallDisplay.from_estimator(regressor, X, y) - err_msg = "Expected 'estimator' to be a binary classifier, but got SVC" + err_msg = "Expected 'estimator' to be a binary classifier." with pytest.raises(ValueError, match=err_msg): PrecisionRecallDisplay.from_estimator(classifier, X, y) diff --git a/sklearn/tests/test_calibration.py b/sklearn/tests/test_calibration.py index 01bdbd6566042..fff774c3fc490 100644 --- a/sklearn/tests/test_calibration.py +++ b/sklearn/tests/test_calibration.py @@ -173,7 +173,7 @@ def test_parallel_execution(data, method, ensemble): X, y = data X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42) - estimator = LinearSVC(random_state=42) + estimator = make_pipeline(StandardScaler(), LinearSVC(random_state=42)) cal_clf_parallel = CalibratedClassifierCV( estimator, method=method, n_jobs=2, ensemble=ensemble @@ -600,13 +600,13 @@ def test_calibration_display_validation(pyplot, iris_data, iris_data_binary): X_binary, y_binary = iris_data_binary reg = LinearRegression().fit(X, y) - msg = "'estimator' should be a fitted classifier" + msg = "Expected 'estimator' to be a binary classifier. Got LinearRegression" with pytest.raises(ValueError, match=msg): CalibrationDisplay.from_estimator(reg, X, y) - clf = LinearSVC().fit(X, y) - msg = "response method predict_proba is not defined in" - with pytest.raises(ValueError, match=msg): + clf = LinearSVC().fit(X_binary, y_binary) + msg = "has none of the following attributes: predict_proba." + with pytest.raises(AttributeError, match=msg): CalibrationDisplay.from_estimator(clf, X, y) clf = LogisticRegression() @@ -622,11 +622,11 @@ def test_calibration_display_non_binary(pyplot, iris_data, constructor_name): y_prob = clf.predict_proba(X) if constructor_name == "from_estimator": - msg = "to be a binary classifier, but got" + msg = "to be a binary classifier. Got 3 classes instead." with pytest.raises(ValueError, match=msg): CalibrationDisplay.from_estimator(clf, X, y) else: - msg = "y should be a 1d array, got an array of shape" + msg = "The target y is not binary. Got multiclass type of target." with pytest.raises(ValueError, match=msg): CalibrationDisplay.from_predictions(y, y_prob) diff --git a/sklearn/utils/_mocking.py b/sklearn/utils/_mocking.py index c7451dce1fbc5..688bfb68ed484 100644 --- a/sklearn/utils/_mocking.py +++ b/sklearn/utils/_mocking.py @@ -1,6 +1,7 @@ import numpy as np from ..base import BaseEstimator, ClassifierMixin +from .metaestimators import available_if from .validation import _check_sample_weight, _num_samples, check_array from .validation import check_is_fitted @@ -344,3 +345,44 @@ def predict_proba(self, X): def _more_tags(self): return {"_skip_test": True} + + +def _check_response(method): + def check(self): + return self.response_methods is not None and method in self.response_methods + + return check + + +class _MockEstimatorOnOffPrediction(BaseEstimator): + """Estimator for which we can turn on/off the prediction methods. + + Parameters + ---------- + response_methods: list of \ + {"predict", "predict_proba", "decision_function"}, default=None + List containing the response implemented by the estimator. When, the + response is in the list, it will return the name of the response method + when called. Otherwise, an `AttributeError` is raised. It allows to + use `getattr` as any conventional estimator. By default, no response + methods are mocked. + """ + + def __init__(self, response_methods=None): + self.response_methods = response_methods + + def fit(self, X, y): + self.classes_ = np.unique(y) + return self + + @available_if(_check_response("predict")) + def predict(self, X): + return "predict" + + @available_if(_check_response("predict_proba")) + def predict_proba(self, X): + return "predict_proba" + + @available_if(_check_response("decision_function")) + def decision_function(self, X): + return "decision_function" diff --git a/sklearn/utils/_response.py b/sklearn/utils/_response.py new file mode 100644 index 0000000000000..50b9409c8276d --- /dev/null +++ b/sklearn/utils/_response.py @@ -0,0 +1,177 @@ +"""Utilities to get the response values of a classifier or a regressor. + +It allows to make uniform checks and validation. +""" +import numpy as np + +from ..base import is_classifier +from .validation import _check_response_method, check_is_fitted + + +def _get_response_values( + estimator, + X, + response_method, + pos_label=None, +): + """Compute the response values of a classifier or a regressor. + + The response values are predictions, one scalar value for each sample in X + that depends on the specific choice of `response_method`. + + This helper only accepts multiclass classifiers with the `predict` response + method. + + If `estimator` is a binary classifier, also return the label for the + effective positive class. + + .. versionadded:: 1.3 + + Parameters + ---------- + estimator : estimator instance + Fitted classifier or regressor or a fitted :class:`~sklearn.pipeline.Pipeline` + in which the last estimator is a classifier or a regressor. + + X : {array-like, sparse matrix} of shape (n_samples, n_features) + Input values. + + response_method : {"predict_proba", "decision_function", "predict"} or \ + list of such str + Specifies the response method to use get prediction from an estimator + (i.e. :term:`predict_proba`, :term:`decision_function` or + :term:`predict`). Possible choices are: + + - if `str`, it corresponds to the name to the method to return; + - if a list of `str`, it provides the method names in order of + preference. The method returned corresponds to the first method in + the list and which is implemented by `estimator`. + + pos_label : str or int, default=None + The class considered as the positive class when computing + the metrics. By default, `estimators.classes_[1]` is + considered as the positive class. + + Returns + ------- + y_pred : ndarray of shape (n_samples,) + Target scores calculated from the provided response_method + and `pos_label`. + + pos_label : str, int or None + The class considered as the positive class when computing + the metrics. Returns `None` if `estimator` is a regressor. + + Raises + ------ + ValueError + If `pos_label` is not a valid label. + If the shape of `y_pred` is not consistent for binary classifier. + If the response method can be applied to a classifier only and + `estimator` is a regressor. + """ + from sklearn.base import is_classifier # noqa + + if is_classifier(estimator): + prediction_method = _check_response_method(estimator, response_method) + classes = estimator.classes_ + + target_type = "binary" if len(classes) <= 2 else "multiclass" + + if target_type == "multiclass" and prediction_method.__name__ != "predict": + raise ValueError( + "With a multiclass estimator, the response method should be " + f"predict, got {prediction_method.__name__} instead." + ) + + if pos_label is not None and pos_label not in classes.tolist(): + raise ValueError( + f"pos_label={pos_label} is not a valid label: It should be " + f"one of {classes}" + ) + elif pos_label is None and target_type == "binary": + pos_label = pos_label if pos_label is not None else classes[-1] + + y_pred = prediction_method(X) + if prediction_method.__name__ == "predict_proba": + if target_type == "binary" and y_pred.shape[1] <= 2: + if y_pred.shape[1] == 2: + col_idx = np.flatnonzero(classes == pos_label)[0] + y_pred = y_pred[:, col_idx] + else: + err_msg = ( + f"Got predict_proba of shape {y_pred.shape}, but need " + "classifier with two classes." + ) + raise ValueError(err_msg) + elif prediction_method.__name__ == "decision_function": + if target_type == "binary": + if pos_label == classes[0]: + y_pred *= -1 + else: # estimator is a regressor + if response_method != "predict": + raise ValueError( + f"{estimator.__class__.__name__} should either be a classifier to be " + f"used with response_method={response_method} or the response_method " + "should be 'predict'. Got a regressor with response_method=" + f"{response_method} instead." + ) + y_pred, pos_label = estimator.predict(X), None + + return y_pred, pos_label + + +def _get_response_values_binary(estimator, X, response_method, pos_label=None): + """Compute the response values of a binary classifier. + + Parameters + ---------- + estimator : estimator instance + Fitted classifier or a fitted :class:`~sklearn.pipeline.Pipeline` + in which the last estimator is a binary classifier. + + X : {array-like, sparse matrix} of shape (n_samples, n_features) + Input values. + + response_method: {'auto', 'predict_proba', 'decision_function'} + Specifies whether to use :term:`predict_proba` or + :term:`decision_function` as the target response. If set to 'auto', + :term:`predict_proba` is tried first and if it does not exist + :term:`decision_function` is tried next. + + pos_label : str or int, default=None + The class considered as the positive class when computing + the metrics. By default, `estimators.classes_[1]` is + considered as the positive class. + + Returns + ------- + y_pred: ndarray of shape (n_samples,) + Target scores calculated from the provided response_method + and pos_label. + + pos_label: str or int + The class considered as the positive class when computing + the metrics. + """ + classification_error = "Expected 'estimator' to be a binary classifier." + + check_is_fitted(estimator) + if not is_classifier(estimator): + raise ValueError( + classification_error + f" Got {estimator.__class__.__name__} instead." + ) + elif len(estimator.classes_) != 2: + raise ValueError( + classification_error + f" Got {len(estimator.classes_)} classes instead." + ) + + if response_method == "auto": + response_method = ["predict_proba", "decision_function"] + + return _get_response_values( + estimator, + X, + response_method, + pos_label=pos_label, + ) diff --git a/sklearn/utils/tests/test_mocking.py b/sklearn/utils/tests/test_mocking.py index a12c41256581a..718c62d5cc83b 100644 --- a/sklearn/utils/tests/test_mocking.py +++ b/sklearn/utils/tests/test_mocking.py @@ -10,7 +10,10 @@ from sklearn.utils import _safe_indexing from sklearn.utils._testing import _convert_container -from sklearn.utils._mocking import CheckingClassifier +from sklearn.utils._mocking import ( + _MockEstimatorOnOffPrediction, + CheckingClassifier, +) @pytest.fixture @@ -181,3 +184,29 @@ def test_checking_classifier_methods_to_check(iris, methods_to_check, predict_me getattr(clf, predict_method)(X) else: getattr(clf, predict_method)(X) + + +@pytest.mark.parametrize( + "response_methods", + [ + ["predict"], + ["predict", "predict_proba"], + ["predict", "decision_function"], + ["predict", "predict_proba", "decision_function"], + ], +) +def test_mock_estimator_on_off_prediction(iris, response_methods): + X, y = iris + estimator = _MockEstimatorOnOffPrediction(response_methods=response_methods) + + estimator.fit(X, y) + assert hasattr(estimator, "classes_") + assert_array_equal(estimator.classes_, np.unique(y)) + + possible_responses = ["predict", "predict_proba", "decision_function"] + for response in possible_responses: + if response in response_methods: + assert hasattr(estimator, response) + assert getattr(estimator, response)(X) == response + else: + assert not hasattr(estimator, response) diff --git a/sklearn/utils/tests/test_response.py b/sklearn/utils/tests/test_response.py new file mode 100644 index 0000000000000..0e2ce5fe5f038 --- /dev/null +++ b/sklearn/utils/tests/test_response.py @@ -0,0 +1,229 @@ +import numpy as np +import pytest + +from sklearn.datasets import load_iris, make_classification, make_regression +from sklearn.linear_model import ( + LinearRegression, + LogisticRegression, +) +from sklearn.svm import SVC +from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor +from sklearn.utils._mocking import _MockEstimatorOnOffPrediction +from sklearn.utils._testing import assert_allclose, assert_array_equal + +from sklearn.utils._response import _get_response_values, _get_response_values_binary + + +X, y = load_iris(return_X_y=True) +X_binary, y_binary = X[:100], y[:100] + + +@pytest.mark.parametrize("response_method", ["decision_function", "predict_proba"]) +def test_get_response_values_regressor_error(response_method): + """Check the error message with regressor an not supported response + method.""" + my_estimator = _MockEstimatorOnOffPrediction(response_methods=[response_method]) + X = "mocking_data", "mocking_target" + err_msg = f"{my_estimator.__class__.__name__} should either be a classifier" + with pytest.raises(ValueError, match=err_msg): + _get_response_values(my_estimator, X, response_method=response_method) + + +@pytest.mark.parametrize( + "estimator, response_method", + [ + (DecisionTreeClassifier(), "predict_proba"), + (SVC(), "decision_function"), + ], +) +def test_get_response_values_error_multiclass_classifier(estimator, response_method): + """Check that we raise an error with multiclass classifier and requesting + response values different from `predict`.""" + X, y = make_classification( + n_samples=10, n_clusters_per_class=1, n_classes=3, random_state=0 + ) + classifier = estimator.fit(X, y) + err_msg = "With a multiclass estimator, the response method should be predict" + with pytest.raises(ValueError, match=err_msg): + _get_response_values(classifier, X, response_method=response_method) + + +def test_get_response_values_regressor(): + """Check the behaviour of `_get_response_values` with regressor.""" + X, y = make_regression(n_samples=10, random_state=0) + regressor = LinearRegression().fit(X, y) + y_pred, pos_label = _get_response_values( + regressor, + X, + response_method="predict", + ) + assert_array_equal(y_pred, regressor.predict(X)) + assert pos_label is None + + +@pytest.mark.parametrize( + "response_method", + ["predict_proba", "decision_function", "predict"], +) +def test_get_response_values_classifier_unknown_pos_label(response_method): + """Check that `_get_response_values` raises the proper error message with + classifier.""" + X, y = make_classification(n_samples=10, n_classes=2, random_state=0) + classifier = LogisticRegression().fit(X, y) + + # provide a `pos_label` which is not in `y` + err_msg = r"pos_label=whatever is not a valid label: It should be one of \[0 1\]" + with pytest.raises(ValueError, match=err_msg): + _get_response_values( + classifier, + X, + response_method=response_method, + pos_label="whatever", + ) + + +def test_get_response_values_classifier_inconsistent_y_pred_for_binary_proba(): + """Check that `_get_response_values` will raise an error when `y_pred` has a + single class with `predict_proba`.""" + X, y_two_class = make_classification(n_samples=10, n_classes=2, random_state=0) + y_single_class = np.zeros_like(y_two_class) + classifier = DecisionTreeClassifier().fit(X, y_single_class) + + err_msg = ( + r"Got predict_proba of shape \(10, 1\), but need classifier with " + r"two classes" + ) + with pytest.raises(ValueError, match=err_msg): + _get_response_values(classifier, X, response_method="predict_proba") + + +def test_get_response_values_binary_classifier_decision_function(): + """Check the behaviour of `_get_response_values` with `decision_function` + and binary classifier.""" + X, y = make_classification( + n_samples=10, + n_classes=2, + weights=[0.3, 0.7], + random_state=0, + ) + classifier = LogisticRegression().fit(X, y) + response_method = "decision_function" + + # default `pos_label` + y_pred, pos_label = _get_response_values( + classifier, + X, + response_method=response_method, + pos_label=None, + ) + assert_allclose(y_pred, classifier.decision_function(X)) + assert pos_label == 1 + + # when forcing `pos_label=classifier.classes_[0]` + y_pred, pos_label = _get_response_values( + classifier, + X, + response_method=response_method, + pos_label=classifier.classes_[0], + ) + assert_allclose(y_pred, classifier.decision_function(X) * -1) + assert pos_label == 0 + + +def test_get_response_values_binary_classifier_predict_proba(): + """Check that `_get_response_values` with `predict_proba` and binary + classifier.""" + X, y = make_classification( + n_samples=10, + n_classes=2, + weights=[0.3, 0.7], + random_state=0, + ) + classifier = LogisticRegression().fit(X, y) + response_method = "predict_proba" + + # default `pos_label` + y_pred, pos_label = _get_response_values( + classifier, + X, + response_method=response_method, + pos_label=None, + ) + assert_allclose(y_pred, classifier.predict_proba(X)[:, 1]) + assert pos_label == 1 + + # when forcing `pos_label=classifier.classes_[0]` + y_pred, pos_label = _get_response_values( + classifier, + X, + response_method=response_method, + pos_label=classifier.classes_[0], + ) + assert_allclose(y_pred, classifier.predict_proba(X)[:, 0]) + assert pos_label == 0 + + +@pytest.mark.parametrize( + "estimator, X, y, err_msg, params", + [ + ( + DecisionTreeRegressor(), + X_binary, + y_binary, + "Expected 'estimator' to be a binary classifier", + {"response_method": "auto"}, + ), + ( + DecisionTreeClassifier(), + X_binary, + y_binary, + r"pos_label=unknown is not a valid label: It should be one of \[0 1\]", + {"response_method": "auto", "pos_label": "unknown"}, + ), + ( + DecisionTreeClassifier(), + X, + y, + "be a binary classifier. Got 3 classes instead.", + {"response_method": "predict_proba"}, + ), + ], +) +def test_get_response_error(estimator, X, y, err_msg, params): + """Check that we raise the proper error messages in _get_response_values_binary.""" + + estimator.fit(X, y) + with pytest.raises(ValueError, match=err_msg): + _get_response_values_binary(estimator, X, **params) + + +def test_get_response_predict_proba(): + """Check the behaviour of `_get_response_values_binary` using `predict_proba`.""" + classifier = DecisionTreeClassifier().fit(X_binary, y_binary) + y_proba, pos_label = _get_response_values_binary( + classifier, X_binary, response_method="predict_proba" + ) + np.testing.assert_allclose(y_proba, classifier.predict_proba(X_binary)[:, 1]) + assert pos_label == 1 + + y_proba, pos_label = _get_response_values_binary( + classifier, X_binary, response_method="predict_proba", pos_label=0 + ) + np.testing.assert_allclose(y_proba, classifier.predict_proba(X_binary)[:, 0]) + assert pos_label == 0 + + +def test_get_response_decision_function(): + """Check the behaviour of `_get_response_values_binary` using decision_function.""" + classifier = LogisticRegression().fit(X_binary, y_binary) + y_score, pos_label = _get_response_values_binary( + classifier, X_binary, response_method="decision_function" + ) + np.testing.assert_allclose(y_score, classifier.decision_function(X_binary)) + assert pos_label == 1 + + y_score, pos_label = _get_response_values_binary( + classifier, X_binary, response_method="decision_function", pos_label=0 + ) + np.testing.assert_allclose(y_score, classifier.decision_function(X_binary) * -1) + assert pos_label == 0 diff --git a/sklearn/utils/tests/test_validation.py b/sklearn/utils/tests/test_validation.py index ca522af287513..53eb776930af5 100644 --- a/sklearn/utils/tests/test_validation.py +++ b/sklearn/utils/tests/test_validation.py @@ -24,7 +24,13 @@ from sklearn.utils import as_float_array, check_array, check_symmetric from sklearn.utils import check_X_y from sklearn.utils import deprecated -from sklearn.utils._mocking import MockDataFrame + +# TODO: add this estimator into the _mocking module in a further refactoring +from sklearn.metrics.tests.test_score_objects import EstimatorWithFit +from sklearn.utils._mocking import ( + MockDataFrame, + _MockEstimatorOnOffPrediction, +) from sklearn.utils.fixes import parse_version from sklearn.utils.estimator_checks import _NotAnArray from sklearn.random_projection import _sparse_random_matrix @@ -53,6 +59,7 @@ _get_feature_names, _check_feature_names_in, _check_fit_params, + _check_response_method, ) from sklearn.base import BaseEstimator import sklearn @@ -1752,6 +1759,57 @@ def test_check_feature_names_in_pandas(): est.get_feature_names_out(["x1", "x2", "x3"]) +def test_check_response_method_unknown_method(): + """Check the error message when passing an unknown response method.""" + err_msg = ( + "RandomForestRegressor has none of the following attributes: unknown_method." + ) + with pytest.raises(AttributeError, match=err_msg): + _check_response_method(RandomForestRegressor(), "unknown_method") + + +@pytest.mark.parametrize( + "response_method", ["decision_function", "predict_proba", "predict"] +) +def test_check_response_method_not_supported_response_method(response_method): + """Check the error message when a response method is not supported by the + estimator.""" + err_msg = ( + f"EstimatorWithFit has none of the following attributes: {response_method}." + ) + with pytest.raises(AttributeError, match=err_msg): + _check_response_method(EstimatorWithFit(), response_method) + + +def test_check_response_method_list_str(): + """Check that we can pass a list of ordered method.""" + method_implemented = ["predict_proba"] + my_estimator = _MockEstimatorOnOffPrediction(method_implemented) + + X = "mocking_data" + + # raise an error when no methods are defined + response_method = ["decision_function", "predict"] + err_msg = ( + "_MockEstimatorOnOffPrediction has none of the following attributes: " + f"{', '.join(response_method)}." + ) + with pytest.raises(AttributeError, match=err_msg): + _check_response_method(my_estimator, response_method)(X) + + # check that we don't get issue when one of the method is defined + response_method = ["decision_function", "predict_proba"] + method_name_predicting = _check_response_method(my_estimator, response_method)(X) + assert method_name_predicting == "predict_proba" + + # check the order of the methods returned + method_implemented = ["predict_proba", "predict"] + my_estimator = _MockEstimatorOnOffPrediction(method_implemented) + response_method = ["decision_function", "predict", "predict_proba"] + method_name_predicting = _check_response_method(my_estimator, response_method)(X) + assert method_name_predicting == "predict" + + def test_boolean_series_remains_boolean(): """Regression test for gh-25145""" pd = importorskip("pandas") diff --git a/sklearn/utils/validation.py b/sklearn/utils/validation.py index e8978a086d001..3e1a3c13f834a 100644 --- a/sklearn/utils/validation.py +++ b/sklearn/utils/validation.py @@ -9,7 +9,7 @@ # Sylvain Marie # License: BSD 3 clause -from functools import wraps +from functools import reduce, wraps import warnings import numbers import operator @@ -1841,6 +1841,52 @@ def _allclose_dense_sparse(x, y, rtol=1e-7, atol=1e-9): ) +def _check_response_method(estimator, response_method): + """Check if `response_method` is available in estimator and return it. + + .. versionadded:: 1.3 + + Parameters + ---------- + estimator : estimator instance + Classifier or regressor to check. + + response_method : {"predict_proba", "decision_function", "predict"} or \ + list of such str + Specifies the response method to use get prediction from an estimator + (i.e. :term:`predict_proba`, :term:`decision_function` or + :term:`predict`). Possible choices are: + - if `str`, it corresponds to the name to the method to return; + - if a list of `str`, it provides the method names in order of + preference. The method returned corresponds to the first method in + the list and which is implemented by `estimator`. + + Returns + ------- + prediction_method : callable + Prediction method of estimator. + + Raises + ------ + AttributeError + If `response_method` is not available in `estimator`. + """ + if isinstance(response_method, str): + list_methods = [response_method] + else: + list_methods = response_method + + prediction_method = [getattr(estimator, method, None) for method in list_methods] + prediction_method = reduce(lambda x, y: x or y, prediction_method) + if prediction_method is None: + raise AttributeError( + f"{estimator.__class__.__name__} has none of the following attributes: " + f"{', '.join(list_methods)}." + ) + + return prediction_method + + def _check_fit_params(X, fit_params, indices=None): """Check and validate the parameters passed during `fit`. From 79d12430d97e8a3d245701dc85995183a5e5a718 Mon Sep 17 00:00:00 2001 From: Julien Jerphanion Date: Sat, 25 Mar 2023 20:25:47 +0100 Subject: [PATCH 103/230] MAINT Extend message for large sparse matrices support (#25961) Co-authored-by: Meekail Zain <34613774+Micky774@users.noreply.github.com> --- sklearn/utils/tests/test_validation.py | 2 +- sklearn/utils/validation.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sklearn/utils/tests/test_validation.py b/sklearn/utils/tests/test_validation.py index 53eb776930af5..7dcf77913e7c6 100644 --- a/sklearn/utils/tests/test_validation.py +++ b/sklearn/utils/tests/test_validation.py @@ -632,7 +632,7 @@ def test_check_array_accept_large_sparse_raise_exception(X_64bit): # When large sparse are not allowed msg = ( "Only sparse matrices with 32-bit integer indices " - "are accepted. Got int64 indices." + "are accepted. Got int64 indices. Please do report" ) with pytest.raises(ValueError, match=msg): check_array(X_64bit, accept_sparse=True, accept_large_sparse=False) diff --git a/sklearn/utils/validation.py b/sklearn/utils/validation.py index 3e1a3c13f834a..2ae5c6a42d172 100644 --- a/sklearn/utils/validation.py +++ b/sklearn/utils/validation.py @@ -987,8 +987,11 @@ def _check_large_sparse(X, accept_large_sparse=False): indices_datatype = getattr(X, key).dtype if indices_datatype not in supported_indices: raise ValueError( - "Only sparse matrices with 32-bit integer" - " indices are accepted. Got %s indices." % indices_datatype + "Only sparse matrices with 32-bit integer indices are accepted." + f" Got {indices_datatype} indices. Please do report a minimal" + " reproducer on scikit-learn issue tracker so that support for" + " your use-case can be studied by maintainers. See:" + " https://scikit-learn.org/dev/developers/minimal_reproducer.html" ) From 4e35a0b642efa7e7ab93b09f87b0bc5abdb51489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Mon, 27 Mar 2023 15:56:04 +0200 Subject: [PATCH 104/230] MAINT Parameters validation for datasets.make_gaussian_quantiles (#25959) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/datasets/_samples_generator.py | 11 +++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 12 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 192f8e6759ddb..2352b5e50c6c5 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1681,6 +1681,17 @@ def make_s_curve(n_samples=100, *, noise=0.0, random_state=None): return X, t +@validate_params( + { + "mean": ["array-like", None], + "cov": [Interval(Real, 0, None, closed="left")], + "n_samples": [Interval(Integral, 1, None, closed="left")], + "n_features": [Interval(Integral, 1, None, closed="left")], + "n_classes": [Interval(Integral, 1, None, closed="left")], + "shuffle": ["boolean"], + "random_state": ["random_state"], + } +) def make_gaussian_quantiles( *, mean=None, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 4b1934c378fbf..9e1f95c4d057a 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -132,6 +132,7 @@ def _check_function_param_validation( "sklearn.datasets.make_circles", "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", + "sklearn.datasets.make_gaussian_quantiles", "sklearn.datasets.make_low_rank_matrix", "sklearn.datasets.make_multilabel_classification", "sklearn.datasets.make_regression", From 611858b865a9986af48b955a4770d9272f8e5d92 Mon Sep 17 00:00:00 2001 From: "A.H.Mansouri" <83764851+A-H-Mansoury@users.noreply.github.com> Date: Mon, 27 Mar 2023 19:07:05 +0330 Subject: [PATCH 105/230] MAINT Parameters validation for sklearn.metrics.d2_tweedie_score (#25975) --- sklearn/metrics/_regression.py | 13 ++++++++++++- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sklearn/metrics/_regression.py b/sklearn/metrics/_regression.py index c351320a48278..b19fc2e7f3f70 100644 --- a/sklearn/metrics/_regression.py +++ b/sklearn/metrics/_regression.py @@ -1238,6 +1238,17 @@ def mean_gamma_deviance(y_true, y_pred, *, sample_weight=None): return mean_tweedie_deviance(y_true, y_pred, sample_weight=sample_weight, power=2) +@validate_params( + { + "y_true": ["array-like"], + "y_pred": ["array-like"], + "sample_weight": ["array-like", None], + "power": [ + Interval(Real, None, 0, closed="right"), + Interval(Real, 1, None, closed="left"), + ], + } +) def d2_tweedie_score(y_true, y_pred, *, sample_weight=None, power=0): """D^2 regression score function, fraction of Tweedie deviance explained. @@ -1257,7 +1268,7 @@ def d2_tweedie_score(y_true, y_pred, *, sample_weight=None, power=0): y_pred : array-like of shape (n_samples,) Estimated target values. - sample_weight : array-like of shape (n_samples,), optional + sample_weight : array-like of shape (n_samples,), default=None Sample weights. power : float, default=0 diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 9e1f95c4d057a..8b722502df25f 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -162,6 +162,7 @@ def _check_function_param_validation( "sklearn.metrics.confusion_matrix", "sklearn.metrics.coverage_error", "sklearn.metrics.d2_pinball_score", + "sklearn.metrics.d2_tweedie_score", "sklearn.metrics.dcg_score", "sklearn.metrics.det_curve", "sklearn.metrics.f1_score", From e0424bc04d727fc90440b965cbaccfd6f369dee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Mon, 27 Mar 2023 17:37:56 +0200 Subject: [PATCH 106/230] MAINT Parameters validation for datasets.make_hastie_10_2 (#25967) --- sklearn/datasets/_samples_generator.py | 6 ++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 7 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 2352b5e50c6c5..d31ed5def2dd4 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -476,6 +476,12 @@ def sample_example(): return X, Y +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "random_state": ["random_state"], + } +) def make_hastie_10_2(n_samples=12000, *, random_state=None): """Generate data for binary classification used in Hastie et al. 2009, Example 10.2. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 8b722502df25f..3c0db8d28257f 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -133,6 +133,7 @@ def _check_function_param_validation( "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", "sklearn.datasets.make_gaussian_quantiles", + "sklearn.datasets.make_hastie_10_2", "sklearn.datasets.make_low_rank_matrix", "sklearn.datasets.make_multilabel_classification", "sklearn.datasets.make_regression", From 2e8eec24181a6fe9a4a111a6cc4cf559c5a88dbf Mon Sep 17 00:00:00 2001 From: Xiao Yuan Date: Tue, 28 Mar 2023 00:12:27 +0800 Subject: [PATCH 107/230] MAINT Parameters validation for preprocessing.minmax_scale (#25962) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/preprocessing/_data.py | 10 ++++++++-- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sklearn/preprocessing/_data.py b/sklearn/preprocessing/_data.py index a363db0bbc8c2..d72b0294fa4f4 100644 --- a/sklearn/preprocessing/_data.py +++ b/sklearn/preprocessing/_data.py @@ -24,7 +24,7 @@ ClassNamePrefixFeaturesOutMixin, ) from ..utils import check_array -from ..utils._param_validation import Interval, StrOptions +from ..utils._param_validation import Interval, Options, StrOptions, validate_params from ..utils.extmath import _incremental_mean_and_var, row_norms from ..utils.sparsefuncs_fast import ( inplace_csr_row_normalize_l1, @@ -546,6 +546,12 @@ def _more_tags(self): return {"allow_nan": True} +@validate_params( + { + "X": ["array-like"], + "axis": [Options(Integral, {0, 1})], + } +) def minmax_scale(X, feature_range=(0, 1), *, axis=0, copy=True): """Transform features by scaling each feature to a given range. @@ -582,7 +588,7 @@ def minmax_scale(X, feature_range=(0, 1), *, axis=0, copy=True): feature_range : tuple (min, max), default=(0, 1) Desired range of transformed data. - axis : int, default=0 + axis : {0, 1}, default=0 Axis used to scale along. If 0, independently scale each feature, otherwise (if 1) scale each sample. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 3c0db8d28257f..62c7b63d43c77 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -230,6 +230,7 @@ def test_function_param_validation(func_module): ("sklearn.decomposition.dict_learning", "sklearn.decomposition.DictionaryLearning"), ("sklearn.decomposition.fastica", "sklearn.decomposition.FastICA"), ("sklearn.decomposition.non_negative_factorization", "sklearn.decomposition.NMF"), + ("sklearn.preprocessing.minmax_scale", "sklearn.preprocessing.MinMaxScaler"), ] From b0390c1d3be6abe770c1c951bbe8896917d9bfe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Mon, 27 Mar 2023 20:42:11 +0200 Subject: [PATCH 108/230] MAINT Parameters validation for datasets.make_checkerboard (#25955) --- sklearn/datasets/_samples_generator.py | 15 +++++++++++++-- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index d31ed5def2dd4..3913ad6eedfb4 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1899,6 +1899,17 @@ def make_biclusters( return result, rows, cols +@validate_params( + { + "shape": [tuple], + "n_clusters": [Interval(Integral, 1, None, closed="left"), "array-like"], + "noise": [Interval(Real, 0, None, closed="left")], + "minval": [Interval(Real, None, None, closed="neither")], + "maxval": [Interval(Real, None, None, closed="neither")], + "shuffle": ["boolean"], + "random_state": ["random_state"], + } +) def make_checkerboard( shape, n_clusters, @@ -1924,10 +1935,10 @@ def make_checkerboard( noise : float, default=0.0 The standard deviation of the gaussian noise. - minval : int, default=10 + minval : float, default=10 Minimum value of a bicluster. - maxval : int, default=100 + maxval : float, default=100 Maximum value of a bicluster. shuffle : bool, default=True diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 62c7b63d43c77..5579ad0215ff1 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -129,6 +129,7 @@ def _check_function_param_validation( "sklearn.datasets.fetch_olivetti_faces", "sklearn.datasets.load_svmlight_file", "sklearn.datasets.load_svmlight_files", + "sklearn.datasets.make_checkerboard", "sklearn.datasets.make_circles", "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", From 1b8116841f4552255cdb2e44bd9923ca7168d6ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Mon, 27 Mar 2023 21:46:25 +0200 Subject: [PATCH 109/230] MAINT Parameters validation for datasets.make_biclusters (#25945) --- sklearn/datasets/_samples_generator.py | 17 ++++++++++++++--- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 3913ad6eedfb4..2eba3f3e31046 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1802,6 +1802,17 @@ def _shuffle(data, random_state=None): return result, row_idx, col_idx +@validate_params( + { + "shape": [tuple], + "n_clusters": [Interval(Integral, 1, None, closed="left")], + "noise": [Interval(Real, 0, None, closed="left")], + "minval": [Interval(Real, None, None, closed="neither")], + "maxval": [Interval(Real, None, None, closed="neither")], + "shuffle": ["boolean"], + "random_state": ["random_state"], + } +) def make_biclusters( shape, n_clusters, @@ -1818,7 +1829,7 @@ def make_biclusters( Parameters ---------- - shape : iterable of shape (n_rows, n_cols) + shape : tuple of shape (n_rows, n_cols) The shape of the result. n_clusters : int @@ -1827,10 +1838,10 @@ def make_biclusters( noise : float, default=0.0 The standard deviation of the gaussian noise. - minval : int, default=10 + minval : float, default=10 Minimum value of a bicluster. - maxval : int, default=100 + maxval : float, default=100 Maximum value of a bicluster. shuffle : bool, default=True diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 5579ad0215ff1..5770aca19e1cc 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -129,6 +129,7 @@ def _check_function_param_validation( "sklearn.datasets.fetch_olivetti_faces", "sklearn.datasets.load_svmlight_file", "sklearn.datasets.load_svmlight_files", + "sklearn.datasets.make_biclusters", "sklearn.datasets.make_checkerboard", "sklearn.datasets.make_circles", "sklearn.datasets.make_classification", From dd6e21099b9b96d0d6f5b37a143c1953c80f3cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Mon, 27 Mar 2023 22:51:28 +0200 Subject: [PATCH 110/230] MAINT Parameters validation for datasets.make_moons (#25971) --- sklearn/datasets/_samples_generator.py | 8 ++++++++ sklearn/datasets/tests/test_samples_generator.py | 6 ------ sklearn/tests/test_public_functions.py | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 2eba3f3e31046..7b078eda40357 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -778,6 +778,14 @@ def make_circles( return X, y +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left"), tuple], + "shuffle": ["boolean"], + "noise": [Interval(Real, 0, None, closed="left"), None], + "random_state": ["random_state"], + } +) def make_moons(n_samples=100, *, shuffle=True, noise=None, random_state=None): """Make two interleaving half circles. diff --git a/sklearn/datasets/tests/test_samples_generator.py b/sklearn/datasets/tests/test_samples_generator.py index e722ed5c4f02a..cd23fc5016672 100644 --- a/sklearn/datasets/tests/test_samples_generator.py +++ b/sklearn/datasets/tests/test_samples_generator.py @@ -636,12 +636,6 @@ def test_make_moons_unbalanced(): assert X.shape == (12, 2), "X shape mismatch" assert y.shape == (12,), "y shape mismatch" - with pytest.raises( - ValueError, - match=r"`n_samples` can be either an int " r"or a two-element tuple.", - ): - make_moons(n_samples=[1, 2, 3]) - with pytest.raises( ValueError, match=r"`n_samples` can be either an int " r"or a two-element tuple.", diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 5770aca19e1cc..d960639cee7fd 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -137,6 +137,7 @@ def _check_function_param_validation( "sklearn.datasets.make_gaussian_quantiles", "sklearn.datasets.make_hastie_10_2", "sklearn.datasets.make_low_rank_matrix", + "sklearn.datasets.make_moons", "sklearn.datasets.make_multilabel_classification", "sklearn.datasets.make_regression", "sklearn.datasets.make_sparse_coded_signal", From aab411b5126f83303550f2426ac6e0330d757e5d Mon Sep 17 00:00:00 2001 From: Christian Lorentzen Date: Tue, 28 Mar 2023 17:43:49 +0200 Subject: [PATCH 111/230] DOC replace deviance by loss in docstring of GradientBoosting (#25968) --- sklearn/ensemble/_gb.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sklearn/ensemble/_gb.py b/sklearn/ensemble/_gb.py index fab8d8710a868..33448c280715b 100644 --- a/sklearn/ensemble/_gb.py +++ b/sklearn/ensemble/_gb.py @@ -622,7 +622,7 @@ def _fit_stages( X_csr, ) - # track deviance (= loss) + # track loss if do_oob: self.train_score_[i] = loss_( y[sample_mask], @@ -1056,28 +1056,28 @@ class GradientBoostingClassifier(ClassifierMixin, BaseGradientBoosting): :func:`sklearn.inspection.permutation_importance` as an alternative. oob_improvement_ : ndarray of shape (n_estimators,) - The improvement in loss (= deviance) on the out-of-bag samples + The improvement in loss on the out-of-bag samples relative to the previous iteration. ``oob_improvement_[0]`` is the improvement in loss of the first stage over the ``init`` estimator. Only available if ``subsample < 1.0``. oob_scores_ : ndarray of shape (n_estimators,) - The full history of the loss (= deviance) values on the out-of-bag + The full history of the loss values on the out-of-bag samples. Only available if `subsample < 1.0`. .. versionadded:: 1.3 oob_score_ : float - The last value of the loss (= deviance) on the out-of-bag samples. It is + The last value of the loss on the out-of-bag samples. It is the same as `oob_scores_[-1]`. Only available if `subsample < 1.0`. .. versionadded:: 1.3 train_score_ : ndarray of shape (n_estimators,) - The i-th score ``train_score_[i]`` is the deviance (= loss) of the + The i-th score ``train_score_[i]`` is the loss of the model at iteration ``i`` on the in-bag sample. - If ``subsample == 1`` this is the deviance on the training data. + If ``subsample == 1`` this is the loss on the training data. init_ : estimator The estimator that provides the initial predictions. @@ -1619,28 +1619,28 @@ class GradientBoostingRegressor(RegressorMixin, BaseGradientBoosting): :func:`sklearn.inspection.permutation_importance` as an alternative. oob_improvement_ : ndarray of shape (n_estimators,) - The improvement in loss (= deviance) on the out-of-bag samples + The improvement in loss on the out-of-bag samples relative to the previous iteration. ``oob_improvement_[0]`` is the improvement in loss of the first stage over the ``init`` estimator. Only available if ``subsample < 1.0``. oob_scores_ : ndarray of shape (n_estimators,) - The full history of the loss (= deviance) values on the out-of-bag + The full history of the loss values on the out-of-bag samples. Only available if `subsample < 1.0`. .. versionadded:: 1.3 oob_score_ : float - The last value of the loss (= deviance) on the out-of-bag samples. It is + The last value of the loss on the out-of-bag samples. It is the same as `oob_scores_[-1]`. Only available if `subsample < 1.0`. .. versionadded:: 1.3 train_score_ : ndarray of shape (n_estimators,) - The i-th score ``train_score_[i]`` is the deviance (= loss) of the + The i-th score ``train_score_[i]`` is the loss of the model at iteration ``i`` on the in-bag sample. - If ``subsample == 1`` this is the deviance on the training data. + If ``subsample == 1`` this is the loss on the training data. init_ : estimator The estimator that provides the initial predictions. From 3a2b132efd2929b23451dfa7f1f4f333198d0a83 Mon Sep 17 00:00:00 2001 From: Christian Veenhuis Date: Tue, 28 Mar 2023 18:34:56 +0200 Subject: [PATCH 112/230] MAINT Fix broken link in feature_selection/_univariate_selection.py (#25984) --- sklearn/feature_selection/_univariate_selection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/feature_selection/_univariate_selection.py b/sklearn/feature_selection/_univariate_selection.py index 1929daa8ae8c8..1cdd636c24f9e 100644 --- a/sklearn/feature_selection/_univariate_selection.py +++ b/sklearn/feature_selection/_univariate_selection.py @@ -85,7 +85,7 @@ def f_oneway(*args): ---------- .. [1] Lowry, Richard. "Concepts and Applications of Inferential Statistics". Chapter 14. - http://faculty.vassar.edu/lowry/ch14pt1.html + http://vassarstats.net/textbook .. [2] Heiman, G.W. Research Methods in Statistics. 2002. """ From a9ab99d4125964d015fb5a29e956ff63a0798be3 Mon Sep 17 00:00:00 2001 From: Boris Feld Date: Tue, 28 Mar 2023 18:54:15 +0200 Subject: [PATCH 113/230] DOC Update model_persistence.rst to fix skops example (#25993) Co-authored-by: adrinjalali --- doc/model_persistence.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/model_persistence.rst b/doc/model_persistence.rst index 9d3d6e941cdc5..53f01fd019d79 100644 --- a/doc/model_persistence.rst +++ b/doc/model_persistence.rst @@ -126,7 +126,7 @@ trusted by you. You can get existing unknown types in a dumped object / file using :func:`skops.io.get_untrusted_types`, and after checking its contents, pass it to the load function:: - unknown_types = sio.get_untrusted_types(obj) + unknown_types = sio.get_untrusted_types(data=obj) clf = sio.loads(obj, trusted=unknown_types) If you trust the source of the file / object, you can pass ``trusted=True``:: From 3cbc887b23504fdf926483aa8f62bf81783d7d7d Mon Sep 17 00:00:00 2001 From: Carla J Date: Tue, 28 Mar 2023 20:56:46 +0200 Subject: [PATCH 114/230] DOC Specified meaning for max_patches=None in extract_patches_2d (#25996) --- sklearn/feature_extraction/image.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sklearn/feature_extraction/image.py b/sklearn/feature_extraction/image.py index 06cbe3b423276..25f494a155a2f 100644 --- a/sklearn/feature_extraction/image.py +++ b/sklearn/feature_extraction/image.py @@ -371,7 +371,8 @@ def extract_patches_2d(image, patch_size, *, max_patches=None, random_state=None max_patches : int or float, default=None The maximum number of patches to extract. If `max_patches` is a float between 0 and 1, it is taken to be a proportion of the total number - of patches. + of patches. If `max_patches` is None it corresponds to the total number + of patches that can be extracted. random_state : int, RandomState instance, default=None Determines the random number generator used for random sampling when From fbf7a0e14f508615d963138f7b6bf92099590a9e Mon Sep 17 00:00:00 2001 From: windiana42 <61181806+windiana42@users.noreply.github.com> Date: Tue, 28 Mar 2023 21:05:41 +0200 Subject: [PATCH 115/230] DOC document that last step is never cached in pipeline (#25995) Co-authored-by: Guillaume Lemaitre --- doc/modules/compose.rst | 2 +- sklearn/pipeline.py | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/modules/compose.rst b/doc/modules/compose.rst index 4a61b5ec5f118..5bcee9550b968 100644 --- a/doc/modules/compose.rst +++ b/doc/modules/compose.rst @@ -198,7 +198,7 @@ after calling ``fit``. This feature is used to avoid computing the fit transformers within a pipeline if the parameters and input data are identical. A typical example is the case of a grid search in which the transformers can be fitted only once and reused for -each configuration. +each configuration. The last step will never be cached, even if it is a transformer. The parameter ``memory`` is needed in order to cache the transformers. ``memory`` can be either a string containing the directory where to cache the diff --git a/sklearn/pipeline.py b/sklearn/pipeline.py index 94d9465d7f819..a604bb6fc6e6e 100644 --- a/sklearn/pipeline.py +++ b/sklearn/pipeline.py @@ -80,13 +80,13 @@ class Pipeline(_BaseComposition): estimator. memory : str or object with the joblib.Memory interface, default=None - Used to cache the fitted transformers of the pipeline. By default, - no caching is performed. If a string is given, it is the path to - the caching directory. Enabling caching triggers a clone of - the transformers before fitting. Therefore, the transformer - instance given to the pipeline cannot be inspected - directly. Use the attribute ``named_steps`` or ``steps`` to - inspect estimators within the pipeline. Caching the + Used to cache the fitted transformers of the pipeline. The last step + will never be cached, even if it is a transformer. By default, no + caching is performed. If a string is given, it is the path to the + caching directory. Enabling caching triggers a clone of the transformers + before fitting. Therefore, the transformer instance given to the + pipeline cannot be inspected directly. Use the attribute ``named_steps`` + or ``steps`` to inspect estimators within the pipeline. Caching the transformers is advantageous when fitting is time consuming. verbose : bool, default=False @@ -858,13 +858,13 @@ def make_pipeline(*steps, memory=None, verbose=False): List of the scikit-learn estimators that are chained together. memory : str or object with the joblib.Memory interface, default=None - Used to cache the fitted transformers of the pipeline. By default, - no caching is performed. If a string is given, it is the path to - the caching directory. Enabling caching triggers a clone of - the transformers before fitting. Therefore, the transformer - instance given to the pipeline cannot be inspected - directly. Use the attribute ``named_steps`` or ``steps`` to - inspect estimators within the pipeline. Caching the + Used to cache the fitted transformers of the pipeline. The last step + will never be cached, even if it is a transformer. By default, no + caching is performed. If a string is given, it is the path to the + caching directory. Enabling caching triggers a clone of the transformers + before fitting. Therefore, the transformer instance given to the + pipeline cannot be inspected directly. Use the attribute ``named_steps`` + or ``steps`` to inspect estimators within the pipeline. Caching the transformers is advantageous when fitting is time consuming. verbose : bool, default=False From 421c7f34c856314c64729f9583645813edfbbd78 Mon Sep 17 00:00:00 2001 From: Yao Xiao <108576690+Charlie-XIAO@users.noreply.github.com> Date: Wed, 29 Mar 2023 05:11:35 +0800 Subject: [PATCH 116/230] FIX SequentialFeatureSelector throws IndexError when cv is a generator (#25973) --- doc/whats_new/v1.3.rst | 3 +++ sklearn/feature_selection/_sequential.py | 12 ++++++---- .../tests/test_sequential.py | 24 +++++++++++++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 51b4214145216..add8f896dcb1a 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -146,6 +146,9 @@ Changelog - |Enhancement| All selectors in :mod:`sklearn.feature_selection` will preserve a DataFrame's dtype when transformed. :pr:`25102` by `Thomas Fan`_. +- |Fix| :class:`feature_selection.SequentialFeatureSelector`'s `cv` parameter + now supports generators. :pr:`25973` by `Yao Xiao `. + :mod:`sklearn.base` ................... diff --git a/sklearn/feature_selection/_sequential.py b/sklearn/feature_selection/_sequential.py index e983c55de7d25..2498cd53b39f6 100644 --- a/sklearn/feature_selection/_sequential.py +++ b/sklearn/feature_selection/_sequential.py @@ -8,12 +8,12 @@ import warnings from ._base import SelectorMixin -from ..base import BaseEstimator, MetaEstimatorMixin, clone +from ..base import BaseEstimator, MetaEstimatorMixin, clone, is_classifier from ..utils._param_validation import HasMethods, Hidden, Interval, StrOptions from ..utils._param_validation import RealNotInt from ..utils._tags import _safe_tags from ..utils.validation import check_is_fitted -from ..model_selection import cross_val_score +from ..model_selection import cross_val_score, check_cv from ..metrics import get_scorer_names @@ -259,6 +259,8 @@ def fit(self, X, y=None): if self.tol is not None and self.tol < 0 and self.direction == "forward": raise ValueError("tol must be positive when doing forward selection") + cv = check_cv(self.cv, y, classifier=is_classifier(self.estimator)) + cloned_estimator = clone(self.estimator) # the current mask corresponds to the set of features: @@ -275,7 +277,7 @@ def fit(self, X, y=None): is_auto_select = self.tol is not None and self.n_features_to_select == "auto" for _ in range(n_iterations): new_feature_idx, new_score = self._get_best_new_feature_score( - cloned_estimator, X, y, current_mask + cloned_estimator, X, y, cv, current_mask ) if is_auto_select and ((new_score - old_score) < self.tol): break @@ -291,7 +293,7 @@ def fit(self, X, y=None): return self - def _get_best_new_feature_score(self, estimator, X, y, current_mask): + def _get_best_new_feature_score(self, estimator, X, y, cv, current_mask): # Return the best new feature and its score to add to the current_mask, # i.e. return the best new feature and its score to add (resp. remove) # when doing forward selection (resp. backward selection). @@ -309,7 +311,7 @@ def _get_best_new_feature_score(self, estimator, X, y, current_mask): estimator, X_new, y, - cv=self.cv, + cv=cv, scoring=self.scoring, n_jobs=self.n_jobs, ).mean() diff --git a/sklearn/feature_selection/tests/test_sequential.py b/sklearn/feature_selection/tests/test_sequential.py index f6451a36005ac..98134addc39e7 100644 --- a/sklearn/feature_selection/tests/test_sequential.py +++ b/sklearn/feature_selection/tests/test_sequential.py @@ -6,11 +6,12 @@ from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline from sklearn.feature_selection import SequentialFeatureSelector -from sklearn.datasets import make_regression, make_blobs +from sklearn.datasets import make_regression, make_blobs, make_classification from sklearn.linear_model import LinearRegression from sklearn.ensemble import HistGradientBoostingRegressor -from sklearn.model_selection import cross_val_score +from sklearn.model_selection import cross_val_score, LeaveOneGroupOut from sklearn.cluster import KMeans +from sklearn.neighbors import KNeighborsClassifier def test_bad_n_features_to_select(): @@ -314,3 +315,22 @@ def test_backward_neg_tol(): assert 0 < sfs.get_support().sum() < X.shape[1] assert new_score < initial_score + + +def test_cv_generator_support(): + """Check that no exception raised when cv is generator + + non-regression test for #25957 + """ + X, y = make_classification(random_state=0) + + groups = np.zeros_like(y, dtype=int) + groups[y.size // 2 :] = 1 + + cv = LeaveOneGroupOut() + splits = cv.split(X, y, groups=groups) + + knc = KNeighborsClassifier(n_neighbors=5) + + sfs = SequentialFeatureSelector(knc, n_features_to_select=5, cv=splits) + sfs.fit(X, y) From 446209a44a8cc02c365af00b1e3657b4fa8bc0dc Mon Sep 17 00:00:00 2001 From: "Thomas J. Fan" Date: Wed, 29 Mar 2023 04:08:25 -0400 Subject: [PATCH 117/230] ENH Adds infrequent categories support to OrdinalEncoder (#25677) Co-authored-by: Tim Head Co-authored-by: Olivier Grisel Co-authored-by: Andreas Mueller --- doc/modules/preprocessing.rst | 49 +- doc/whats_new/v1.3.rst | 5 + sklearn/preprocessing/_encoders.py | 537 ++++++++++++------- sklearn/preprocessing/tests/test_encoders.py | 253 +++++++++ 4 files changed, 657 insertions(+), 187 deletions(-) diff --git a/doc/modules/preprocessing.rst b/doc/modules/preprocessing.rst index 86f2d29cf4ecf..dc151871874d4 100644 --- a/doc/modules/preprocessing.rst +++ b/doc/modules/preprocessing.rst @@ -729,14 +729,15 @@ separate categories:: See :ref:`dict_feature_extraction` for categorical features that are represented as a dict, not as scalars. -.. _one_hot_encoder_infrequent_categories: +.. _encoder_infrequent_categories: Infrequent categories --------------------- -:class:`OneHotEncoder` supports aggregating infrequent categories into a single -output for each feature. The parameters to enable the gathering of infrequent -categories are `min_frequency` and `max_categories`. +:class:`OneHotEncoder` and :class:`OrdinalEncoder` support aggregating +infrequent categories into a single output for each feature. The parameters to +enable the gathering of infrequent categories are `min_frequency` and +`max_categories`. 1. `min_frequency` is either an integer greater or equal to 1, or a float in the interval `(0.0, 1.0)`. If `min_frequency` is an integer, categories with @@ -750,11 +751,47 @@ categories are `min_frequency` and `max_categories`. input feature. `max_categories` includes the feature that combines infrequent categories. -In the following example, the categories, `'dog', 'snake'` are considered -infrequent:: +In the following example with :class:`OrdinalEncoder`, the categories `'dog' and +'snake'` are considered infrequent:: >>> X = np.array([['dog'] * 5 + ['cat'] * 20 + ['rabbit'] * 10 + ... ['snake'] * 3], dtype=object).T + >>> enc = preprocessing.OrdinalEncoder(min_frequency=6).fit(X) + >>> enc.infrequent_categories_ + [array(['dog', 'snake'], dtype=object)] + >>> enc.transform(np.array([['dog'], ['cat'], ['rabbit'], ['snake']])) + array([[2.], + [0.], + [1.], + [2.]]) + +:class:`OrdinalEncoder`'s `max_categories` do **not** take into account missing +or unknown categories. Setting `unknown_value` or `encoded_missing_value` to an +integer will increase the number of unique integer codes by one each. This can +result in up to `max_categories + 2` integer codes. In the following example, +"a" and "d" are considered infrequent and grouped together into a single +category, "b" and "c" are their own categories, unknown values are encoded as 3 +and missing values are encoded as 4. + + >>> X_train = np.array( + ... [["a"] * 5 + ["b"] * 20 + ["c"] * 10 + ["d"] * 3 + [np.nan]], + ... dtype=object).T + >>> enc = preprocessing.OrdinalEncoder( + ... handle_unknown="use_encoded_value", unknown_value=3, + ... max_categories=3, encoded_missing_value=4) + >>> _ = enc.fit(X_train) + >>> X_test = np.array([["a"], ["b"], ["c"], ["d"], ["e"], [np.nan]], dtype=object) + >>> enc.transform(X_test) + array([[2.], + [0.], + [1.], + [2.], + [3.], + [4.]]) + +Similarity, :class:`OneHotEncoder` can be configured to group together infrequent +categories:: + >>> enc = preprocessing.OneHotEncoder(min_frequency=6, sparse_output=False).fit(X) >>> enc.infrequent_categories_ [array(['dog', 'snake'], dtype=object)] diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index add8f896dcb1a..07b581f2104b1 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -396,6 +396,11 @@ Changelog :pr:`24935` by :user:`Seladus `, :user:`Guillaume Lemaitre `, and :user:`Dea María Léon `, :pr:`25257` by :user:`Gleb Levitski `. +- |Feature| :class:`preprocessing.OrdinalEncoder` now supports grouping + infrequent categories into a single feature. Grouping infrequent categories + is enabled by specifying how to select infrequent categories with + `min_frequency` or `max_categories`. :pr:`25677` by `Thomas Fan`_. + - |Fix| :class:`AdditiveChi2Sampler` is now stateless. The `sample_interval_` attribute is deprecated and will be removed in 1.5. :pr:`25190` by :user:`Vincent Maladière `. diff --git a/sklearn/preprocessing/_encoders.py b/sklearn/preprocessing/_encoders.py index f985a4a4e18b3..1962f571cfbaa 100644 --- a/sklearn/preprocessing/_encoders.py +++ b/sklearn/preprocessing/_encoders.py @@ -68,8 +68,14 @@ def _check_X(self, X, force_all_finite=True): return X_columns, n_samples, n_features def _fit( - self, X, handle_unknown="error", force_all_finite=True, return_counts=False + self, + X, + handle_unknown="error", + force_all_finite=True, + return_counts=False, + return_and_ignore_missing_for_infrequent=False, ): + self._check_infrequent_enabled() self._check_n_features(X, reset=True) self._check_feature_names(X, reset=True) X_list, n_samples, n_features = self._check_X( @@ -86,13 +92,14 @@ def _fit( self.categories_ = [] category_counts = [] + compute_counts = return_counts or self._infrequent_enabled for i in range(n_features): Xi = X_list[i] if self.categories == "auto": - result = _unique(Xi, return_counts=return_counts) - if return_counts: + result = _unique(Xi, return_counts=compute_counts) + if compute_counts: cats, counts = result category_counts.append(counts) else: @@ -139,7 +146,7 @@ def _fit( " during fit".format(diff, i) ) raise ValueError(msg) - if return_counts: + if compute_counts: category_counts.append(_get_counts(Xi, cats)) self.categories_.append(cats) @@ -147,10 +154,31 @@ def _fit( output = {"n_samples": n_samples} if return_counts: output["category_counts"] = category_counts + + missing_indices = {} + if return_and_ignore_missing_for_infrequent: + for feature_idx, categories_for_idx in enumerate(self.categories_): + for category_idx, category in enumerate(categories_for_idx): + if is_scalar_nan(category): + missing_indices[feature_idx] = category_idx + break + output["missing_indices"] = missing_indices + + if self._infrequent_enabled: + self._fit_infrequent_category_mapping( + n_samples, + category_counts, + missing_indices, + ) return output def _transform( - self, X, handle_unknown="error", force_all_finite=True, warn_on_unknown=False + self, + X, + handle_unknown="error", + force_all_finite=True, + warn_on_unknown=False, + ignore_category_indices=None, ): self._check_feature_names(X, reset=False) self._check_n_features(X, reset=False) @@ -207,8 +235,209 @@ def _transform( UserWarning, ) + self._map_infrequent_categories(X_int, X_mask, ignore_category_indices) return X_int, X_mask + @property + def infrequent_categories_(self): + """Infrequent categories for each feature.""" + # raises an AttributeError if `_infrequent_indices` is not defined + infrequent_indices = self._infrequent_indices + return [ + None if indices is None else category[indices] + for category, indices in zip(self.categories_, infrequent_indices) + ] + + def _check_infrequent_enabled(self): + """ + This functions checks whether _infrequent_enabled is True or False. + This has to be called after parameter validation in the fit function. + """ + max_categories = getattr(self, "max_categories", None) + min_frequency = getattr(self, "min_frequency", None) + self._infrequent_enabled = ( + max_categories is not None and max_categories >= 1 + ) or min_frequency is not None + + def _identify_infrequent(self, category_count, n_samples, col_idx): + """Compute the infrequent indices. + + Parameters + ---------- + category_count : ndarray of shape (n_cardinality,) + Category counts. + + n_samples : int + Number of samples. + + col_idx : int + Index of the current category. Only used for the error message. + + Returns + ------- + output : ndarray of shape (n_infrequent_categories,) or None + If there are infrequent categories, indices of infrequent + categories. Otherwise None. + """ + if isinstance(self.min_frequency, numbers.Integral): + infrequent_mask = category_count < self.min_frequency + elif isinstance(self.min_frequency, numbers.Real): + min_frequency_abs = n_samples * self.min_frequency + infrequent_mask = category_count < min_frequency_abs + else: + infrequent_mask = np.zeros(category_count.shape[0], dtype=bool) + + n_current_features = category_count.size - infrequent_mask.sum() + 1 + if self.max_categories is not None and self.max_categories < n_current_features: + # max_categories includes the one infrequent category + frequent_category_count = self.max_categories - 1 + if frequent_category_count == 0: + # All categories are infrequent + infrequent_mask[:] = True + else: + # stable sort to preserve original count order + smallest_levels = np.argsort(category_count, kind="mergesort")[ + :-frequent_category_count + ] + infrequent_mask[smallest_levels] = True + + output = np.flatnonzero(infrequent_mask) + return output if output.size > 0 else None + + def _fit_infrequent_category_mapping( + self, n_samples, category_counts, missing_indices + ): + """Fit infrequent categories. + + Defines the private attribute: `_default_to_infrequent_mappings`. For + feature `i`, `_default_to_infrequent_mappings[i]` defines the mapping + from the integer encoding returned by `super().transform()` into + infrequent categories. If `_default_to_infrequent_mappings[i]` is None, + there were no infrequent categories in the training set. + + For example if categories 0, 2 and 4 were frequent, while categories + 1, 3, 5 were infrequent for feature 7, then these categories are mapped + to a single output: + `_default_to_infrequent_mappings[7] = array([0, 3, 1, 3, 2, 3])` + + Defines private attribute: `_infrequent_indices`. `_infrequent_indices[i]` + is an array of indices such that + `categories_[i][_infrequent_indices[i]]` are all the infrequent category + labels. If the feature `i` has no infrequent categories + `_infrequent_indices[i]` is None. + + .. versionadded:: 1.1 + + Parameters + ---------- + n_samples : int + Number of samples in training set. + category_counts: list of ndarray + `category_counts[i]` is the category counts corresponding to + `self.categories_[i]`. + missing_indices : dict + Dict mapping from feature_idx to category index with a missing value. + """ + # Remove missing value from counts, so it is not considered as infrequent + if missing_indices: + category_counts_ = [] + for feature_idx, count in enumerate(category_counts): + if feature_idx in missing_indices: + category_counts_.append( + np.delete(count, missing_indices[feature_idx]) + ) + else: + category_counts_.append(count) + else: + category_counts_ = category_counts + + self._infrequent_indices = [ + self._identify_infrequent(category_count, n_samples, col_idx) + for col_idx, category_count in enumerate(category_counts_) + ] + + # compute mapping from default mapping to infrequent mapping + self._default_to_infrequent_mappings = [] + + for feature_idx, infreq_idx in enumerate(self._infrequent_indices): + cats = self.categories_[feature_idx] + # no infrequent categories + if infreq_idx is None: + self._default_to_infrequent_mappings.append(None) + continue + + n_cats = len(cats) + if feature_idx in missing_indices: + # Missing index was removed from ths category when computing + # infrequent indices, thus we need to decrease the number of + # total categories when considering the infrequent mapping. + n_cats -= 1 + + # infrequent indices exist + mapping = np.empty(n_cats, dtype=np.int64) + n_infrequent_cats = infreq_idx.size + + # infrequent categories are mapped to the last element. + n_frequent_cats = n_cats - n_infrequent_cats + mapping[infreq_idx] = n_frequent_cats + + frequent_indices = np.setdiff1d(np.arange(n_cats), infreq_idx) + mapping[frequent_indices] = np.arange(n_frequent_cats) + + self._default_to_infrequent_mappings.append(mapping) + + def _map_infrequent_categories(self, X_int, X_mask, ignore_category_indices): + """Map infrequent categories to integer representing the infrequent category. + + This modifies X_int in-place. Values that were invalid based on `X_mask` + are mapped to the infrequent category if there was an infrequent + category for that feature. + + Parameters + ---------- + X_int: ndarray of shape (n_samples, n_features) + Integer encoded categories. + + X_mask: ndarray of shape (n_samples, n_features) + Bool mask for valid values in `X_int`. + + ignore_category_indices : dict + Dictionary mapping from feature_idx to category index to ignore. + Ignored indexes will not be grouped and the original ordinal encoding + will remain. + """ + if not self._infrequent_enabled: + return + + ignore_category_indices = ignore_category_indices or {} + + for col_idx in range(X_int.shape[1]): + infrequent_idx = self._infrequent_indices[col_idx] + if infrequent_idx is None: + continue + + X_int[~X_mask[:, col_idx], col_idx] = infrequent_idx[0] + if self.handle_unknown == "infrequent_if_exist": + # All the unknown values are now mapped to the + # infrequent_idx[0], which makes the unknown values valid + # This is needed in `transform` when the encoding is formed + # using `X_mask`. + X_mask[:, col_idx] = True + + # Remaps encoding in `X_int` where the infrequent categories are + # grouped together. + for i, mapping in enumerate(self._default_to_infrequent_mappings): + if mapping is None: + continue + + if i in ignore_category_indices: + # Update rows that are **not** ignored + rows_to_update = X_int[:, i] != ignore_category_indices[i] + else: + rows_to_update = slice(None) + + X_int[rows_to_update, i] = np.take(mapping, X_int[rows_to_update, i]) + def _more_tags(self): return {"X_types": ["categorical"]} @@ -319,7 +548,7 @@ class OneHotEncoder(_BaseEncoder): :meth:`inverse_transform` will handle an unknown category as with `handle_unknown='ignore'`. Infrequent categories exist based on `min_frequency` and `max_categories`. Read more in the - :ref:`User Guide `. + :ref:`User Guide `. .. versionchanged:: 1.1 `'infrequent_if_exist'` was added to automatically handle unknown @@ -336,7 +565,7 @@ class OneHotEncoder(_BaseEncoder): `min_frequency * n_samples` will be considered infrequent. .. versionadded:: 1.1 - Read more in the :ref:`User Guide `. + Read more in the :ref:`User Guide `. max_categories : int, default=None Specifies an upper limit to the number of output features for each input @@ -346,7 +575,7 @@ class OneHotEncoder(_BaseEncoder): there is no limit to the number of output features. .. versionadded:: 1.1 - Read more in the :ref:`User Guide `. + Read more in the :ref:`User Guide `. feature_name_combiner : "concat" or callable, default="concat" Callable with signature `def callable(input_feature, category)` that returns a @@ -527,25 +756,6 @@ def __init__( self.max_categories = max_categories self.feature_name_combiner = feature_name_combiner - @property - def infrequent_categories_(self): - """Infrequent categories for each feature.""" - # raises an AttributeError if `_infrequent_indices` is not defined - infrequent_indices = self._infrequent_indices - return [ - None if indices is None else category[indices] - for category, indices in zip(self.categories_, infrequent_indices) - ] - - def _check_infrequent_enabled(self): - """ - This functions checks whether _infrequent_enabled is True or False. - This has to be called after parameter validation in the fit function. - """ - self._infrequent_enabled = ( - self.max_categories is not None and self.max_categories >= 1 - ) or self.min_frequency is not None - def _map_drop_idx_to_infrequent(self, feature_idx, drop_idx): """Convert `drop_idx` into the index for infrequent categories. @@ -688,141 +898,6 @@ def _set_drop_idx(self): self.drop_idx_ = np.asarray(drop_idx_, dtype=object) - def _identify_infrequent(self, category_count, n_samples, col_idx): - """Compute the infrequent indices. - - Parameters - ---------- - category_count : ndarray of shape (n_cardinality,) - Category counts. - - n_samples : int - Number of samples. - - col_idx : int - Index of the current category. Only used for the error message. - - Returns - ------- - output : ndarray of shape (n_infrequent_categories,) or None - If there are infrequent categories, indices of infrequent - categories. Otherwise None. - """ - if isinstance(self.min_frequency, numbers.Integral): - infrequent_mask = category_count < self.min_frequency - elif isinstance(self.min_frequency, numbers.Real): - min_frequency_abs = n_samples * self.min_frequency - infrequent_mask = category_count < min_frequency_abs - else: - infrequent_mask = np.zeros(category_count.shape[0], dtype=bool) - - n_current_features = category_count.size - infrequent_mask.sum() + 1 - if self.max_categories is not None and self.max_categories < n_current_features: - # stable sort to preserve original count order - smallest_levels = np.argsort(category_count, kind="mergesort")[ - : -self.max_categories + 1 - ] - infrequent_mask[smallest_levels] = True - - output = np.flatnonzero(infrequent_mask) - return output if output.size > 0 else None - - def _fit_infrequent_category_mapping(self, n_samples, category_counts): - """Fit infrequent categories. - - Defines the private attribute: `_default_to_infrequent_mappings`. For - feature `i`, `_default_to_infrequent_mappings[i]` defines the mapping - from the integer encoding returned by `super().transform()` into - infrequent categories. If `_default_to_infrequent_mappings[i]` is None, - there were no infrequent categories in the training set. - - For example if categories 0, 2 and 4 were frequent, while categories - 1, 3, 5 were infrequent for feature 7, then these categories are mapped - to a single output: - `_default_to_infrequent_mappings[7] = array([0, 3, 1, 3, 2, 3])` - - Defines private attribute: `_infrequent_indices`. `_infrequent_indices[i]` - is an array of indices such that - `categories_[i][_infrequent_indices[i]]` are all the infrequent category - labels. If the feature `i` has no infrequent categories - `_infrequent_indices[i]` is None. - - .. versionadded:: 1.1 - - Parameters - ---------- - n_samples : int - Number of samples in training set. - category_counts: list of ndarray - `category_counts[i]` is the category counts corresponding to - `self.categories_[i]`. - """ - self._infrequent_indices = [ - self._identify_infrequent(category_count, n_samples, col_idx) - for col_idx, category_count in enumerate(category_counts) - ] - - # compute mapping from default mapping to infrequent mapping - self._default_to_infrequent_mappings = [] - - for cats, infreq_idx in zip(self.categories_, self._infrequent_indices): - # no infrequent categories - if infreq_idx is None: - self._default_to_infrequent_mappings.append(None) - continue - - n_cats = len(cats) - # infrequent indices exist - mapping = np.empty(n_cats, dtype=np.int64) - n_infrequent_cats = infreq_idx.size - - # infrequent categories are mapped to the last element. - n_frequent_cats = n_cats - n_infrequent_cats - mapping[infreq_idx] = n_frequent_cats - - frequent_indices = np.setdiff1d(np.arange(n_cats), infreq_idx) - mapping[frequent_indices] = np.arange(n_frequent_cats) - - self._default_to_infrequent_mappings.append(mapping) - - def _map_infrequent_categories(self, X_int, X_mask): - """Map infrequent categories to integer representing the infrequent category. - - This modifies X_int in-place. Values that were invalid based on `X_mask` - are mapped to the infrequent category if there was an infrequent - category for that feature. - - Parameters - ---------- - X_int: ndarray of shape (n_samples, n_features) - Integer encoded categories. - - X_mask: ndarray of shape (n_samples, n_features) - Bool mask for valid values in `X_int`. - """ - if not self._infrequent_enabled: - return - - for col_idx in range(X_int.shape[1]): - infrequent_idx = self._infrequent_indices[col_idx] - if infrequent_idx is None: - continue - - X_int[~X_mask[:, col_idx], col_idx] = infrequent_idx[0] - if self.handle_unknown == "infrequent_if_exist": - # All the unknown values are now mapped to the - # infrequent_idx[0], which makes the unknown values valid - # This is needed in `transform` when the encoding is formed - # using `X_mask`. - X_mask[:, col_idx] = True - - # Remaps encoding in `X_int` where the infrequent categories are - # grouped together. - for i, mapping in enumerate(self._default_to_infrequent_mappings): - if mapping is None: - continue - X_int[:, i] = np.take(mapping, X_int[:, i]) - def _compute_transformed_categories(self, i, remove_dropped=True): """Compute the transformed categories used for column `i`. @@ -905,18 +980,11 @@ def fit(self, X, y=None): ) self.sparse_output = self.sparse - self._check_infrequent_enabled() - - fit_results = self._fit( + self._fit( X, handle_unknown=self.handle_unknown, force_all_finite="allow-nan", - return_counts=self._infrequent_enabled, ) - if self._infrequent_enabled: - self._fit_infrequent_category_mapping( - fit_results["n_samples"], fit_results["category_counts"] - ) self._set_drop_idx() self._n_features_outs = self._compute_n_features_outs() return self @@ -952,7 +1020,6 @@ def transform(self, X): force_all_finite="allow-nan", warn_on_unknown=warn_on_unknown, ) - self._map_infrequent_categories(X_int, X_mask) n_samples, n_features = X_int.shape @@ -1210,6 +1277,34 @@ class OrdinalEncoder(OneToOneFeatureMixin, _BaseEncoder): .. versionadded:: 1.1 + min_frequency : int or float, default=None + Specifies the minimum frequency below which a category will be + considered infrequent. + + - If `int`, categories with a smaller cardinality will be considered + infrequent. + + - If `float`, categories with a smaller cardinality than + `min_frequency * n_samples` will be considered infrequent. + + .. versionadded:: 1.3 + Read more in the :ref:`User Guide `. + + max_categories : int, default=None + Specifies an upper limit to the number of output categories for each input + feature when considering infrequent categories. If there are infrequent + categories, `max_categories` includes the category representing the + infrequent categories along with the frequent categories. If `None`, + there is no limit to the number of output features. + + `max_categories` do **not** take into account missing or unknown + categories. Setting `unknown_value` or `encoded_missing_value` to an + integer will increase the number of unique integer codes by one each. + This can result in up to `max_categories + 2` integer codes. + + .. versionadded:: 1.3 + Read more in the :ref:`User Guide `. + Attributes ---------- categories_ : list of arrays @@ -1228,6 +1323,15 @@ class OrdinalEncoder(OneToOneFeatureMixin, _BaseEncoder): .. versionadded:: 1.0 + infrequent_categories_ : list of ndarray + Defined only if infrequent categories are enabled by setting + `min_frequency` or `max_categories` to a non-default value. + `infrequent_categories_[i]` are the infrequent categories for feature + `i`. If the feature `i` has no infrequent categories + `infrequent_categories_[i]` is None. + + .. versionadded:: 1.3 + See Also -------- OneHotEncoder : Performs a one-hot encoding of categorical features. This encoding @@ -1282,6 +1386,27 @@ class OrdinalEncoder(OneToOneFeatureMixin, _BaseEncoder): array([[ 1., 0.], [ 0., 1.], [ 0., -1.]]) + + Infrequent categories are enabled by setting `max_categories` or `min_frequency`. + In the following example, "a" and "d" are considered infrequent and grouped + together into a single category, "b" and "c" are their own categories, unknown + values are encoded as 3 and missing values are encoded as 4. + + >>> X_train = np.array( + ... [["a"] * 5 + ["b"] * 20 + ["c"] * 10 + ["d"] * 3 + [np.nan]], + ... dtype=object).T + >>> enc = OrdinalEncoder( + ... handle_unknown="use_encoded_value", unknown_value=3, + ... max_categories=3, encoded_missing_value=4) + >>> _ = enc.fit(X_train) + >>> X_test = np.array([["a"], ["b"], ["c"], ["d"], ["e"], [np.nan]], dtype=object) + >>> enc.transform(X_test) + array([[2.], + [0.], + [1.], + [2.], + [3.], + [4.]]) """ _parameter_constraints: dict = { @@ -1290,6 +1415,12 @@ class OrdinalEncoder(OneToOneFeatureMixin, _BaseEncoder): "encoded_missing_value": [Integral, type(np.nan)], "handle_unknown": [StrOptions({"error", "use_encoded_value"})], "unknown_value": [Integral, type(np.nan), None], + "max_categories": [Interval(Integral, 1, None, closed="left"), None], + "min_frequency": [ + Interval(Integral, 1, None, closed="left"), + Interval(RealNotInt, 0, 1, closed="neither"), + None, + ], } def __init__( @@ -1300,12 +1431,16 @@ def __init__( handle_unknown="error", unknown_value=None, encoded_missing_value=np.nan, + min_frequency=None, + max_categories=None, ): self.categories = categories self.dtype = dtype self.handle_unknown = handle_unknown self.unknown_value = unknown_value self.encoded_missing_value = encoded_missing_value + self.min_frequency = min_frequency + self.max_categories = max_categories def fit(self, X, y=None): """ @@ -1350,9 +1485,21 @@ def fit(self, X, y=None): ) # `_fit` will only raise an error when `self.handle_unknown="error"` - self._fit(X, handle_unknown=self.handle_unknown, force_all_finite="allow-nan") + fit_results = self._fit( + X, + handle_unknown=self.handle_unknown, + force_all_finite="allow-nan", + return_and_ignore_missing_for_infrequent=True, + ) + self._missing_indices = fit_results["missing_indices"] cardinalities = [len(categories) for categories in self.categories_] + if self._infrequent_enabled: + # Cardinality decreases because the infrequent categories are grouped + # together + for feature_idx, infrequent in enumerate(self.infrequent_categories_): + if infrequent is not None: + cardinalities[feature_idx] -= len(infrequent) # stores the missing indices per category self._missing_indices = {} @@ -1426,7 +1573,10 @@ def transform(self, X): Transformed input. """ X_int, X_mask = self._transform( - X, handle_unknown=self.handle_unknown, force_all_finite="allow-nan" + X, + handle_unknown=self.handle_unknown, + force_all_finite="allow-nan", + ignore_category_indices=self._missing_indices, ) X_trans = X_int.astype(self.dtype, copy=False) @@ -1471,6 +1621,9 @@ def inverse_transform(self, X): X_tr = np.empty((n_samples, n_features), dtype=dt) found_unknown = {} + infrequent_masks = {} + + infrequent_indices = getattr(self, "_infrequent_indices", None) for i in range(n_features): labels = X[:, i] @@ -1480,22 +1633,44 @@ def inverse_transform(self, X): X_i_mask = _get_mask(labels, self.encoded_missing_value) labels[X_i_mask] = self._missing_indices[i] + rows_to_update = slice(None) + categories = self.categories_[i] + + if infrequent_indices is not None and infrequent_indices[i] is not None: + # Compute mask for frequent categories + infrequent_encoding_value = len(categories) - len(infrequent_indices[i]) + infrequent_masks[i] = labels == infrequent_encoding_value + rows_to_update = ~infrequent_masks[i] + + # Remap categories to be only frequent categories. The infrequent + # categories will be mapped to "infrequent_sklearn" later + frequent_categories_mask = np.ones_like(categories, dtype=bool) + frequent_categories_mask[infrequent_indices[i]] = False + categories = categories[frequent_categories_mask] + if self.handle_unknown == "use_encoded_value": unknown_labels = _get_mask(labels, self.unknown_value) + found_unknown[i] = unknown_labels known_labels = ~unknown_labels - X_tr[known_labels, i] = self.categories_[i][ - labels[known_labels].astype("int64", copy=False) - ] - found_unknown[i] = unknown_labels - else: - X_tr[:, i] = self.categories_[i][labels.astype("int64", copy=False)] + if isinstance(rows_to_update, np.ndarray): + rows_to_update &= known_labels + else: + rows_to_update = known_labels - # insert None values for unknown values - if found_unknown: + labels_int = labels[rows_to_update].astype("int64", copy=False) + X_tr[rows_to_update, i] = categories[labels_int] + + if found_unknown or infrequent_masks: X_tr = X_tr.astype(object, copy=False) + # insert None values for unknown values + if found_unknown: for idx, mask in found_unknown.items(): X_tr[mask, idx] = None + if infrequent_masks: + for idx, mask in infrequent_masks.items(): + X_tr[mask, idx] = "infrequent_sklearn" + return X_tr diff --git a/sklearn/preprocessing/tests/test_encoders.py b/sklearn/preprocessing/tests/test_encoders.py index a4fea0ee92dbc..ffd5eda5195d0 100644 --- a/sklearn/preprocessing/tests/test_encoders.py +++ b/sklearn/preprocessing/tests/test_encoders.py @@ -2051,3 +2051,256 @@ def test_drop_idx_infrequent_categories(): ["x0_b", "x0_c", "x0_d", "x0_e", "x0_infrequent_sklearn"], ) assert ohe.drop_idx_ is None + + +@pytest.mark.parametrize( + "kwargs", + [ + {"max_categories": 3}, + {"min_frequency": 6}, + {"min_frequency": 9}, + {"min_frequency": 0.24}, + {"min_frequency": 0.16}, + {"max_categories": 3, "min_frequency": 8}, + {"max_categories": 4, "min_frequency": 6}, + ], +) +def test_ordinal_encoder_infrequent_three_levels(kwargs): + """Test parameters for grouping 'a', and 'd' into the infrequent category.""" + + X_train = np.array([["a"] * 5 + ["b"] * 20 + ["c"] * 10 + ["d"] * 3]).T + ordinal = OrdinalEncoder( + handle_unknown="use_encoded_value", unknown_value=-1, **kwargs + ).fit(X_train) + assert_array_equal(ordinal.categories_, [["a", "b", "c", "d"]]) + assert_array_equal(ordinal.infrequent_categories_, [["a", "d"]]) + + X_test = [["a"], ["b"], ["c"], ["d"], ["z"]] + expected_trans = [[2], [0], [1], [2], [-1]] + + X_trans = ordinal.transform(X_test) + assert_allclose(X_trans, expected_trans) + + X_inverse = ordinal.inverse_transform(X_trans) + expected_inverse = [ + ["infrequent_sklearn"], + ["b"], + ["c"], + ["infrequent_sklearn"], + [None], + ] + assert_array_equal(X_inverse, expected_inverse) + + +def test_ordinal_encoder_infrequent_three_levels_user_cats(): + """Test that the order of the categories provided by a user is respected. + + In this case 'c' is encoded as the first category and 'b' is encoded + as the second one. + """ + + X_train = np.array( + [["a"] * 5 + ["b"] * 20 + ["c"] * 10 + ["d"] * 3], dtype=object + ).T + ordinal = OrdinalEncoder( + categories=[["c", "d", "b", "a"]], + max_categories=3, + handle_unknown="use_encoded_value", + unknown_value=-1, + ).fit(X_train) + assert_array_equal(ordinal.categories_, [["c", "d", "b", "a"]]) + assert_array_equal(ordinal.infrequent_categories_, [["d", "a"]]) + + X_test = [["a"], ["b"], ["c"], ["d"], ["z"]] + expected_trans = [[2], [1], [0], [2], [-1]] + + X_trans = ordinal.transform(X_test) + assert_allclose(X_trans, expected_trans) + + X_inverse = ordinal.inverse_transform(X_trans) + expected_inverse = [ + ["infrequent_sklearn"], + ["b"], + ["c"], + ["infrequent_sklearn"], + [None], + ] + assert_array_equal(X_inverse, expected_inverse) + + +def test_ordinal_encoder_infrequent_mixed(): + """Test when feature 0 has infrequent categories and feature 1 does not.""" + + X = np.column_stack(([0, 1, 3, 3, 3, 3, 2, 0, 3], [0, 0, 0, 0, 1, 1, 1, 1, 1])) + + ordinal = OrdinalEncoder(max_categories=3).fit(X) + + assert_array_equal(ordinal.infrequent_categories_[0], [1, 2]) + assert ordinal.infrequent_categories_[1] is None + + X_test = [[3, 0], [1, 1]] + expected_trans = [[1, 0], [2, 1]] + + X_trans = ordinal.transform(X_test) + assert_allclose(X_trans, expected_trans) + + X_inverse = ordinal.inverse_transform(X_trans) + expected_inverse = np.array([[3, 0], ["infrequent_sklearn", 1]], dtype=object) + assert_array_equal(X_inverse, expected_inverse) + + +def test_ordinal_encoder_infrequent_multiple_categories_dtypes(): + """Test infrequent categories with a pandas DataFrame with multiple dtypes.""" + + pd = pytest.importorskip("pandas") + categorical_dtype = pd.CategoricalDtype(["bird", "cat", "dog", "snake"]) + X = pd.DataFrame( + { + "str": ["a", "f", "c", "f", "f", "a", "c", "b", "b"], + "int": [5, 3, 0, 10, 10, 12, 0, 3, 5], + "categorical": pd.Series( + ["dog"] * 4 + ["cat"] * 3 + ["snake"] + ["bird"], + dtype=categorical_dtype, + ), + }, + columns=["str", "int", "categorical"], + ) + + ordinal = OrdinalEncoder(max_categories=3).fit(X) + # X[:, 0] 'a', 'b', 'c' have the same frequency. 'a' and 'b' will be + # considered infrequent because they appear first when sorted + + # X[:, 1] 0, 3, 5, 10 has frequency 2 and 12 has frequency 1. + # 0, 3, 12 will be considered infrequent because they appear first when + # sorted. + + # X[:, 2] "snake" and "bird" or infrequent + + assert_array_equal(ordinal.infrequent_categories_[0], ["a", "b"]) + assert_array_equal(ordinal.infrequent_categories_[1], [0, 3, 12]) + assert_array_equal(ordinal.infrequent_categories_[2], ["bird", "snake"]) + + X_test = pd.DataFrame( + { + "str": ["a", "b", "f", "c"], + "int": [12, 0, 10, 5], + "categorical": pd.Series( + ["cat"] + ["snake"] + ["bird"] + ["dog"], + dtype=categorical_dtype, + ), + }, + columns=["str", "int", "categorical"], + ) + expected_trans = [[2, 2, 0], [2, 2, 2], [1, 1, 2], [0, 0, 1]] + + X_trans = ordinal.transform(X_test) + assert_allclose(X_trans, expected_trans) + + +def test_ordinal_encoder_infrequent_custom_mapping(): + """Check behavior of unknown_value and encoded_missing_value with infrequent.""" + X_train = np.array( + [["a"] * 5 + ["b"] * 20 + ["c"] * 10 + ["d"] * 3 + [np.nan]], dtype=object + ).T + + ordinal = OrdinalEncoder( + handle_unknown="use_encoded_value", + unknown_value=2, + max_categories=2, + encoded_missing_value=3, + ).fit(X_train) + assert_array_equal(ordinal.infrequent_categories_, [["a", "c", "d"]]) + + X_test = np.array([["a"], ["b"], ["c"], ["d"], ["e"], [np.nan]], dtype=object) + expected_trans = [[1], [0], [1], [1], [2], [3]] + + X_trans = ordinal.transform(X_test) + assert_allclose(X_trans, expected_trans) + + +@pytest.mark.parametrize( + "kwargs", + [ + {"max_categories": 6}, + {"min_frequency": 2}, + ], +) +def test_ordinal_encoder_all_frequent(kwargs): + """All categories are considered frequent have same encoding as default encoder.""" + X_train = np.array( + [["a"] * 5 + ["b"] * 20 + ["c"] * 10 + ["d"] * 3], dtype=object + ).T + + adjusted_encoder = OrdinalEncoder( + **kwargs, handle_unknown="use_encoded_value", unknown_value=-1 + ).fit(X_train) + default_encoder = OrdinalEncoder( + handle_unknown="use_encoded_value", unknown_value=-1 + ).fit(X_train) + + X_test = [["a"], ["b"], ["c"], ["d"], ["e"]] + + assert_allclose( + adjusted_encoder.transform(X_test), default_encoder.transform(X_test) + ) + + +@pytest.mark.parametrize( + "kwargs", + [ + {"max_categories": 1}, + {"min_frequency": 100}, + ], +) +def test_ordinal_encoder_all_infrequent(kwargs): + """When all categories are infrequent, they are all encoded as zero.""" + X_train = np.array( + [["a"] * 5 + ["b"] * 20 + ["c"] * 10 + ["d"] * 3], dtype=object + ).T + encoder = OrdinalEncoder( + **kwargs, handle_unknown="use_encoded_value", unknown_value=-1 + ).fit(X_train) + + X_test = [["a"], ["b"], ["c"], ["d"], ["e"]] + assert_allclose(encoder.transform(X_test), [[0], [0], [0], [0], [-1]]) + + +def test_ordinal_encoder_missing_appears_frequent(): + """Check behavior when missing value appears frequently.""" + X = np.array( + [[np.nan] * 20 + ["dog"] * 10 + ["cat"] * 5 + ["snake"] + ["deer"]], + dtype=object, + ).T + ordinal = OrdinalEncoder(max_categories=3).fit(X) + + X_test = np.array([["snake", "cat", "dog", np.nan]], dtype=object).T + X_trans = ordinal.transform(X_test) + assert_allclose(X_trans, [[2], [0], [1], [np.nan]]) + + +def test_ordinal_encoder_missing_appears_infrequent(): + """Check behavior when missing value appears infrequently.""" + + # feature 0 has infrequent categories + # feature 1 has no infrequent categories + X = np.array( + [ + [np.nan] + ["dog"] * 10 + ["cat"] * 5 + ["snake"] + ["deer"], + ["red"] * 9 + ["green"] * 9, + ], + dtype=object, + ).T + ordinal = OrdinalEncoder(min_frequency=4).fit(X) + + X_test = np.array( + [ + ["snake", "red"], + ["deer", "green"], + [np.nan, "green"], + ["dog", "green"], + ["cat", "red"], + ], + dtype=object, + ) + X_trans = ordinal.transform(X_test) + assert_allclose(X_trans, [[2, 1], [2, 0], [np.nan, 0], [1, 0], [0, 1]]) From c1a2106b74f69a8c976d72493dd4d8fa75b9f7a5 Mon Sep 17 00:00:00 2001 From: mdarii Date: Wed, 29 Mar 2023 10:09:04 +0200 Subject: [PATCH 118/230] MAINT make plot_digits_denoising deterministic by fixing random state (#26004) --- .../applications/plot_cyclical_feature_engineering.py | 1 + examples/applications/plot_digits_denoising.py | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/applications/plot_cyclical_feature_engineering.py b/examples/applications/plot_cyclical_feature_engineering.py index b2d33de149d39..ecd270354ab76 100644 --- a/examples/applications/plot_cyclical_feature_engineering.py +++ b/examples/applications/plot_cyclical_feature_engineering.py @@ -216,6 +216,7 @@ ), HistGradientBoostingRegressor( categorical_features=categorical_columns, + random_state=42, ), ).set_output(transform="pandas") diff --git a/examples/applications/plot_digits_denoising.py b/examples/applications/plot_digits_denoising.py index 84702034152f5..cec8e342367c3 100644 --- a/examples/applications/plot_digits_denoising.py +++ b/examples/applications/plot_digits_denoising.py @@ -98,9 +98,14 @@ def plot_digits(X, title): # uses a radial basis function (RBF) kernel. from sklearn.decomposition import PCA, KernelPCA -pca = PCA(n_components=32) +pca = PCA(n_components=32, random_state=42) kernel_pca = KernelPCA( - n_components=400, kernel="rbf", gamma=1e-3, fit_inverse_transform=True, alpha=5e-3 + n_components=400, + kernel="rbf", + gamma=1e-3, + fit_inverse_transform=True, + alpha=5e-3, + random_state=42, ) pca.fit(X_train_noisy) From dd68ebb6157ef32d1d932943d5e91c85b5f46c94 Mon Sep 17 00:00:00 2001 From: murezzda <47388020+murezzda@users.noreply.github.com> Date: Wed, 29 Mar 2023 10:13:26 +0200 Subject: [PATCH 119/230] DOC improve example of PatchExtractor (#26002) --- sklearn/feature_extraction/image.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sklearn/feature_extraction/image.py b/sklearn/feature_extraction/image.py index 25f494a155a2f..cee1a4a100e57 100644 --- a/sklearn/feature_extraction/image.py +++ b/sklearn/feature_extraction/image.py @@ -532,12 +532,16 @@ class PatchExtractor(TransformerMixin, BaseEstimator): >>> from sklearn.feature_extraction import image >>> # Use the array data from the second image in this dataset: >>> X = load_sample_images().images[1] + >>> X = X[None, ...] >>> print(f"Image shape: {X.shape}") - Image shape: (427, 640, 3) - >>> pe = image.PatchExtractor(patch_size=(2, 2)) + Image shape: (1, 427, 640, 3) + >>> pe = image.PatchExtractor(patch_size=(10, 10)) >>> pe_trans = pe.transform(X) >>> print(f"Patches shape: {pe_trans.shape}") - Patches shape: (545706, 2, 2) + Patches shape: (263758, 10, 10, 3) + >>> X_reconstructed = image.reconstruct_from_patches_2d(pe_trans, X.shape[1:]) + >>> print(f"Reconstructed shape: {X_reconstructed.shape}") + Reconstructed shape: (427, 640, 3) """ _parameter_constraints: dict = { From 1410e62524bb97c3e1639b93b19ad360b5e39795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Wed, 29 Mar 2023 11:13:51 +0200 Subject: [PATCH 120/230] MAINT Parameters validation for datasets.make_friedman2 (#25986) --- sklearn/datasets/_samples_generator.py | 7 +++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 8 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 7b078eda40357..4e84ab33dbe75 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1097,6 +1097,13 @@ def make_friedman1(n_samples=100, n_features=10, *, noise=0.0, random_state=None return X, y +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "noise": [Interval(Real, 0, None, closed="left")], + "random_state": ["random_state"], + } +) def make_friedman2(n_samples=100, *, noise=0.0, random_state=None): """Generate the "Friedman #2" regression problem. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index d960639cee7fd..5e738fea4a6eb 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -134,6 +134,7 @@ def _check_function_param_validation( "sklearn.datasets.make_circles", "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", + "sklearn.datasets.make_friedman2", "sklearn.datasets.make_gaussian_quantiles", "sklearn.datasets.make_hastie_10_2", "sklearn.datasets.make_low_rank_matrix", From 6c8dd846ee03937d9883c7a566ecbd202db0eb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Wed, 29 Mar 2023 11:16:13 +0200 Subject: [PATCH 121/230] MAINT Parameters validation for datasets.make_friedman3 (#25989) --- sklearn/datasets/_samples_generator.py | 7 +++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 8 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 4e84ab33dbe75..5252fe334b7f7 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1169,6 +1169,13 @@ def make_friedman2(n_samples=100, *, noise=0.0, random_state=None): return X, y +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "noise": [Interval(Real, 0, None, closed="left")], + "random_state": ["random_state"], + } +) def make_friedman3(n_samples=100, *, noise=0.0, random_state=None): """Generate the "Friedman #3" regression problem. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 5e738fea4a6eb..025b0ca5eef0f 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -135,6 +135,7 @@ def _check_function_param_validation( "sklearn.datasets.make_classification", "sklearn.datasets.make_friedman1", "sklearn.datasets.make_friedman2", + "sklearn.datasets.make_friedman3", "sklearn.datasets.make_gaussian_quantiles", "sklearn.datasets.make_hastie_10_2", "sklearn.datasets.make_low_rank_matrix", From ded0bd6ca0d23a0a6fa4798e762495fe79d6d139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Wed, 29 Mar 2023 11:17:53 +0200 Subject: [PATCH 122/230] MAINT Parameters validation for datasets.make_sparse_uncorrelated (#26001) --- sklearn/datasets/_samples_generator.py | 7 +++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 8 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index 5252fe334b7f7..a96cd458bb943 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1440,6 +1440,13 @@ def make_sparse_coded_signal( return map(np.squeeze, (Y, D, X)) +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "n_features": [Interval(Integral, 1, None, closed="left")], + "random_state": ["random_state"], + } +) def make_sparse_uncorrelated(n_samples=100, n_features=10, *, random_state=None): """Generate a random regression problem with sparse uncorrelated design. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 025b0ca5eef0f..e3eb9f9fdf269 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -143,6 +143,7 @@ def _check_function_param_validation( "sklearn.datasets.make_multilabel_classification", "sklearn.datasets.make_regression", "sklearn.datasets.make_sparse_coded_signal", + "sklearn.datasets.make_sparse_uncorrelated", "sklearn.decomposition.sparse_encode", "sklearn.feature_extraction.grid_to_graph", "sklearn.feature_extraction.img_to_graph", From 1be0930c942d8b9b3c08b90a5b9c9fcbe9bd098f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Wed, 29 Mar 2023 11:21:07 +0200 Subject: [PATCH 123/230] MAINT Parameters validation for datasets.make_spd_matrix (#26003) --- sklearn/datasets/_samples_generator.py | 6 ++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 7 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index a96cd458bb943..fca6907c6904b 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1498,6 +1498,12 @@ def make_sparse_uncorrelated(n_samples=100, n_features=10, *, random_state=None) return X, y +@validate_params( + { + "n_dim": [Interval(Integral, 1, None, closed="left")], + "random_state": ["random_state"], + } +) def make_spd_matrix(n_dim, *, random_state=None): """Generate a random symmetric, positive-definite matrix. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index e3eb9f9fdf269..903c42984a8f4 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -144,6 +144,7 @@ def _check_function_param_validation( "sklearn.datasets.make_regression", "sklearn.datasets.make_sparse_coded_signal", "sklearn.datasets.make_sparse_uncorrelated", + "sklearn.datasets.make_spd_matrix", "sklearn.decomposition.sparse_encode", "sklearn.feature_extraction.grid_to_graph", "sklearn.feature_extraction.img_to_graph", From 68e038443c72186425b9f3885ebc2768e59f01d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Wed, 29 Mar 2023 13:00:53 +0200 Subject: [PATCH 124/230] MAINT Parameters validation for datasets.make_sparse_spd_matrix (#26009) --- sklearn/datasets/_samples_generator.py | 10 ++++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 11 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index fca6907c6904b..efe880d270b21 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1537,6 +1537,16 @@ def make_spd_matrix(n_dim, *, random_state=None): return X +@validate_params( + { + "dim": [Interval(Integral, 1, None, closed="left")], + "alpha": [Interval(Real, 0, 1, closed="both")], + "norm_diag": ["boolean"], + "smallest_coef": [Interval(Real, 0, 1, closed="both")], + "largest_coef": [Interval(Real, 0, 1, closed="both")], + "random_state": ["random_state"], + } +) def make_sparse_spd_matrix( dim=1, *, diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 903c42984a8f4..726d6adeb8e85 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -143,6 +143,7 @@ def _check_function_param_validation( "sklearn.datasets.make_multilabel_classification", "sklearn.datasets.make_regression", "sklearn.datasets.make_sparse_coded_signal", + "sklearn.datasets.make_sparse_spd_matrix", "sklearn.datasets.make_sparse_uncorrelated", "sklearn.datasets.make_spd_matrix", "sklearn.decomposition.sparse_encode", From c024ddf6a429d32d3cb4e719bf8196aeaac7f4f2 Mon Sep 17 00:00:00 2001 From: Peter Piontek Date: Wed, 29 Mar 2023 13:34:29 +0200 Subject: [PATCH 125/230] DOC Added the meanings of default=None for PatchExtractor parameters (#26005) --- sklearn/feature_extraction/image.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sklearn/feature_extraction/image.py b/sklearn/feature_extraction/image.py index cee1a4a100e57..89bdd7557f583 100644 --- a/sklearn/feature_extraction/image.py +++ b/sklearn/feature_extraction/image.py @@ -503,12 +503,14 @@ class PatchExtractor(TransformerMixin, BaseEstimator): Parameters ---------- patch_size : tuple of int (patch_height, patch_width), default=None - The dimensions of one patch. + The dimensions of one patch. If set to None, the patch size will be + automatically set to `(img_height // 10, img_width // 10)`, where + `img_height` and `img_width` are the dimensions of the input images. max_patches : int or float, default=None The maximum number of patches per image to extract. If `max_patches` is a float in (0, 1), it is taken to mean a proportion of the total number - of patches. + of patches. If set to None, extract all possible patches. random_state : int, RandomState instance, default=None Determines the random number generator used for random sampling when @@ -618,8 +620,8 @@ def transform(self, X): else: if len(self.patch_size) != 2: raise ValueError( - f"patch_size must be a tuple of two integers. Got {self.patch_size}" - " instead." + "patch_size must be a tuple of two integers. Got" + f" {self.patch_size} instead." ) patch_size = self.patch_size From 5325d9c6dee0a5b3bac678b82e96851a720f2561 Mon Sep 17 00:00:00 2001 From: Guillaume Lemaitre Date: Wed, 29 Mar 2023 16:30:45 +0200 Subject: [PATCH 126/230] MAINT remove unecessary check covered by parameter validation framework (#26014) --- sklearn/mixture/_base.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sklearn/mixture/_base.py b/sklearn/mixture/_base.py index 00721dc8d70ec..a298dfec6a0da 100644 --- a/sklearn/mixture/_base.py +++ b/sklearn/mixture/_base.py @@ -137,10 +137,6 @@ def _initialize_parameters(self, X, random_state): random_state=random_state, ) resp[indices, np.arange(self.n_components)] = 1 - else: - raise ValueError( - "Unimplemented initialization method '%s'" % self.init_params - ) self._initialize(X, resp) From 9b801fc7f2dca9224d09c479683cce9bc92191dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Wed, 29 Mar 2023 17:48:56 +0200 Subject: [PATCH 127/230] MAINT Consistent cython types from _typedefs (#25942) Co-authored-by: Julien Jerphanion --- setup.py | 7 +- sklearn/cluster/_hierarchical_fast.pyx | 6 +- sklearn/metrics/_dist_metrics.pxd.tp | 113 +- sklearn/metrics/_dist_metrics.pyx.tp | 970 +++++++++--------- .../_argkmin_classmode.pyx.tp | 4 - .../_datasets_pair.pxd.tp | 34 +- .../_datasets_pair.pyx.tp | 59 +- .../_middle_term_computer.pxd.tp | 218 ++-- .../_middle_term_computer.pyx.tp | 326 +++--- sklearn/utils/_typedefs.pxd | 33 +- sklearn/utils/_typedefs.pyx | 28 +- sklearn/utils/tests/test_typedefs.py | 22 + 12 files changed, 898 insertions(+), 922 deletions(-) create mode 100644 sklearn/utils/tests/test_typedefs.py diff --git a/setup.py b/setup.py index f5522600f623f..e36848a316b69 100755 --- a/setup.py +++ b/setup.py @@ -265,7 +265,6 @@ def check_package_status(package, min_version): { "sources": ["_middle_term_computer.pyx.tp", "_middle_term_computer.pxd.tp"], "language": "c++", - "include_np": True, "extra_compile_args": ["-std=c++11"], }, { @@ -397,9 +396,9 @@ def check_package_status(package, min_version): }, {"sources": ["_random.pyx"], "include_np": True}, {"sources": ["_logistic_sigmoid.pyx"], "include_np": True}, - {"sources": ["_typedefs.pyx"], "include_np": True}, - {"sources": ["_heap.pyx"], "include_np": True}, - {"sources": ["_sorting.pyx"], "include_np": True}, + {"sources": ["_typedefs.pyx"]}, + {"sources": ["_heap.pyx"]}, + {"sources": ["_sorting.pyx"]}, {"sources": ["_vector_sentinel.pyx"], "language": "c++", "include_np": True}, {"sources": ["_isfinite.pyx"]}, ], diff --git a/sklearn/cluster/_hierarchical_fast.pyx b/sklearn/cluster/_hierarchical_fast.pyx index 99f0b3c0f0235..4ba895ddcf352 100644 --- a/sklearn/cluster/_hierarchical_fast.pyx +++ b/sklearn/cluster/_hierarchical_fast.pyx @@ -5,7 +5,7 @@ cimport cython from ..metrics._dist_metrics cimport DistanceMetric from ..utils._fast_dict cimport IntFloatDict -from ..utils._typedefs cimport float64_t, intp_t, bool_t +from ..utils._typedefs cimport float64_t, intp_t, uint8_t # C++ from cython.operator cimport dereference as deref, preincrement as inc @@ -119,7 +119,7 @@ def _get_parents( nodes, heads, const intp_t[:] parents, - bool_t[::1] not_visited + uint8_t[::1] not_visited ): """Returns the heads of the given nodes, as defined by parents. @@ -465,7 +465,7 @@ def mst_linkage_core( """ cdef: intp_t n_samples = raw_data.shape[0] - bool_t[:] in_tree = np.zeros(n_samples, dtype=bool) + uint8_t[:] in_tree = np.zeros(n_samples, dtype=bool) float64_t[:, ::1] result = np.zeros((n_samples - 1, 3)) intp_t current_node = 0 diff --git a/sklearn/metrics/_dist_metrics.pxd.tp b/sklearn/metrics/_dist_metrics.pxd.tp index cb1aec99b2e9a..511e0941a7098 100644 --- a/sklearn/metrics/_dist_metrics.pxd.tp +++ b/sklearn/metrics/_dist_metrics.pxd.tp @@ -9,26 +9,21 @@ implementation_specific_values = [ # for the float64 case as to still be able to expose the original # float64 implementation under the same API, namely `DistanceMetric`. # - # On the other hand, '32' bit is used for `name_suffix` for the float32 + # On the other hand, '32' is used for `name_suffix` for the float32 # case to remove ambiguity and use `DistanceMetric32`, which is not # publicly exposed. # # The metric mapping is adapted accordingly to route to the correct # implementations. # - # We also use 64bit types as defined in `sklearn.utils._typedefs` - # to maintain backward compatibility at the symbol level for extra - # safety. - # - ('', 'DTYPE_t', 'DTYPE'), - ('32', 'cnp.float32_t', 'np.float32') + ('', 'float64_t', 'np.float64'), + ('32', 'float32_t', 'np.float32') ] }} -cimport numpy as cnp from libc.math cimport sqrt, exp -from ..utils._typedefs cimport DTYPE_t, ITYPE_t, SPARSE_INDEX_TYPE_t +from ..utils._typedefs cimport float64_t, float32_t, int32_t, intp_t {{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}} @@ -37,37 +32,37 @@ from ..utils._typedefs cimport DTYPE_t, ITYPE_t, SPARSE_INDEX_TYPE_t # # We use these for the default (euclidean) case so that they can be # inlined. This leads to faster computation for the most common case -cdef inline DTYPE_t euclidean_dist{{name_suffix}}( +cdef inline float64_t euclidean_dist{{name_suffix}}( const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t tmp, d=0 - cdef cnp.intp_t j + cdef float64_t tmp, d=0 + cdef intp_t j for j in range(size): - tmp = (x1[j] - x2[j]) + tmp = (x1[j] - x2[j]) d += tmp * tmp return sqrt(d) -cdef inline DTYPE_t euclidean_rdist{{name_suffix}}( +cdef inline float64_t euclidean_rdist{{name_suffix}}( const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t tmp, d=0 - cdef cnp.intp_t j + cdef float64_t tmp, d=0 + cdef intp_t j for j in range(size): - tmp = (x1[j] - x2[j]) + tmp = (x1[j] - x2[j]) d += tmp * tmp return d -cdef inline DTYPE_t euclidean_dist_to_rdist{{name_suffix}}(const {{INPUT_DTYPE_t}} dist) except -1 nogil: +cdef inline float64_t euclidean_dist_to_rdist{{name_suffix}}(const {{INPUT_DTYPE_t}} dist) except -1 nogil: return dist * dist -cdef inline DTYPE_t euclidean_rdist_to_dist{{name_suffix}}(const {{INPUT_DTYPE_t}} dist) except -1 nogil: +cdef inline float64_t euclidean_rdist_to_dist{{name_suffix}}(const {{INPUT_DTYPE_t}} dist) except -1 nogil: return sqrt(dist) @@ -78,89 +73,89 @@ cdef class DistanceMetric{{name_suffix}}: # we must define them here so that cython's limited polymorphism will work. # Because we don't expect to instantiate a lot of these objects, the # extra memory overhead of this setup should not be an issue. - cdef DTYPE_t p - cdef const DTYPE_t[::1] vec - cdef const DTYPE_t[:, ::1] mat - cdef ITYPE_t size + cdef float64_t p + cdef const float64_t[::1] vec + cdef const float64_t[:, ::1] mat + cdef intp_t size cdef object func cdef object kwargs - cdef DTYPE_t dist( + cdef float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil - cdef DTYPE_t rdist( + cdef float64_t rdist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil - cdef DTYPE_t dist_csr( + cdef float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil - cdef DTYPE_t rdist_csr( + cdef float64_t rdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil cdef int pdist( self, const {{INPUT_DTYPE_t}}[:, ::1] X, - DTYPE_t[:, ::1] D, + float64_t[:, ::1] D, ) except -1 cdef int cdist( self, const {{INPUT_DTYPE_t}}[:, ::1] X, const {{INPUT_DTYPE_t}}[:, ::1] Y, - DTYPE_t[:, ::1] D, + float64_t[:, ::1] D, ) except -1 cdef int pdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, - const SPARSE_INDEX_TYPE_t[:] x1_indptr, - const ITYPE_t size, - DTYPE_t[:, ::1] D, + const int32_t[:] x1_indices, + const int32_t[:] x1_indptr, + const intp_t size, + float64_t[:, ::1] D, ) except -1 nogil cdef int cdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, - const SPARSE_INDEX_TYPE_t[:] x1_indptr, + const int32_t[:] x1_indices, + const int32_t[:] x1_indptr, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t[:] x2_indptr, - const ITYPE_t size, - DTYPE_t[:, ::1] D, + const int32_t[:] x2_indices, + const int32_t[:] x2_indptr, + const intp_t size, + float64_t[:, ::1] D, ) except -1 nogil - cdef DTYPE_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil + cdef float64_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil - cdef DTYPE_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil + cdef float64_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil {{endfor}} diff --git a/sklearn/metrics/_dist_metrics.pyx.tp b/sklearn/metrics/_dist_metrics.pyx.tp index 4d2ab3251b56e..ed09552ed5914 100644 --- a/sklearn/metrics/_dist_metrics.pyx.tp +++ b/sklearn/metrics/_dist_metrics.pyx.tp @@ -5,10 +5,9 @@ implementation_specific_values = [ # # name_suffix, INPUT_DTYPE_t, INPUT_DTYPE # - # # On the first hand, an empty string is used for `name_suffix` - # for the 64bit case as to still be able to expose the original - # 64bit implementation under the same API, namely `DistanceMetric`. + # for the float64 case as to still be able to expose the original + # float64 implementation under the same API, namely `DistanceMetric`. # # On the other hand, '32' bit is used for `name_suffix` for the float32 # case to remove ambiguity and use `DistanceMetric32`, which is not @@ -17,12 +16,8 @@ implementation_specific_values = [ # The metric mapping is adapted accordingly to route to the correct # implementations. # - # We also use 64bit types as defined in `sklearn.utils._typedefs` - # to maintain backward compatibility at the symbol level for extra - # safety. - # - ('', 'DTYPE_t', 'DTYPE'), - ('32', 'cnp.float32_t', 'np.float32') + ('', 'float64_t', 'np.float64'), + ('32', 'float32_t', 'np.float32') ] }} @@ -38,8 +33,7 @@ cnp.import_array() # required in order to use C-API from libc.math cimport fabs, sqrt, exp, pow, cos, sin, asin from scipy.sparse import csr_matrix, issparse -from ..utils._typedefs cimport DTYPE_t, ITYPE_t, DTYPECODE -from ..utils._typedefs import DTYPE, ITYPE +from ..utils._typedefs cimport float64_t, float32_t, int32_t, intp_t from ..utils import check_array from ..utils.fixes import parse_version, sp_base_version @@ -80,7 +74,6 @@ def get_valid_metric_ids(L): return [key for (key, val) in METRIC_MAPPING.items() if (val.__name__ in L) or (val in L)] -from ..utils._typedefs import SPARSE_INDEX_TYPE {{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}} @@ -115,14 +108,15 @@ METRIC_MAPPING{{name_suffix}} = { 'pyfunc': PyFuncDistance{{name_suffix}}, } -cdef inline object _buffer_to_ndarray{{name_suffix}}(const {{INPUT_DTYPE_t}}* x, cnp.npy_intp n): +cdef inline object _buffer_to_ndarray{{name_suffix}}(const {{INPUT_DTYPE_t}}* x, intp_t n): # Wrap a memory buffer with an ndarray. Warning: this is not robust. # In particular, if x is deallocated before the returned array goes # out of scope, this could cause memory errors. Since there is not # a possibility of this for our use-case, this should be safe. # Note: this Segfaults unless np.import_array() is called above - return cnp.PyArray_SimpleNewFromData(1, &n, DTYPECODE, x) + # TODO: remove the explicit cast to cnp.intp_t* when cython min version >= 3.0 + return cnp.PyArray_SimpleNewFromData(1, &n, cnp.NPY_FLOAT64, x) cdef {{INPUT_DTYPE_t}} INF{{name_suffix}} = np.inf @@ -245,8 +239,8 @@ cdef class DistanceMetric{{name_suffix}}: """ def __cinit__(self): self.p = 2 - self.vec = np.zeros(1, dtype=DTYPE, order='C') - self.mat = np.zeros((1, 1), dtype=DTYPE, order='C') + self.vec = np.zeros(1, dtype=np.float64, order='C') + self.mat = np.zeros((1, 1), dtype=np.float64, order='C') self.size = 1 def __reduce__(self): @@ -330,11 +324,11 @@ cdef class DistanceMetric{{name_suffix}}: """ return - cdef DTYPE_t dist( + cdef float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: """Compute the distance between vectors x1 and x2 @@ -342,11 +336,11 @@ cdef class DistanceMetric{{name_suffix}}: """ return -999 - cdef DTYPE_t rdist( + cdef float64_t rdist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: """Compute the rank-preserving surrogate distance between vectors x1 and x2. @@ -362,10 +356,10 @@ cdef class DistanceMetric{{name_suffix}}: cdef int pdist( self, const {{INPUT_DTYPE_t}}[:, ::1] X, - DTYPE_t[:, ::1] D, + float64_t[:, ::1] D, ) except -1: """Compute the pairwise distances between points in X""" - cdef ITYPE_t i1, i2 + cdef intp_t i1, i2 for i1 in range(X.shape[0]): for i2 in range(i1, X.shape[0]): D[i1, i2] = self.dist(&X[i1, 0], &X[i2, 0], X.shape[1]) @@ -377,10 +371,10 @@ cdef class DistanceMetric{{name_suffix}}: self, const {{INPUT_DTYPE_t}}[:, ::1] X, const {{INPUT_DTYPE_t}}[:, ::1] Y, - DTYPE_t[:, ::1] D, + float64_t[:, ::1] D, ) except -1: """Compute the cross-pairwise distances between arrays X and Y""" - cdef ITYPE_t i1, i2 + cdef intp_t i1, i2 if X.shape[1] != Y.shape[1]: raise ValueError('X and Y must have the same second dimension') for i1 in range(X.shape[0]): @@ -388,17 +382,17 @@ cdef class DistanceMetric{{name_suffix}}: D[i1, i2] = self.dist(&X[i1, 0], &Y[i2, 0], X.shape[1]) return 0 - cdef DTYPE_t dist_csr( + cdef float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: """Compute the distance between vectors x1 and x2 represented under the CSR format. @@ -418,12 +412,12 @@ cdef class DistanceMetric{{name_suffix}}: 2. An alternative signature would be: - cdef DTYPE_t dist_csr( + cdef float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, + const int32_t[:] x2_indices, ) except -1 nogil: Where callers would use slicing on the original CSR data and indices @@ -454,17 +448,17 @@ cdef class DistanceMetric{{name_suffix}}: """ return -999 - cdef DTYPE_t rdist_csr( + cdef float64_t rdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: """Distance between rows of CSR matrices x1 and x2. @@ -498,10 +492,10 @@ cdef class DistanceMetric{{name_suffix}}: cdef int pdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, - const SPARSE_INDEX_TYPE_t[:] x1_indptr, - const ITYPE_t size, - DTYPE_t[:, ::1] D, + const int32_t[:] x1_indices, + const int32_t[:] x1_indptr, + const intp_t size, + float64_t[:, ::1] D, ) except -1 nogil: """Pairwise distances between rows in CSR matrix X. @@ -509,9 +503,9 @@ cdef class DistanceMetric{{name_suffix}}: because it leverages the symmetry of the problem. """ cdef: - ITYPE_t i1, i2 - ITYPE_t n_x1 = x1_indptr.shape[0] - 1 - ITYPE_t x1_start, x1_end, x2_start, x2_end + intp_t i1, i2 + intp_t n_x1 = x1_indptr.shape[0] - 1 + intp_t x1_start, x1_end, x2_start, x2_end for i1 in range(n_x1): x1_start = x1_indptr[i1] @@ -535,21 +529,21 @@ cdef class DistanceMetric{{name_suffix}}: cdef int cdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, - const SPARSE_INDEX_TYPE_t[:] x1_indptr, + const int32_t[:] x1_indices, + const int32_t[:] x1_indptr, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t[:] x2_indptr, - const ITYPE_t size, - DTYPE_t[:, ::1] D, + const int32_t[:] x2_indices, + const int32_t[:] x2_indptr, + const intp_t size, + float64_t[:, ::1] D, ) except -1 nogil: """Compute the cross-pairwise distances between arrays X and Y represented in the CSR format.""" cdef: - ITYPE_t i1, i2 - ITYPE_t n_x1 = x1_indptr.shape[0] - 1 - ITYPE_t n_x2 = x2_indptr.shape[0] - 1 - ITYPE_t x1_start, x1_end, x2_start, x2_end + intp_t i1, i2 + intp_t n_x1 = x1_indptr.shape[0] - 1 + intp_t n_x2 = x2_indptr.shape[0] - 1 + intp_t x1_start, x1_end, x2_start, x2_end for i1 in range(n_x1): x1_start = x1_indptr[i1] @@ -571,11 +565,11 @@ cdef class DistanceMetric{{name_suffix}}: ) return 0 - cdef DTYPE_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: + cdef float64_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: """Convert the rank-preserving surrogate distance to the distance""" return rdist - cdef DTYPE_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: + cdef float64_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: """Convert the distance to the rank-preserving surrogate distance""" return dist @@ -622,41 +616,41 @@ cdef class DistanceMetric{{name_suffix}}: def _pairwise_dense_dense(self, X, Y): cdef const {{INPUT_DTYPE_t}}[:, ::1] Xarr cdef const {{INPUT_DTYPE_t}}[:, ::1] Yarr - cdef DTYPE_t[:, ::1] Darr + cdef float64_t[:, ::1] Darr Xarr = np.asarray(X, dtype={{INPUT_DTYPE}}, order='C') self._validate_data(Xarr) if X is Y: - Darr = np.empty((Xarr.shape[0], Xarr.shape[0]), dtype=DTYPE, order='C') + Darr = np.empty((Xarr.shape[0], Xarr.shape[0]), dtype=np.float64, order='C') self.pdist(Xarr, Darr) else: Yarr = np.asarray(Y, dtype={{INPUT_DTYPE}}, order='C') self._validate_data(Yarr) - Darr = np.empty((Xarr.shape[0], Yarr.shape[0]), dtype=DTYPE, order='C') + Darr = np.empty((Xarr.shape[0], Yarr.shape[0]), dtype=np.float64, order='C') self.cdist(Xarr, Yarr, Darr) return np.asarray(Darr) def _pairwise_sparse_sparse(self, X: csr_matrix , Y: csr_matrix): cdef: - ITYPE_t n_X, n_features + intp_t n_X, n_features const {{INPUT_DTYPE_t}}[:] X_data - const SPARSE_INDEX_TYPE_t[:] X_indices - const SPARSE_INDEX_TYPE_t[:] X_indptr + const int32_t[:] X_indices + const int32_t[:] X_indptr - ITYPE_t n_Y + intp_t n_Y const {{INPUT_DTYPE_t}}[:] Y_data - const SPARSE_INDEX_TYPE_t[:] Y_indices - const SPARSE_INDEX_TYPE_t[:] Y_indptr + const int32_t[:] Y_indices + const int32_t[:] Y_indptr - DTYPE_t[:, ::1] Darr + float64_t[:, ::1] Darr X_csr = X.tocsr() n_X, n_features = X_csr.shape X_data = np.asarray(X_csr.data, dtype={{INPUT_DTYPE}}) - X_indices = np.asarray(X_csr.indices, dtype=SPARSE_INDEX_TYPE) - X_indptr = np.asarray(X_csr.indptr, dtype=SPARSE_INDEX_TYPE) + X_indices = np.asarray(X_csr.indices, dtype=np.int32) + X_indptr = np.asarray(X_csr.indptr, dtype=np.int32) if X is Y: - Darr = np.empty((n_X, n_X), dtype=DTYPE, order='C') + Darr = np.empty((n_X, n_X), dtype=np.float64, order='C') self.pdist_csr( x1_data=&X_data[0], x1_indices=X_indices, @@ -668,10 +662,10 @@ cdef class DistanceMetric{{name_suffix}}: Y_csr = Y.tocsr() n_Y, _ = Y_csr.shape Y_data = np.asarray(Y_csr.data, dtype={{INPUT_DTYPE}}) - Y_indices = np.asarray(Y_csr.indices, dtype=SPARSE_INDEX_TYPE) - Y_indptr = np.asarray(Y_csr.indptr, dtype=SPARSE_INDEX_TYPE) + Y_indices = np.asarray(Y_csr.indices, dtype=np.int32) + Y_indptr = np.asarray(Y_csr.indptr, dtype=np.int32) - Darr = np.empty((n_X, n_Y), dtype=DTYPE, order='C') + Darr = np.empty((n_X, n_Y), dtype=np.float64, order='C') self.cdist_csr( x1_data=&X_data[0], x1_indices=X_indices, @@ -686,30 +680,30 @@ cdef class DistanceMetric{{name_suffix}}: def _pairwise_sparse_dense(self, X: csr_matrix, Y): cdef: - ITYPE_t n_X = X.shape[0] - ITYPE_t n_features = X.shape[1] + intp_t n_X = X.shape[0] + intp_t n_features = X.shape[1] const {{INPUT_DTYPE_t}}[:] X_data = np.asarray( X.data, dtype={{INPUT_DTYPE}}, ) - const SPARSE_INDEX_TYPE_t[:] X_indices = np.asarray( - X.indices, dtype=SPARSE_INDEX_TYPE, + const int32_t[:] X_indices = np.asarray( + X.indices, dtype=np.int32, ) - const SPARSE_INDEX_TYPE_t[:] X_indptr = np.asarray( - X.indptr, dtype=SPARSE_INDEX_TYPE, + const int32_t[:] X_indptr = np.asarray( + X.indptr, dtype=np.int32, ) const {{INPUT_DTYPE_t}}[:, ::1] Y_data = np.asarray( Y, dtype={{INPUT_DTYPE}}, order="C", ) - ITYPE_t n_Y = Y_data.shape[0] - const SPARSE_INDEX_TYPE_t[:] Y_indices = ( - np.arange(n_features, dtype=SPARSE_INDEX_TYPE) + intp_t n_Y = Y_data.shape[0] + const int32_t[:] Y_indices = ( + np.arange(n_features, dtype=np.int32) ) - DTYPE_t[:, ::1] Darr = np.empty((n_X, n_Y), dtype=DTYPE, order='C') + float64_t[:, ::1] Darr = np.empty((n_X, n_Y), dtype=np.float64, order='C') - ITYPE_t i1, i2 - ITYPE_t x1_start, x1_end + intp_t i1, i2 + intp_t x1_start, x1_end {{INPUT_DTYPE_t}} * x2_data with nogil: @@ -750,33 +744,33 @@ cdef class DistanceMetric{{name_suffix}}: # swapping argument and by transposing the results, but this would # have come with an extra copy to ensure C-contiguity of the result. cdef: - ITYPE_t n_X = X.shape[0] - ITYPE_t n_features = X.shape[1] + intp_t n_X = X.shape[0] + intp_t n_features = X.shape[1] const {{INPUT_DTYPE_t}}[:, ::1] X_data = np.asarray( X, dtype={{INPUT_DTYPE}}, order="C", ) - const SPARSE_INDEX_TYPE_t[:] X_indices = np.arange( - n_features, dtype=SPARSE_INDEX_TYPE, + const int32_t[:] X_indices = np.arange( + n_features, dtype=np.int32, ) - ITYPE_t n_Y = Y.shape[0] + intp_t n_Y = Y.shape[0] const {{INPUT_DTYPE_t}}[:] Y_data = np.asarray( Y.data, dtype={{INPUT_DTYPE}}, ) - const SPARSE_INDEX_TYPE_t[:] Y_indices = np.asarray( - Y.indices, dtype=SPARSE_INDEX_TYPE, + const int32_t[:] Y_indices = np.asarray( + Y.indices, dtype=np.int32, ) - const SPARSE_INDEX_TYPE_t[:] Y_indptr = np.asarray( - Y.indptr, dtype=SPARSE_INDEX_TYPE, + const int32_t[:] Y_indptr = np.asarray( + Y.indptr, dtype=np.int32, ) - DTYPE_t[:, ::1] Darr = np.empty((n_X, n_Y), dtype=DTYPE, order='C') + float64_t[:, ::1] Darr = np.empty((n_X, n_Y), dtype=np.float64, order='C') - ITYPE_t i1, i2 + intp_t i1, i2 {{INPUT_DTYPE_t}} * x1_data - ITYPE_t x2_start, x2_end + intp_t x2_start, x2_end with nogil: # Use the exact same adaptation for CSR than in SparseDenseDatasetsPair @@ -865,24 +859,24 @@ cdef class EuclideanDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): def __init__(self): self.p = 2 - cdef inline DTYPE_t dist(self, + cdef inline float64_t dist(self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: return euclidean_dist{{name_suffix}}(x1, x2, size) - cdef inline DTYPE_t rdist(self, + cdef inline float64_t rdist(self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: return euclidean_rdist{{name_suffix}}(x1, x2, size) - cdef inline DTYPE_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: + cdef inline float64_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: return sqrt(rdist) - cdef inline DTYPE_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: + cdef inline float64_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: return dist * dist def rdist_to_dist(self, rdist): @@ -891,26 +885,26 @@ cdef class EuclideanDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): def dist_to_rdist(self, dist): return dist ** 2 - cdef inline DTYPE_t rdist_csr( + cdef inline float64_t rdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t d = 0.0 - DTYPE_t unsquared = 0 + float64_t d = 0.0 + float64_t unsquared = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -943,17 +937,17 @@ cdef class EuclideanDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): return d - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: return sqrt( self.rdist_csr( @@ -978,7 +972,7 @@ cdef class SEuclideanDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = \sqrt{ \sum_i \frac{ (x_i - y_i) ^ 2}{V_i} } """ def __init__(self, V): - self.vec = np.asarray(V, dtype=DTYPE) + self.vec = np.asarray(V, dtype=np.float64) self.size = self.vec.shape[0] self.p = 2 @@ -986,31 +980,31 @@ cdef class SEuclideanDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): if X.shape[1] != self.size: raise ValueError('SEuclidean dist: size of V does not match') - cdef inline DTYPE_t rdist( + cdef inline float64_t rdist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t tmp, d=0 - cdef cnp.intp_t j + cdef float64_t tmp, d=0 + cdef intp_t j for j in range(size): tmp = x1[j] - x2[j] d += (tmp * tmp / self.vec[j]) return d - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: return sqrt(self.rdist(x1, x2, size)) - cdef inline DTYPE_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: + cdef inline float64_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: return sqrt(rdist) - cdef inline DTYPE_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: + cdef inline float64_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: return dist * dist def rdist_to_dist(self, rdist): @@ -1019,26 +1013,26 @@ cdef class SEuclideanDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): def dist_to_rdist(self, dist): return dist ** 2 - cdef inline DTYPE_t rdist_csr( + cdef inline float64_t rdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t d = 0.0 - DTYPE_t unsquared = 0 + float64_t d = 0.0 + float64_t unsquared = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -1072,17 +1066,17 @@ cdef class SEuclideanDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): i1 = i1 + 1 return d - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: return sqrt( self.rdist_csr( @@ -1109,37 +1103,37 @@ cdef class ManhattanDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): def __init__(self): self.p = 1 - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t d = 0 - cdef cnp.intp_t j + cdef float64_t d = 0 + cdef intp_t j for j in range(size): d += fabs(x1[j] - x2[j]) return d - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t d = 0.0 + float64_t d = 0.0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -1192,38 +1186,38 @@ cdef class ChebyshevDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): def __init__(self): self.p = INF{{name_suffix}} - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t d = 0 - cdef cnp.intp_t j + cdef float64_t d = 0 + cdef intp_t j for j in range(size): d = fmax(d, fabs(x1[j] - x2[j])) return d - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t d = 0.0 + float64_t d = 0.0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -1289,14 +1283,14 @@ cdef class MinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): self.p = p if w is not None: w_array = check_array( - w, ensure_2d=False, dtype=DTYPE, input_name="w" + w, ensure_2d=False, dtype=np.float64, input_name="w" ) if (w_array < 0).any(): raise ValueError("w cannot contain negative weights") self.vec = w_array self.size = self.vec.shape[0] else: - self.vec = np.asarray([], dtype=DTYPE) + self.vec = np.asarray([], dtype=np.float64) self.size = 0 def _validate_data(self, X): @@ -1305,14 +1299,14 @@ cdef class MinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): f"the number of features ({X.shape[1]}). " f"Currently len(w)={self.size}.") - cdef inline DTYPE_t rdist( + cdef inline float64_t rdist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t d=0 - cdef cnp.intp_t j + cdef float64_t d=0 + cdef intp_t j cdef bint has_w = self.size > 0 if has_w: for j in range(size): @@ -1322,18 +1316,18 @@ cdef class MinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): d += (pow(fabs(x1[j] - x2[j]), self.p)) return d - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: return pow(self.rdist(x1, x2, size), 1. / self.p) - cdef inline DTYPE_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: + cdef inline float64_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: return pow(rdist, 1. / self.p) - cdef inline DTYPE_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: + cdef inline float64_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: return pow(dist, self.p) def rdist_to_dist(self, rdist): @@ -1342,25 +1336,25 @@ cdef class MinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): def dist_to_rdist(self, dist): return dist ** self.p - cdef inline DTYPE_t rdist_csr( + cdef inline float64_t rdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t d = 0.0 + float64_t d = 0.0 bint has_w = self.size > 0 if has_w: @@ -1422,17 +1416,17 @@ cdef class MinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): return d - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: return pow( self.rdist_csr( @@ -1485,7 +1479,7 @@ cdef class WMinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): raise ValueError("WMinkowskiDistance requires finite p. " "For p=inf, use ChebyshevDistance.") self.p = p - self.vec = np.asarray(w, dtype=DTYPE) + self.vec = np.asarray(w, dtype=np.float64) self.size = self.vec.shape[0] def _validate_data(self, X): @@ -1493,31 +1487,31 @@ cdef class WMinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): raise ValueError('WMinkowskiDistance dist: ' 'size of w does not match') - cdef inline DTYPE_t rdist( + cdef inline float64_t rdist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t d = 0 - cdef cnp.intp_t j + cdef float64_t d = 0 + cdef intp_t j for j in range(size): d += (pow(self.vec[j] * fabs(x1[j] - x2[j]), self.p)) return d - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: return pow(self.rdist(x1, x2, size), 1. / self.p) - cdef inline DTYPE_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: + cdef inline float64_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: return pow(rdist, 1. / self.p) - cdef inline DTYPE_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: + cdef inline float64_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: return pow(dist, self.p) def rdist_to_dist(self, rdist): @@ -1526,25 +1520,25 @@ cdef class WMinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): def dist_to_rdist(self, dist): return dist ** self.p - cdef inline DTYPE_t rdist_csr( + cdef inline float64_t rdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t d = 0.0 + float64_t d = 0.0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -1576,17 +1570,17 @@ cdef class WMinkowskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): return d - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: return pow( self.rdist_csr( @@ -1621,7 +1615,7 @@ cdef class MahalanobisDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): optionally specify the inverse directly. If VI is passed, then V is not referenced. """ - cdef DTYPE_t[::1] buffer + cdef float64_t[::1] buffer def __init__(self, V=None, VI=None): if VI is None: @@ -1632,30 +1626,30 @@ cdef class MahalanobisDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): if VI.ndim != 2 or VI.shape[0] != VI.shape[1]: raise ValueError("V/VI must be square") - self.mat = np.asarray(VI, dtype=DTYPE, order='C') + self.mat = np.asarray(VI, dtype=np.float64, order='C') self.size = self.mat.shape[0] # We need to create a buffer to store the vectors' coordinates' differences - self.buffer = np.zeros(self.size, dtype=DTYPE) + self.buffer = np.zeros(self.size, dtype=np.float64) def __setstate__(self, state): super().__setstate__(state) self.size = self.mat.shape[0] - self.buffer = np.zeros(self.size, dtype=DTYPE) + self.buffer = np.zeros(self.size, dtype=np.float64) def _validate_data(self, X): if X.shape[1] != self.size: raise ValueError('Mahalanobis dist: size of V does not match') - cdef inline DTYPE_t rdist( + cdef inline float64_t rdist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t tmp, d = 0 - cdef cnp.intp_t i, j + cdef float64_t tmp, d = 0 + cdef intp_t i, j # compute (x1 - x2).T * VI * (x1 - x2) for i in range(size): @@ -1668,18 +1662,18 @@ cdef class MahalanobisDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): d += tmp * self.buffer[i] return d - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: return sqrt(self.rdist(x1, x2, size)) - cdef inline DTYPE_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: + cdef inline float64_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: return sqrt(rdist) - cdef inline DTYPE_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: + cdef inline float64_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: return dist * dist def rdist_to_dist(self, rdist): @@ -1688,25 +1682,25 @@ cdef class MahalanobisDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): def dist_to_rdist(self, dist): return dist ** 2 - cdef inline DTYPE_t rdist_csr( + cdef inline float64_t rdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t tmp, d = 0.0 + float64_t tmp, d = 0.0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -1742,17 +1736,17 @@ cdef class MahalanobisDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): return d - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: return sqrt( self.rdist_csr( @@ -1779,39 +1773,39 @@ cdef class HammingDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): .. math:: D(x, y) = \frac{1}{N} \sum_i \delta_{x_i, y_i} """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int n_unequal = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): if x1[j] != x2[j]: n_unequal += 1 return float(n_unequal) / size - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t d = 0.0 + float64_t d = 0.0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -1854,39 +1848,39 @@ cdef class CanberraDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): .. math:: D(x, y) = \sum_i \frac{|x_i - y_i|}{|x_i| + |y_i|} """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t denom, d = 0 - cdef cnp.intp_t j + cdef float64_t denom, d = 0 + cdef intp_t j for j in range(size): denom = fabs(x1[j]) + fabs(x2[j]) if denom > 0: d += fabs(x1[j] - x2[j]) / denom return d - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t d = 0.0 + float64_t d = 0.0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -1929,14 +1923,14 @@ cdef class BrayCurtisDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): .. math:: D(x, y) = \frac{\sum_i |x_i - y_i|}{\sum_i(|x_i| + |y_i|)} """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t num = 0, denom = 0 - cdef cnp.intp_t j + cdef float64_t num = 0, denom = 0 + cdef intp_t j for j in range(size): num += fabs(x1[j] - x2[j]) denom += fabs(x1[j]) + fabs(x2[j]) @@ -1945,26 +1939,26 @@ cdef class BrayCurtisDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): else: return 0.0 - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t num = 0.0 - DTYPE_t denom = 0.0 + float64_t num = 0.0 + float64_t denom = 0.0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2009,14 +2003,14 @@ cdef class JaccardDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = (N_TF + N_FT) / (N_TT + N_TF + N_FT) """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int tf1, tf2, n_eq = 0, nnz = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): tf1 = x1[j] != 0 tf2 = x2[j] != 0 @@ -2029,25 +2023,25 @@ cdef class JaccardDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): return 0 return (nnz - n_eq) * 1.0 / nnz - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - ITYPE_t tf1, tf2, n_tt = 0, nnz = 0 + intp_t tf1, tf2, n_tt = 0, nnz = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2098,39 +2092,39 @@ cdef class MatchingDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = (N_TF + N_FT) / N """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int tf1, tf2, n_neq = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): tf1 = x1[j] != 0 tf2 = x2[j] != 0 n_neq += (tf1 != tf2) return n_neq * 1. / size - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - ITYPE_t tf1, tf2, n_neq = 0 + intp_t tf1, tf2, n_neq = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2173,14 +2167,14 @@ cdef class DiceDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = (N_TF + N_FT) / (2 * N_TT + N_TF + N_FT) """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int tf1, tf2, n_neq = 0, n_tt = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): tf1 = x1[j] != 0 tf2 = x2[j] != 0 @@ -2188,25 +2182,25 @@ cdef class DiceDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): n_neq += (tf1 != tf2) return n_neq / (2.0 * n_tt + n_neq) - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - ITYPE_t tf1, tf2, n_tt = 0, n_neq = 0 + intp_t tf1, tf2, n_tt = 0, n_neq = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2254,14 +2248,14 @@ cdef class KulsinskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = 1 - N_TT / (N + N_TF + N_FT) """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int tf1, tf2, n_tt = 0, n_neq = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): tf1 = x1[j] != 0 tf2 = x2[j] != 0 @@ -2269,25 +2263,25 @@ cdef class KulsinskiDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): n_tt += (tf1 and tf2) return (n_neq - n_tt + size) * 1.0 / (n_neq + size) - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - ITYPE_t tf1, tf2, n_tt = 0, n_neq = 0 + intp_t tf1, tf2, n_tt = 0, n_neq = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2333,39 +2327,39 @@ cdef class RogersTanimotoDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = 2 (N_TF + N_FT) / (N + N_TF + N_FT) """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int tf1, tf2, n_neq = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): tf1 = x1[j] != 0 tf2 = x2[j] != 0 n_neq += (tf1 != tf2) return (2.0 * n_neq) / (size + n_neq) - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - ITYPE_t tf1, tf2, n_neq = 0 + intp_t tf1, tf2, n_neq = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2410,39 +2404,39 @@ cdef class RussellRaoDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = (N - N_TT) / N """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int tf1, tf2, n_tt = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): tf1 = x1[j] != 0 tf2 = x2[j] != 0 n_tt += (tf1 and tf2) return (size - n_tt) * 1. / size - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - ITYPE_t tf1, tf2, n_tt = 0 + intp_t tf1, tf2, n_tt = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2480,39 +2474,39 @@ cdef class SokalMichenerDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = 2 (N_TF + N_FT) / (N + N_TF + N_FT) """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int tf1, tf2, n_neq = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): tf1 = x1[j] != 0 tf2 = x2[j] != 0 n_neq += (tf1 != tf2) return (2.0 * n_neq) / (size + n_neq) - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - ITYPE_t tf1, tf2, n_neq = 0 + intp_t tf1, tf2, n_neq = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2557,14 +2551,14 @@ cdef class SokalSneathDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): D(x, y) = (N_TF + N_FT) / (N_TT / 2 + N_FT + N_TF) """ - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: cdef int tf1, tf2, n_tt = 0, n_neq = 0 - cdef cnp.intp_t j + cdef intp_t j for j in range(size): tf1 = x1[j] != 0 tf2 = x2[j] != 0 @@ -2572,25 +2566,25 @@ cdef class SokalSneathDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): n_tt += (tf1 and tf2) return n_neq / (0.5 * n_tt + n_neq) - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - ITYPE_t tf1, tf2, n_tt = 0, n_neq = 0 + intp_t tf1, tf2, n_tt = 0, n_neq = 0 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2646,27 +2640,27 @@ cdef class HaversineDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): raise ValueError("Haversine distance only valid " "in 2 dimensions") - cdef inline DTYPE_t rdist(self, + cdef inline float64_t rdist(self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: - cdef DTYPE_t sin_0 = sin(0.5 * ((x1[0]) - (x2[0]))) - cdef DTYPE_t sin_1 = sin(0.5 * ((x1[1]) - (x2[1]))) + cdef float64_t sin_0 = sin(0.5 * ((x1[0]) - (x2[0]))) + cdef float64_t sin_1 = sin(0.5 * ((x1[1]) - (x2[1]))) return (sin_0 * sin_0 + cos(x1[0]) * cos(x2[0]) * sin_1 * sin_1) - cdef inline DTYPE_t dist(self, + cdef inline float64_t dist(self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: return 2 * asin(sqrt(self.rdist(x1, x2, size))) - cdef inline DTYPE_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: + cdef inline float64_t _rdist_to_dist(self, {{INPUT_DTYPE_t}} rdist) except -1 nogil: return 2 * asin(sqrt(rdist)) - cdef inline DTYPE_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: - cdef DTYPE_t tmp = sin(0.5 * dist) + cdef inline float64_t _dist_to_rdist(self, {{INPUT_DTYPE_t}} dist) except -1 nogil: + cdef float64_t tmp = sin(0.5 * dist) return tmp * tmp def rdist_to_dist(self, rdist): @@ -2676,17 +2670,17 @@ cdef class HaversineDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): tmp = np.sin(0.5 * dist) return tmp * tmp - cdef inline DTYPE_t dist_csr( + cdef inline float64_t dist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: return 2 * asin(sqrt(self.rdist_csr( x1_data, @@ -2700,30 +2694,30 @@ cdef class HaversineDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): size, ))) - cdef inline DTYPE_t rdist_csr( + cdef inline float64_t rdist_csr( self, const {{INPUT_DTYPE_t}}* x1_data, - const SPARSE_INDEX_TYPE_t[:] x1_indices, + const int32_t[:] x1_indices, const {{INPUT_DTYPE_t}}* x2_data, - const SPARSE_INDEX_TYPE_t[:] x2_indices, - const SPARSE_INDEX_TYPE_t x1_start, - const SPARSE_INDEX_TYPE_t x1_end, - const SPARSE_INDEX_TYPE_t x2_start, - const SPARSE_INDEX_TYPE_t x2_end, - const ITYPE_t size, + const int32_t[:] x2_indices, + const int32_t x1_start, + const int32_t x1_end, + const int32_t x2_start, + const int32_t x2_end, + const intp_t size, ) except -1 nogil: cdef: - cnp.npy_intp ix1, ix2 - cnp.npy_intp i1 = x1_start - cnp.npy_intp i2 = x2_start + intp_t ix1, ix2 + intp_t i1 = x1_start + intp_t i2 = x2_start - DTYPE_t x1_0 = 0 - DTYPE_t x1_1 = 0 - DTYPE_t x2_0 = 0 - DTYPE_t x2_1 = 0 - DTYPE_t sin_0 - DTYPE_t sin_1 + float64_t x1_0 = 0 + float64_t x1_1 = 0 + float64_t x2_0 = 0 + float64_t x2_1 = 0 + float64_t sin_0 + float64_t sin_1 while i1 < x1_end and i2 < x2_end: ix1 = x1_indices[i1] @@ -2792,19 +2786,19 @@ cdef class PyFuncDistance{{name_suffix}}(DistanceMetric{{name_suffix}}): # allowed in cython >= 0.26 since it is a redundant GIL acquisition. The # only way to be back compatible is to inherit `dist` from the base class # without GIL and called an inline `_dist` which acquire GIL. - cdef inline DTYPE_t dist( + cdef inline float64_t dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 nogil: return self._dist(x1, x2, size) - cdef inline DTYPE_t _dist( + cdef inline float64_t _dist( self, const {{INPUT_DTYPE_t}}* x1, const {{INPUT_DTYPE_t}}* x2, - ITYPE_t size, + intp_t size, ) except -1 with gil: cdef: object x1arr = _buffer_to_ndarray{{name_suffix}}(x1, size) diff --git a/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp index a7744ab6e6b8f..3d0ea84b0091d 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_argkmin_classmode.pyx.tp @@ -3,10 +3,6 @@ from cython.parallel cimport parallel, prange from libcpp.map cimport map as cpp_map, pair as cpp_pair from libc.stdlib cimport free -cimport numpy as cnp - -cnp.import_array() - from ...utils._typedefs cimport intp_t, float64_t import numpy as np diff --git a/sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pxd.tp b/sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pxd.tp index 416263d1c3134..23337cb2b59d6 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pxd.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pxd.tp @@ -7,14 +7,12 @@ implementation_specific_values = [ # # We use DistanceMetric for float64 for backward naming compatibility. # - ('64', 'DistanceMetric', 'DTYPE_t'), - ('32', 'DistanceMetric32', 'cnp.float32_t') + ('64', 'DistanceMetric', 'float64_t'), + ('32', 'DistanceMetric32', 'float32_t') ] }} -cimport numpy as cnp - -from ...utils._typedefs cimport DTYPE_t, ITYPE_t, SPARSE_INDEX_TYPE_t +from ...utils._typedefs cimport float64_t, float32_t, int32_t, intp_t from ...metrics._dist_metrics cimport DistanceMetric, DistanceMetric32 {{for name_suffix, DistanceMetric, INPUT_DTYPE_t in implementation_specific_values}} @@ -23,15 +21,15 @@ from ...metrics._dist_metrics cimport DistanceMetric, DistanceMetric32 cdef class DatasetsPair{{name_suffix}}: cdef: {{DistanceMetric}} distance_metric - ITYPE_t n_features + intp_t n_features - cdef ITYPE_t n_samples_X(self) noexcept nogil + cdef intp_t n_samples_X(self) noexcept nogil - cdef ITYPE_t n_samples_Y(self) noexcept nogil + cdef intp_t n_samples_Y(self) noexcept nogil - cdef DTYPE_t dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil + cdef float64_t dist(self, intp_t i, intp_t j) noexcept nogil - cdef DTYPE_t surrogate_dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil + cdef float64_t surrogate_dist(self, intp_t i, intp_t j) noexcept nogil cdef class DenseDenseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): @@ -43,23 +41,23 @@ cdef class DenseDenseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): cdef class SparseSparseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): cdef: const {{INPUT_DTYPE_t}}[:] X_data - const SPARSE_INDEX_TYPE_t[:] X_indices - const SPARSE_INDEX_TYPE_t[:] X_indptr + const int32_t[:] X_indices + const int32_t[:] X_indptr const {{INPUT_DTYPE_t}}[:] Y_data - const SPARSE_INDEX_TYPE_t[:] Y_indices - const SPARSE_INDEX_TYPE_t[:] Y_indptr + const int32_t[:] Y_indices + const int32_t[:] Y_indptr cdef class SparseDenseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): cdef: const {{INPUT_DTYPE_t}}[:] X_data - const SPARSE_INDEX_TYPE_t[:] X_indices - const SPARSE_INDEX_TYPE_t[:] X_indptr + const int32_t[:] X_indices + const int32_t[:] X_indptr const {{INPUT_DTYPE_t}}[:] Y_data - const SPARSE_INDEX_TYPE_t[:] Y_indices - ITYPE_t n_Y + const int32_t[:] Y_indices + intp_t n_Y cdef class DenseSparseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): diff --git a/sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pyx.tp index 5442d2883ac5b..5569c1f231d62 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pyx.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_datasets_pair.pyx.tp @@ -7,23 +7,20 @@ implementation_specific_values = [ # # We use DistanceMetric for float64 for backward naming compatibility. # - ('64', 'DistanceMetric', 'DTYPE_t', 'DTYPE'), - ('32', 'DistanceMetric32', 'cnp.float32_t', 'np.float32') + ('64', 'DistanceMetric', 'float64_t', 'np.float64'), + ('32', 'DistanceMetric32', 'float32_t', 'np.float32') ] }} import numpy as np -cimport numpy as cnp from cython cimport final -from ...utils._typedefs cimport DTYPE_t, ITYPE_t +from ...utils._typedefs cimport float64_t, float32_t, intp_t from ...metrics._dist_metrics cimport DistanceMetric from scipy.sparse import issparse, csr_matrix -from ...utils._typedefs import DTYPE, SPARSE_INDEX_TYPE -cnp.import_array() {{for name_suffix, DistanceMetric, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}} cdef class DatasetsPair{{name_suffix}}: @@ -124,34 +121,34 @@ cdef class DatasetsPair{{name_suffix}}: @classmethod def unpack_csr_matrix(cls, X: csr_matrix): - """Ensure that the CSR matrix is indexed with SPARSE_INDEX_TYPE.""" + """Ensure that the CSR matrix is indexed with np.int32.""" X_data = np.asarray(X.data, dtype={{INPUT_DTYPE}}) - X_indices = np.asarray(X.indices, dtype=SPARSE_INDEX_TYPE) - X_indptr = np.asarray(X.indptr, dtype=SPARSE_INDEX_TYPE) + X_indices = np.asarray(X.indices, dtype=np.int32) + X_indptr = np.asarray(X.indptr, dtype=np.int32) return X_data, X_indices, X_indptr - def __init__(self, {{DistanceMetric}} distance_metric, ITYPE_t n_features): + def __init__(self, {{DistanceMetric}} distance_metric, intp_t n_features): self.distance_metric = distance_metric self.n_features = n_features - cdef ITYPE_t n_samples_X(self) noexcept nogil: + cdef intp_t n_samples_X(self) noexcept nogil: """Number of samples in X.""" # This is a abstract method. # This _must_ always be overwritten in subclasses. # TODO: add "with gil: raise" here when supporting Cython 3.0 return -999 - cdef ITYPE_t n_samples_Y(self) noexcept nogil: + cdef intp_t n_samples_Y(self) noexcept nogil: """Number of samples in Y.""" # This is a abstract method. # This _must_ always be overwritten in subclasses. # TODO: add "with gil: raise" here when supporting Cython 3.0 return -999 - cdef DTYPE_t surrogate_dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t surrogate_dist(self, intp_t i, intp_t j) noexcept nogil: return self.dist(i, j) - cdef DTYPE_t dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t dist(self, intp_t i, intp_t j) noexcept nogil: # This is a abstract method. # This _must_ always be overwritten in subclasses. # TODO: add "with gil: raise" here when supporting Cython 3.0 @@ -186,19 +183,19 @@ cdef class DenseDenseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): self.Y = Y @final - cdef ITYPE_t n_samples_X(self) noexcept nogil: + cdef intp_t n_samples_X(self) noexcept nogil: return self.X.shape[0] @final - cdef ITYPE_t n_samples_Y(self) noexcept nogil: + cdef intp_t n_samples_Y(self) noexcept nogil: return self.Y.shape[0] @final - cdef DTYPE_t surrogate_dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t surrogate_dist(self, intp_t i, intp_t j) noexcept nogil: return self.distance_metric.rdist(&self.X[i, 0], &self.Y[j, 0], self.n_features) @final - cdef DTYPE_t dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t dist(self, intp_t i, intp_t j) noexcept nogil: return self.distance_metric.dist(&self.X[i, 0], &self.Y[j, 0], self.n_features) @@ -226,15 +223,15 @@ cdef class SparseSparseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): self.Y_data, self.Y_indices, self.Y_indptr = self.unpack_csr_matrix(Y) @final - cdef ITYPE_t n_samples_X(self) noexcept nogil: + cdef intp_t n_samples_X(self) noexcept nogil: return self.X_indptr.shape[0] - 1 @final - cdef ITYPE_t n_samples_Y(self) noexcept nogil: + cdef intp_t n_samples_Y(self) noexcept nogil: return self.Y_indptr.shape[0] - 1 @final - cdef DTYPE_t surrogate_dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t surrogate_dist(self, intp_t i, intp_t j) noexcept nogil: return self.distance_metric.rdist_csr( x1_data=&self.X_data[0], x1_indices=self.X_indices, @@ -248,7 +245,7 @@ cdef class SparseSparseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): ) @final - cdef DTYPE_t dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t dist(self, intp_t i, intp_t j) noexcept nogil: return self.distance_metric.dist_csr( x1_data=&self.X_data[0], x1_indices=self.X_indices, @@ -316,18 +313,18 @@ cdef class SparseDenseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): # Y array already has been checked here self.n_Y = Y.shape[0] self.Y_data = np.ravel(Y) - self.Y_indices = np.arange(self.n_features, dtype=SPARSE_INDEX_TYPE) + self.Y_indices = np.arange(self.n_features, dtype=np.int32) @final - cdef ITYPE_t n_samples_X(self) noexcept nogil: + cdef intp_t n_samples_X(self) noexcept nogil: return self.X_indptr.shape[0] - 1 @final - cdef ITYPE_t n_samples_Y(self) noexcept nogil: + cdef intp_t n_samples_Y(self) noexcept nogil: return self.n_Y @final - cdef DTYPE_t surrogate_dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t surrogate_dist(self, intp_t i, intp_t j) noexcept nogil: return self.distance_metric.rdist_csr( x1_data=&self.X_data[0], x1_indices=self.X_indices, @@ -343,7 +340,7 @@ cdef class SparseDenseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): ) @final - cdef DTYPE_t dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t dist(self, intp_t i, intp_t j) noexcept nogil: return self.distance_metric.dist_csr( x1_data=&self.X_data[0], @@ -383,22 +380,22 @@ cdef class DenseSparseDatasetsPair{{name_suffix}}(DatasetsPair{{name_suffix}}): self.datasets_pair = SparseDenseDatasetsPair{{name_suffix}}(Y, X, distance_metric) @final - cdef ITYPE_t n_samples_X(self) noexcept nogil: + cdef intp_t n_samples_X(self) noexcept nogil: # Swapping interface return self.datasets_pair.n_samples_Y() @final - cdef ITYPE_t n_samples_Y(self) noexcept nogil: + cdef intp_t n_samples_Y(self) noexcept nogil: # Swapping interface return self.datasets_pair.n_samples_X() @final - cdef DTYPE_t surrogate_dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t surrogate_dist(self, intp_t i, intp_t j) noexcept nogil: # Swapping arguments on the same interface return self.datasets_pair.surrogate_dist(j, i) @final - cdef DTYPE_t dist(self, ITYPE_t i, ITYPE_t j) noexcept nogil: + cdef float64_t dist(self, intp_t i, intp_t j) noexcept nogil: # Swapping arguments on the same interface return self.datasets_pair.dist(j, i) diff --git a/sklearn/metrics/_pairwise_distances_reduction/_middle_term_computer.pxd.tp b/sklearn/metrics/_pairwise_distances_reduction/_middle_term_computer.pxd.tp index 6b116f0f44d6f..bdf007bd0514a 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_middle_term_computer.pxd.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_middle_term_computer.pxd.tp @@ -8,30 +8,28 @@ implementation_specific_values = [ # We also use the float64 dtype and C-type names as defined in # `sklearn.utils._typedefs` to maintain consistency. # - ('64', False, 'DTYPE_t', 'DTYPE'), - ('32', True, 'cnp.float32_t', 'np.float32') + ('64', False, 'float64_t', 'np.float64'), + ('32', True, 'float32_t', 'np.float32') ] }} -cimport numpy as cnp - from libcpp.vector cimport vector -from ...utils._typedefs cimport DTYPE_t, ITYPE_t, SPARSE_INDEX_TYPE_t +from ...utils._typedefs cimport float64_t, float32_t, int32_t, intp_t cdef void _middle_term_sparse_sparse_64( - const DTYPE_t[:] X_data, - const SPARSE_INDEX_TYPE_t[:] X_indices, - const SPARSE_INDEX_TYPE_t[:] X_indptr, - ITYPE_t X_start, - ITYPE_t X_end, - const DTYPE_t[:] Y_data, - const SPARSE_INDEX_TYPE_t[:] Y_indices, - const SPARSE_INDEX_TYPE_t[:] Y_indptr, - ITYPE_t Y_start, - ITYPE_t Y_end, - DTYPE_t * D, + const float64_t[:] X_data, + const int32_t[:] X_indices, + const int32_t[:] X_indptr, + intp_t X_start, + intp_t X_end, + const float64_t[:] Y_data, + const int32_t[:] Y_indices, + const int32_t[:] Y_indptr, + intp_t Y_start, + intp_t Y_end, + float64_t * D, ) noexcept nogil @@ -40,58 +38,58 @@ cdef void _middle_term_sparse_sparse_64( cdef class MiddleTermComputer{{name_suffix}}: cdef: - ITYPE_t effective_n_threads - ITYPE_t chunks_n_threads - ITYPE_t dist_middle_terms_chunks_size - ITYPE_t n_features - ITYPE_t chunk_size + intp_t effective_n_threads + intp_t chunks_n_threads + intp_t dist_middle_terms_chunks_size + intp_t n_features + intp_t chunk_size # Buffers for the `-2 * X_c @ Y_c.T` term computed via GEMM - vector[vector[DTYPE_t]] dist_middle_terms_chunks + vector[vector[float64_t]] dist_middle_terms_chunks cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil - cdef void _parallel_on_X_parallel_init(self, ITYPE_t thread_num) noexcept nogil + cdef void _parallel_on_X_parallel_init(self, intp_t thread_num) noexcept nogil cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil cdef void _parallel_on_Y_init(self) noexcept nogil cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num ) noexcept nogil - cdef DTYPE_t * _compute_dist_middle_terms( + cdef float64_t * _compute_dist_middle_terms( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil @@ -102,95 +100,95 @@ cdef class DenseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name_ {{if upcast_to_float64}} # Buffers for upcasting chunks of X and Y from 32bit to 64bit - vector[vector[DTYPE_t]] X_c_upcast - vector[vector[DTYPE_t]] Y_c_upcast + vector[vector[float64_t]] X_c_upcast + vector[vector[float64_t]] Y_c_upcast {{endif}} cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num ) noexcept nogil - cdef DTYPE_t * _compute_dist_middle_terms( + cdef float64_t * _compute_dist_middle_terms( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil cdef class SparseSparseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name_suffix}}): cdef: - const DTYPE_t[:] X_data - const SPARSE_INDEX_TYPE_t[:] X_indices - const SPARSE_INDEX_TYPE_t[:] X_indptr + const float64_t[:] X_data + const int32_t[:] X_indices + const int32_t[:] X_indptr - const DTYPE_t[:] Y_data - const SPARSE_INDEX_TYPE_t[:] Y_indices - const SPARSE_INDEX_TYPE_t[:] Y_indptr + const float64_t[:] Y_data + const int32_t[:] Y_indices + const int32_t[:] Y_indptr cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num ) noexcept nogil cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num ) noexcept nogil - cdef DTYPE_t * _compute_dist_middle_terms( + cdef float64_t * _compute_dist_middle_terms( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil cdef class SparseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name_suffix}}): cdef: - const DTYPE_t[:] X_data - const SPARSE_INDEX_TYPE_t[:] X_indices - const SPARSE_INDEX_TYPE_t[:] X_indptr + const float64_t[:] X_data + const int32_t[:] X_indices + const int32_t[:] X_indptr const {{INPUT_DTYPE_t}}[:, ::1] Y @@ -202,29 +200,29 @@ cdef class SparseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num ) noexcept nogil cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num ) noexcept nogil - cdef DTYPE_t * _compute_dist_middle_terms( + cdef float64_t * _compute_dist_middle_terms( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil {{endfor}} diff --git a/sklearn/metrics/_pairwise_distances_reduction/_middle_term_computer.pyx.tp b/sklearn/metrics/_pairwise_distances_reduction/_middle_term_computer.pyx.tp index 255efc83565d5..f2d89ed65909c 100644 --- a/sklearn/metrics/_pairwise_distances_reduction/_middle_term_computer.pyx.tp +++ b/sklearn/metrics/_pairwise_distances_reduction/_middle_term_computer.pyx.tp @@ -8,13 +8,11 @@ implementation_specific_values = [ # We also use the float64 dtype and C-type names as defined in # `sklearn.utils._typedefs` to maintain consistency. # - ('64', False, 'DTYPE_t', 'DTYPE'), - ('32', True, 'cnp.float32_t', 'np.float32') + ('64', False, 'float64_t', 'np.float64'), + ('32', True, 'float32_t', 'np.float32') ] }} -cimport numpy as cnp - from libcpp.vector cimport vector from ...utils._cython_blas cimport ( @@ -25,7 +23,7 @@ from ...utils._cython_blas cimport ( Trans, _gemm, ) -from ...utils._typedefs cimport DTYPE_t, ITYPE_t, SPARSE_INDEX_TYPE_t +from ...utils._typedefs cimport float64_t, float32_t, int32_t, intp_t # TODO: change for `libcpp.algorithm.fill` once Cython 3 is used # Introduction in Cython: @@ -36,29 +34,29 @@ cdef extern from "" namespace "std" nogil: import numpy as np from scipy.sparse import issparse, csr_matrix -from ...utils._typedefs import DTYPE, SPARSE_INDEX_TYPE + cdef void _middle_term_sparse_sparse_64( - const DTYPE_t[:] X_data, - const SPARSE_INDEX_TYPE_t[:] X_indices, - const SPARSE_INDEX_TYPE_t[:] X_indptr, - ITYPE_t X_start, - ITYPE_t X_end, - const DTYPE_t[:] Y_data, - const SPARSE_INDEX_TYPE_t[:] Y_indices, - const SPARSE_INDEX_TYPE_t[:] Y_indptr, - ITYPE_t Y_start, - ITYPE_t Y_end, - DTYPE_t * D, + const float64_t[:] X_data, + const int32_t[:] X_indices, + const int32_t[:] X_indptr, + intp_t X_start, + intp_t X_end, + const float64_t[:] Y_data, + const int32_t[:] Y_indices, + const int32_t[:] Y_indptr, + intp_t Y_start, + intp_t Y_end, + float64_t * D, ) noexcept nogil: # This routine assumes that D points to the first element of a # zeroed buffer of length at least equal to n_X × n_Y, conceptually # representing a 2-d C-ordered array. cdef: - ITYPE_t i, j, k - ITYPE_t n_X = X_end - X_start - ITYPE_t n_Y = Y_end - Y_start - ITYPE_t x_col, x_ptr, y_col, y_ptr + intp_t i, j, k + intp_t n_X = X_end - X_start + intp_t n_Y = Y_end - Y_start + intp_t x_col, x_ptr, y_col, y_ptr for i in range(n_X): for x_ptr in range(X_indptr[X_start+i], X_indptr[X_start+i+1]): @@ -74,25 +72,25 @@ cdef void _middle_term_sparse_sparse_64( {{for name_suffix, upcast_to_float64, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}} cdef void _middle_term_sparse_dense_{{name_suffix}}( - const DTYPE_t[:] X_data, - const SPARSE_INDEX_TYPE_t[:] X_indices, - const SPARSE_INDEX_TYPE_t[:] X_indptr, - ITYPE_t X_start, - ITYPE_t X_end, + const float64_t[:] X_data, + const int32_t[:] X_indices, + const int32_t[:] X_indptr, + intp_t X_start, + intp_t X_end, const {{INPUT_DTYPE_t}}[:, ::1] Y, - ITYPE_t Y_start, - ITYPE_t Y_end, + intp_t Y_start, + intp_t Y_end, bint c_ordered_middle_term, - DTYPE_t * dist_middle_terms, + float64_t * dist_middle_terms, ) nogil: # This routine assumes that dist_middle_terms is a pointer to the first element # of a buffer filled with zeros of length at least equal to n_X × n_Y, conceptually # representing a 2-d C-ordered of F-ordered array. cdef: - ITYPE_t i, j, k - ITYPE_t n_X = X_end - X_start - ITYPE_t n_Y = Y_end - Y_start - ITYPE_t X_i_col_idx, X_i_ptr, Y_j_col_idx, Y_j_ptr + intp_t i, j, k + intp_t n_X = X_end - X_start + intp_t n_Y = Y_end - Y_start + intp_t X_i_col_idx, X_i_ptr, Y_j_col_idx, Y_j_ptr for i in range(n_X): for j in range(n_Y): @@ -206,19 +204,19 @@ cdef class MiddleTermComputer{{name_suffix}}: @classmethod def unpack_csr_matrix(cls, X: csr_matrix): - """Ensure that the CSR matrix is indexed with SPARSE_INDEX_TYPE.""" - X_data = np.asarray(X.data, dtype=DTYPE) - X_indices = np.asarray(X.indices, dtype=SPARSE_INDEX_TYPE) - X_indptr = np.asarray(X.indptr, dtype=SPARSE_INDEX_TYPE) + """Ensure that the CSR matrix is indexed with np.int32.""" + X_data = np.asarray(X.data, dtype=np.float64) + X_indices = np.asarray(X.indices, dtype=np.int32) + X_indptr = np.asarray(X.indptr, dtype=np.int32) return X_data, X_indices, X_indptr def __init__( self, - ITYPE_t effective_n_threads, - ITYPE_t chunks_n_threads, - ITYPE_t dist_middle_terms_chunks_size, - ITYPE_t n_features, - ITYPE_t chunk_size, + intp_t effective_n_threads, + intp_t chunks_n_threads, + intp_t dist_middle_terms_chunks_size, + intp_t n_features, + intp_t chunk_size, ): self.effective_n_threads = effective_n_threads self.chunks_n_threads = chunks_n_threads @@ -226,26 +224,26 @@ cdef class MiddleTermComputer{{name_suffix}}: self.n_features = n_features self.chunk_size = chunk_size - self.dist_middle_terms_chunks = vector[vector[DTYPE_t]](self.effective_n_threads) + self.dist_middle_terms_chunks = vector[vector[float64_t]](self.effective_n_threads) cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: return - cdef void _parallel_on_X_parallel_init(self, ITYPE_t thread_num) noexcept nogil: + cdef void _parallel_on_X_parallel_init(self, intp_t thread_num) noexcept nogil: self.dist_middle_terms_chunks[thread_num].resize(self.dist_middle_terms_chunks_size) cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: return @@ -257,29 +255,29 @@ cdef class MiddleTermComputer{{name_suffix}}: cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: return cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num ) noexcept nogil: return - cdef DTYPE_t * _compute_dist_middle_terms( + cdef float64_t * _compute_dist_middle_terms( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: return NULL @@ -298,11 +296,11 @@ cdef class DenseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name_ self, const {{INPUT_DTYPE_t}}[:, ::1] X, const {{INPUT_DTYPE_t}}[:, ::1] Y, - ITYPE_t effective_n_threads, - ITYPE_t chunks_n_threads, - ITYPE_t dist_middle_terms_chunks_size, - ITYPE_t n_features, - ITYPE_t chunk_size, + intp_t effective_n_threads, + intp_t chunks_n_threads, + intp_t dist_middle_terms_chunks_size, + intp_t n_features, + intp_t chunk_size, ): super().__init__( effective_n_threads, @@ -316,8 +314,8 @@ cdef class DenseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name_ {{if upcast_to_float64}} # We populate the buffer for upcasting chunks of X and Y from float32 to float64. - self.X_c_upcast = vector[vector[DTYPE_t]](self.effective_n_threads) - self.Y_c_upcast = vector[vector[DTYPE_t]](self.effective_n_threads) + self.X_c_upcast = vector[vector[float64_t]](self.effective_n_threads) + self.Y_c_upcast = vector[vector[float64_t]](self.effective_n_threads) upcast_buffer_n_elements = self.chunk_size * n_features @@ -328,94 +326,94 @@ cdef class DenseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name_ cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: {{if upcast_to_float64}} cdef: - ITYPE_t i, j - ITYPE_t n_chunk_samples = Y_end - Y_start + intp_t i, j + intp_t n_chunk_samples = Y_end - Y_start # Upcasting Y_c=Y[Y_start:Y_end, :] from float32 to float64 for i in range(n_chunk_samples): for j in range(self.n_features): - self.Y_c_upcast[thread_num][i * self.n_features + j] = self.Y[Y_start + i, j] + self.Y_c_upcast[thread_num][i * self.n_features + j] = self.Y[Y_start + i, j] {{else}} return {{endif}} cdef void _parallel_on_X_init_chunk( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: {{if upcast_to_float64}} cdef: - ITYPE_t i, j - ITYPE_t n_chunk_samples = X_end - X_start + intp_t i, j + intp_t n_chunk_samples = X_end - X_start # Upcasting X_c=X[X_start:X_end, :] from float32 to float64 for i in range(n_chunk_samples): for j in range(self.n_features): - self.X_c_upcast[thread_num][i * self.n_features + j] = self.X[X_start + i, j] + self.X_c_upcast[thread_num][i * self.n_features + j] = self.X[X_start + i, j] {{else}} return {{endif}} cdef void _parallel_on_Y_parallel_init( self, - ITYPE_t thread_num, - ITYPE_t X_start, - ITYPE_t X_end, + intp_t thread_num, + intp_t X_start, + intp_t X_end, ) noexcept nogil: {{if upcast_to_float64}} cdef: - ITYPE_t i, j - ITYPE_t n_chunk_samples = X_end - X_start + intp_t i, j + intp_t n_chunk_samples = X_end - X_start # Upcasting X_c=X[X_start:X_end, :] from float32 to float64 for i in range(n_chunk_samples): for j in range(self.n_features): - self.X_c_upcast[thread_num][i * self.n_features + j] = self.X[X_start + i, j] + self.X_c_upcast[thread_num][i * self.n_features + j] = self.X[X_start + i, j] {{else}} return {{endif}} cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num ) noexcept nogil: {{if upcast_to_float64}} cdef: - ITYPE_t i, j - ITYPE_t n_chunk_samples = Y_end - Y_start + intp_t i, j + intp_t n_chunk_samples = Y_end - Y_start # Upcasting Y_c=Y[Y_start:Y_end, :] from float32 to float64 for i in range(n_chunk_samples): for j in range(self.n_features): - self.Y_c_upcast[thread_num][i * self.n_features + j] = self.Y[Y_start + i, j] + self.Y_c_upcast[thread_num][i * self.n_features + j] = self.Y[Y_start + i, j] {{else}} return {{endif}} - cdef DTYPE_t * _compute_dist_middle_terms( + cdef float64_t * _compute_dist_middle_terms( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: cdef: - DTYPE_t *dist_middle_terms = self.dist_middle_terms_chunks[thread_num].data() + float64_t *dist_middle_terms = self.dist_middle_terms_chunks[thread_num].data() # Careful: LDA, LDB and LDC are given for F-ordered arrays # in BLAS documentations, for instance: @@ -425,24 +423,24 @@ cdef class DenseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name_ BLAS_Order order = RowMajor BLAS_Trans ta = NoTrans BLAS_Trans tb = Trans - ITYPE_t m = X_end - X_start - ITYPE_t n = Y_end - Y_start - ITYPE_t K = self.n_features - DTYPE_t alpha = - 2. + intp_t m = X_end - X_start + intp_t n = Y_end - Y_start + intp_t K = self.n_features + float64_t alpha = - 2. {{if upcast_to_float64}} - DTYPE_t * A = self.X_c_upcast[thread_num].data() - DTYPE_t * B = self.Y_c_upcast[thread_num].data() + float64_t * A = self.X_c_upcast[thread_num].data() + float64_t * B = self.Y_c_upcast[thread_num].data() {{else}} # Casting for A and B to remove the const is needed because APIs exposed via # scipy.linalg.cython_blas aren't reflecting the arguments' const qualifier. # See: https://github.com/scipy/scipy/issues/14262 - DTYPE_t * A = &self.X[X_start, 0] - DTYPE_t * B = &self.Y[Y_start, 0] + float64_t * A = &self.X[X_start, 0] + float64_t * B = &self.Y[Y_start, 0] {{endif}} - ITYPE_t lda = self.n_features - ITYPE_t ldb = self.n_features - DTYPE_t beta = 0. - ITYPE_t ldc = Y_end - Y_start + intp_t lda = self.n_features + intp_t ldb = self.n_features + float64_t beta = 0. + intp_t ldc = Y_end - Y_start # dist_middle_terms = `-2 * X[X_start:X_end] @ Y[Y_start:Y_end].T` _gemm(order, ta, tb, m, n, K, alpha, A, lda, B, ldb, beta, dist_middle_terms, ldc) @@ -466,11 +464,11 @@ cdef class SparseSparseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{nam self, X, Y, - ITYPE_t effective_n_threads, - ITYPE_t chunks_n_threads, - ITYPE_t dist_middle_terms_chunks_size, - ITYPE_t n_features, - ITYPE_t chunk_size, + intp_t effective_n_threads, + intp_t chunks_n_threads, + intp_t dist_middle_terms_chunks_size, + intp_t n_features, + intp_t chunk_size, ): super().__init__( effective_n_threads, @@ -484,11 +482,11 @@ cdef class SparseSparseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{nam cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: # Flush the thread dist_middle_terms_chunks to 0.0 fill( @@ -499,11 +497,11 @@ cdef class SparseSparseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{nam cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: # Flush the thread dist_middle_terms_chunks to 0.0 fill( @@ -512,16 +510,16 @@ cdef class SparseSparseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{nam 0.0, ) - cdef DTYPE_t * _compute_dist_middle_terms( + cdef float64_t * _compute_dist_middle_terms( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: cdef: - DTYPE_t *dist_middle_terms = ( + float64_t *dist_middle_terms = ( self.dist_middle_terms_chunks[thread_num].data() ) @@ -553,11 +551,11 @@ cdef class SparseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name self, X, Y, - ITYPE_t effective_n_threads, - ITYPE_t chunks_n_threads, - ITYPE_t dist_middle_terms_chunks_size, - ITYPE_t n_features, - ITYPE_t chunk_size, + intp_t effective_n_threads, + intp_t chunks_n_threads, + intp_t dist_middle_terms_chunks_size, + intp_t n_features, + intp_t chunk_size, bint c_ordered_middle_term, ): super().__init__( @@ -573,11 +571,11 @@ cdef class SparseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name cdef void _parallel_on_X_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: # Fill the thread's dist_middle_terms_chunks with 0.0 before # computing its elements in _compute_dist_middle_terms. @@ -589,11 +587,11 @@ cdef class SparseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name cdef void _parallel_on_Y_pre_compute_and_reduce_distances_on_chunks( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: # Fill the thread's dist_middle_terms_chunks with 0.0 before # computing its elements in _compute_dist_middle_terms. @@ -603,16 +601,16 @@ cdef class SparseDenseMiddleTermComputer{{name_suffix}}(MiddleTermComputer{{name 0.0, ) - cdef DTYPE_t * _compute_dist_middle_terms( + cdef float64_t * _compute_dist_middle_terms( self, - ITYPE_t X_start, - ITYPE_t X_end, - ITYPE_t Y_start, - ITYPE_t Y_end, - ITYPE_t thread_num, + intp_t X_start, + intp_t X_end, + intp_t Y_start, + intp_t Y_end, + intp_t thread_num, ) noexcept nogil: cdef: - DTYPE_t *dist_middle_terms = ( + float64_t *dist_middle_terms = ( self.dist_middle_terms_chunks[thread_num].data() ) diff --git a/sklearn/utils/_typedefs.pxd b/sklearn/utils/_typedefs.pxd index 7baed97c1ef03..f803b20e2efec 100644 --- a/sklearn/utils/_typedefs.pxd +++ b/sklearn/utils/_typedefs.pxd @@ -1,6 +1,3 @@ -#!python -cimport numpy as cnp - # Commonly used types # These are redefinitions of the ones defined by numpy in # https://github.com/numpy/numpy/blob/main/numpy/__init__.pxd @@ -8,7 +5,6 @@ cimport numpy as cnp # https://github.com/cython/cython/blob/master/Cython/Includes/numpy/__init__.pxd. # It will eventually avoid having to always include the numpy headers even when we # would only use it for the types. -# TODO: don't cimport numpy in this extension. # # When used to declare variables that will receive values from numpy arrays, it # should match the dtype of the array. For example, to declare a variable that will @@ -18,31 +14,14 @@ cimport numpy as cnp # TODO: Stop defining custom types locally or globally like DTYPE_t and friends and # use these consistently throughout the codebase. # NOTE: Extend this list as needed when converting more cython extensions. -ctypedef unsigned char bool_t +ctypedef unsigned char uint8_t ctypedef Py_ssize_t intp_t ctypedef float float32_t ctypedef double float64_t +# Sparse matrices indices and indices' pointers arrays must use int32_t over +# intp_t because intp_t is platform dependent. +# When large sparse matrices are supported, indexing must use int64_t. +# See https://github.com/scikit-learn/scikit-learn/issues/23653 which tracks the +# ongoing work to support large sparse matrices. ctypedef signed int int32_t ctypedef signed long long int64_t - - -# Floating point/data type -ctypedef cnp.float64_t DTYPE_t # WARNING: should match DTYPE in typedefs.pyx - -cdef enum: - DTYPECODE = cnp.NPY_FLOAT64 - -# Index/integer type. -# WARNING: ITYPE_t must be a signed integer type or you will have a bad time! -ctypedef cnp.intp_t ITYPE_t # WARNING: should match ITYPE in typedefs.pyx - -# scipy matrices indices dtype (namely for indptr and indices arrays) -# -# Note that indices might need to be represented as cnp.int64_t. -# Currently, we use Cython classes which do not handle fused types -# so we hardcode this type to cnp.int32_t, supporting all but edge -# cases. -# -# TODO: support cnp.int64_t for this case -# See: https://github.com/scikit-learn/scikit-learn/issues/23653 -ctypedef cnp.int32_t SPARSE_INDEX_TYPE_t diff --git a/sklearn/utils/_typedefs.pyx b/sklearn/utils/_typedefs.pyx index faf9bd386beca..22e18cdae8d2e 100644 --- a/sklearn/utils/_typedefs.pyx +++ b/sklearn/utils/_typedefs.pyx @@ -1,20 +1,20 @@ -#!python +# _typedefs is a declaration only module +# +# The functions implemented here are for testing purpose only. + import numpy as np -# use a hack to determine the associated numpy data types -# NOTE: the following requires the buffer interface, only available in -# numpy 1.5+. We'll choose the DTYPE by hand instead. -#cdef ITYPE_t idummy -#cdef ITYPE_t[:] idummy_view = &idummy -#ITYPE = np.asarray(idummy_view).dtype -ITYPE = np.intp # WARNING: this should match ITYPE_t in typedefs.pxd +ctypedef fused testing_type_t: + uint8_t + intp_t + float32_t + float64_t + int32_t + int64_t -#cdef DTYPE_t ddummy -#cdef DTYPE_t[:] ddummy_view = &ddummy -#DTYPE = np.asarray(ddummy_view).dtype -DTYPE = np.float64 # WARNING: this should match DTYPE_t in typedefs.pxd -# WARNING: this must match SPARSE_INDEX_TYPE_t in typedefs.pxd -SPARSE_INDEX_TYPE = np.int32 +def testing_make_array_from_typed_val(testing_type_t val): + cdef testing_type_t[:] val_view = &val + return np.asarray(val_view) diff --git a/sklearn/utils/tests/test_typedefs.py b/sklearn/utils/tests/test_typedefs.py new file mode 100644 index 0000000000000..f49356a91801a --- /dev/null +++ b/sklearn/utils/tests/test_typedefs.py @@ -0,0 +1,22 @@ +import numpy as np +import pytest + +from sklearn.utils._typedefs import testing_make_array_from_typed_val + + +@pytest.mark.parametrize( + "type_t, value, expected_dtype", + [ + ("uint8_t", 1, np.uint8), + ("intp_t", 1, np.intp), + ("float64_t", 1.0, np.float64), + ("float32_t", 1.0, np.float32), + ("int32_t", 1, np.int32), + ("int64_t", 1, np.int64), + ], +) +def test_types(type_t, value, expected_dtype): + """Check that the types defined in _typedefs correspond to the expected + numpy dtypes. + """ + assert testing_make_array_from_typed_val[type_t](value).dtype == expected_dtype From 75316ba072d73543faaa455e6f090d014dcaecbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:24:18 +0200 Subject: [PATCH 128/230] MAINT Parameters validation for datasets.make_swiss_roll (#26020) --- sklearn/datasets/_samples_generator.py | 8 ++++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 9 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index efe880d270b21..c312f4aafffa4 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1627,6 +1627,14 @@ def make_sparse_spd_matrix( return prec +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "noise": [Interval(Real, 0, None, closed="left")], + "random_state": ["random_state"], + "hole": ["boolean"], + } +) def make_swiss_roll(n_samples=100, *, noise=0.0, random_state=None, hole=False): """Generate a swiss roll dataset. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 726d6adeb8e85..fdffc85b20488 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -146,6 +146,7 @@ def _check_function_param_validation( "sklearn.datasets.make_sparse_spd_matrix", "sklearn.datasets.make_sparse_uncorrelated", "sklearn.datasets.make_spd_matrix", + "sklearn.datasets.make_swiss_roll", "sklearn.decomposition.sparse_encode", "sklearn.feature_extraction.grid_to_graph", "sklearn.feature_extraction.img_to_graph", From d7aa0667b5931e554d5a735c26e66ffe03053545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:25:00 +0200 Subject: [PATCH 129/230] MAINT Parameters validation for datasets.make_s_curve (#26022) --- sklearn/datasets/_samples_generator.py | 7 +++++++ sklearn/tests/test_public_functions.py | 1 + 2 files changed, 8 insertions(+) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index c312f4aafffa4..d1f0d54cd6fc6 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -1700,6 +1700,13 @@ def make_swiss_roll(n_samples=100, *, noise=0.0, random_state=None, hole=False): return X, t +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left")], + "noise": [Interval(Real, 0, None, closed="left")], + "random_state": ["random_state"], + } +) def make_s_curve(n_samples=100, *, noise=0.0, random_state=None): """Generate an S curve dataset. diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index fdffc85b20488..2d13140aad89f 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -142,6 +142,7 @@ def _check_function_param_validation( "sklearn.datasets.make_moons", "sklearn.datasets.make_multilabel_classification", "sklearn.datasets.make_regression", + "sklearn.datasets.make_s_curve", "sklearn.datasets.make_sparse_coded_signal", "sklearn.datasets.make_sparse_spd_matrix", "sklearn.datasets.make_sparse_uncorrelated", From cf695edef05d9624bbf51c6503798ed51ff52f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Baranger?= <39696928+tbaranger@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:35:16 +0200 Subject: [PATCH 130/230] MAINT Parameters validation for datasets.make_blobs (#25983) Co-authored-by: Guillaume Lemaitre --- sklearn/datasets/_samples_generator.py | 29 +++++++++++++++++--------- sklearn/tests/test_public_functions.py | 1 + 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/sklearn/datasets/_samples_generator.py b/sklearn/datasets/_samples_generator.py index d1f0d54cd6fc6..cb3b36d944eb2 100644 --- a/sklearn/datasets/_samples_generator.py +++ b/sklearn/datasets/_samples_generator.py @@ -855,6 +855,18 @@ def make_moons(n_samples=100, *, shuffle=True, noise=None, random_state=None): return X, y +@validate_params( + { + "n_samples": [Interval(Integral, 1, None, closed="left"), "array-like"], + "n_features": [Interval(Integral, 1, None, closed="left")], + "centers": [Interval(Integral, 1, None, closed="left"), "array-like", None], + "cluster_std": [Interval(Real, 0, None, closed="left"), "array-like"], + "center_box": [tuple], + "shuffle": ["boolean"], + "random_state": ["random_state"], + "return_centers": ["boolean"], + } +) def make_blobs( n_samples=100, n_features=2, @@ -884,7 +896,7 @@ def make_blobs( n_features : int, default=2 The number of features for each sample. - centers : int or ndarray of shape (n_centers, n_features), default=None + centers : int or array-like of shape (n_centers, n_features), default=None The number of centers to generate, or the fixed center locations. If n_samples is an int and centers is None, 3 centers are generated. If n_samples is array-like, centers must be @@ -967,22 +979,19 @@ def make_blobs( centers = generator.uniform( center_box[0], center_box[1], size=(n_centers, n_features) ) - try: - assert len(centers) == n_centers - except TypeError as e: + if not isinstance(centers, Iterable): raise ValueError( "Parameter `centers` must be array-like. Got {!r} instead".format( centers ) - ) from e - except AssertionError as e: + ) + if len(centers) != n_centers: raise ValueError( "Length of `n_samples` not consistent with number of " f"centers. Got n_samples = {n_samples} and centers = {centers}" - ) from e - else: - centers = check_array(centers) - n_features = centers.shape[1] + ) + centers = check_array(centers) + n_features = centers.shape[1] # stds: if cluster_std is given as list, it must be consistent # with the n_centers diff --git a/sklearn/tests/test_public_functions.py b/sklearn/tests/test_public_functions.py index 2d13140aad89f..e127369072828 100644 --- a/sklearn/tests/test_public_functions.py +++ b/sklearn/tests/test_public_functions.py @@ -130,6 +130,7 @@ def _check_function_param_validation( "sklearn.datasets.load_svmlight_file", "sklearn.datasets.load_svmlight_files", "sklearn.datasets.make_biclusters", + "sklearn.datasets.make_blobs", "sklearn.datasets.make_checkerboard", "sklearn.datasets.make_circles", "sklearn.datasets.make_classification", From 1953454cd67c855f536098cb1ee75bd392c5fd53 Mon Sep 17 00:00:00 2001 From: Yao Xiao <108576690+Charlie-XIAO@users.noreply.github.com> Date: Thu, 30 Mar 2023 20:50:17 +0800 Subject: [PATCH 131/230] DOC fix SplineTransformer include_bias docstring (#26018) --- sklearn/preprocessing/_polynomial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/preprocessing/_polynomial.py b/sklearn/preprocessing/_polynomial.py index 9e09715a50718..eefe2936d2d99 100644 --- a/sklearn/preprocessing/_polynomial.py +++ b/sklearn/preprocessing/_polynomial.py @@ -517,7 +517,7 @@ class SplineTransformer(TransformerMixin, BaseEstimator): recommended to manually set the knot values to control the period. include_bias : bool, default=True - If True (default), then the last spline element inside the data range + If False, then the last spline element inside the data range of a feature is dropped. As B-splines sum to one over the spline basis functions for each data point, they implicitly include a bias term, i.e. a column of ones. It acts as an intercept term in a linear models. From 5bf7defcb7fe913a993eaac3067780d1c873c018 Mon Sep 17 00:00:00 2001 From: Yao Xiao <108576690+Charlie-XIAO@users.noreply.github.com> Date: Thu, 30 Mar 2023 23:18:52 +0800 Subject: [PATCH 132/230] ENH RocCurveDisplay add option to plot chance level (#25987) --- doc/whats_new/v1.3.rst | 6 ++ .../plot_outlier_detection_bench.py | 12 +-- examples/model_selection/plot_roc.py | 10 +-- examples/model_selection/plot_roc_crossval.py | 5 +- sklearn/metrics/_plot/roc_curve.py | 76 ++++++++++++++++++- .../_plot/tests/test_roc_curve_display.py | 68 +++++++++++++++++ 6 files changed, 163 insertions(+), 14 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 07b581f2104b1..458f3929f6ccf 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -321,6 +321,12 @@ Changelog curves. :pr:`24668` by :user:`dberenbaum`. +- |Enhancement| :meth:`metrics.RocCurveDisplay.from_estimator` and + :meth:`metrics.RocCurveDisplay.from_predictions` now accept two new keywords, + `plot_chance_level` and `chance_level_kw` to plot the baseline chance + level. This line is exposed in the `chance_level_` attribute. + :pr:`25987` by :user:`Yao Xiao `. + - |Fix| :func:`log_loss` raises a warning if the values of the parameter `y_pred` are not normalized, instead of actually normalizing them in the metric. Starting from 1.5 this will raise an error. :pr:`25299` by :user:`Omar Salman Date: Thu, 30 Mar 2023 17:53:04 +0200 Subject: [PATCH 133/230] DOC show from_estimator and from_predictions for Displays (#25994) --- doc/modules/classes.rst | 6 +++--- doc/templates/display_all_class_methods.rst | 14 ++++++++++++++ doc/templates/display_only_from_estimator.rst | 13 +++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 doc/templates/display_all_class_methods.rst create mode 100644 doc/templates/display_only_from_estimator.rst diff --git a/doc/modules/classes.rst b/doc/modules/classes.rst index 1e61ac5aac08a..96cc18540bae3 100644 --- a/doc/modules/classes.rst +++ b/doc/modules/classes.rst @@ -659,7 +659,7 @@ Plotting .. autosummary:: :toctree: generated/ - :template: class.rst + :template: display_only_from_estimator.rst inspection.DecisionBoundaryDisplay inspection.PartialDependenceDisplay @@ -1122,7 +1122,7 @@ See the :ref:`visualizations` section of the user guide for further details. .. autosummary:: :toctree: generated/ - :template: class.rst + :template: display.rst metrics.ConfusionMatrixDisplay metrics.DetCurveDisplay @@ -1242,7 +1242,7 @@ Visualization .. autosummary:: :toctree: generated/ - :template: class.rst + :template: display_only_from_estimator.rst model_selection.LearningCurveDisplay diff --git a/doc/templates/display_all_class_methods.rst b/doc/templates/display_all_class_methods.rst new file mode 100644 index 0000000000000..1211296bb57ce --- /dev/null +++ b/doc/templates/display_all_class_methods.rst @@ -0,0 +1,14 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}============== + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + +.. include:: {{module}}.{{objname}}.examples +.. include:: {{module}}.{{objname}}.from_estimator.examples +.. include:: {{module}}.{{objname}}.from_predictions.examples + +.. raw:: html + +
diff --git a/doc/templates/display_only_from_estimator.rst b/doc/templates/display_only_from_estimator.rst new file mode 100644 index 0000000000000..6d064133fc5e2 --- /dev/null +++ b/doc/templates/display_only_from_estimator.rst @@ -0,0 +1,13 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}============== + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + +.. include:: {{module}}.{{objname}}.examples +.. include:: {{module}}.{{objname}}.from_estimator.examples + +.. raw:: html + +
From 9caf93657aaa8ee485c2ba88b1c2692cc59e15bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= Date: Thu, 30 Mar 2023 19:30:41 +0200 Subject: [PATCH 134/230] EXA Fix rst in plot_partial_dependence (#26028) --- examples/inspection/plot_partial_dependence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/inspection/plot_partial_dependence.py b/examples/inspection/plot_partial_dependence.py index f2f6c2949bb84..7572f146d6363 100644 --- a/examples/inspection/plot_partial_dependence.py +++ b/examples/inspection/plot_partial_dependence.py @@ -198,7 +198,7 @@ # features and individual conditional expectation (ICE). # # Multi-layer perceptron -# """""""""""""""""""""" +# ~~~~~~~~~~~~~~~~~~~~~~ # # Let's fit a :class:`~sklearn.neural_network.MLPRegressor` and compute # single-variable partial dependence plots. @@ -278,7 +278,7 @@ # %% # Gradient boosting -# """"""""""""""""" +# ~~~~~~~~~~~~~~~~~ # # Let's now fit a :class:`~sklearn.ensemble.HistGradientBoostingRegressor` and # compute the partial dependence on the same features. We also use the @@ -330,7 +330,7 @@ # %% # Analysis of the plots -# """"""""""""""""""""" +# ~~~~~~~~~~~~~~~~~~~~~ # # We will first look at the PDPs for the numerical features. For both models, the # general trend of the PDP of the temperature is that the number of bike rentals is @@ -352,7 +352,7 @@ # synthetic samples if features are correlated. # # ICE vs. PDP -# """"""""""" +# ~~~~~~~~~~~ # PDP is an average of the marginal effects of the features. We are averaging the # response of all samples of the provided set. Thus, some effects could be hidden. In # this regard, it is possible to plot each individual response. This representation is @@ -521,7 +521,7 @@ # %% # 3D representation -# """"""""""""""""" +# ~~~~~~~~~~~~~~~~~ # # Let's make the same partial dependence plot for the 2 features interaction, # this time in 3 dimensions. From 05fdbae54f8d0e0d8458d054c3eb441cbfbcb2fb Mon Sep 17 00:00:00 2001 From: "Thomas J. Fan" Date: Sun, 2 Apr 2023 05:06:59 -0400 Subject: [PATCH 135/230] CI Adds coverage to docker jobs on Azure (#26027) Co-authored-by: Julien Jerphanion Co-authored-by: Olivier Grisel --- azure-pipelines.yml | 1 + build_tools/azure/combine_coverage_reports.sh | 17 +++++++ build_tools/azure/debian_atlas_32bit_lock.txt | 6 +++ .../azure/debian_atlas_32bit_requirements.txt | 1 + build_tools/azure/posix-docker.yml | 15 ++++++ build_tools/azure/posix.yml | 5 ++ build_tools/azure/test_script.sh | 8 +-- build_tools/azure/upload_codecov.sh | 49 +++++++++++-------- build_tools/azure/windows.yml | 16 +++--- build_tools/shared.sh | 8 +++ .../update_environments_and_lock_files.py | 9 +++- 11 files changed, 101 insertions(+), 34 deletions(-) create mode 100755 build_tools/azure/combine_coverage_reports.sh diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0ba11773a978d..af9044665a912 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -232,6 +232,7 @@ jobs: debian_atlas_32bit: DOCKER_CONTAINER: 'i386/debian:11.2' DISTRIB: 'debian-32' + COVERAGE: "true" LOCK_FILE: './build_tools/azure/debian_atlas_32bit_lock.txt' # disable pytest xdist due to unknown bug with 32-bit container PYTEST_XDIST_VERSION: 'none' diff --git a/build_tools/azure/combine_coverage_reports.sh b/build_tools/azure/combine_coverage_reports.sh new file mode 100755 index 0000000000000..e1f28c8f0e24a --- /dev/null +++ b/build_tools/azure/combine_coverage_reports.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -e + +# Defines the show_installed_libraries and activate_environment functions. +source build_tools/shared.sh + +activate_environment + +# Combine all coverage files generated by subprocesses workers such +# such as pytest-xdist and joblib/loky: +pushd $TEST_DIR +coverage combine --append +popd + +# Copy the combined coverage file to the root of the repository: +cp $TEST_DIR/.coverage $BUILD_REPOSITORY_LOCALPATH diff --git a/build_tools/azure/debian_atlas_32bit_lock.txt b/build_tools/azure/debian_atlas_32bit_lock.txt index dbcc32cd1ff78..74d387a906a4a 100644 --- a/build_tools/azure/debian_atlas_32bit_lock.txt +++ b/build_tools/azure/debian_atlas_32bit_lock.txt @@ -6,6 +6,8 @@ # attrs==22.2.0 # via pytest +coverage==7.2.2 + # via pytest-cov cython==0.29.33 # via -r build_tools/azure/debian_atlas_32bit_requirements.txt joblib==1.1.1 @@ -19,6 +21,10 @@ pluggy==0.13.1 py==1.11.0 # via pytest pytest==5.3.1 + # via + # -r build_tools/azure/debian_atlas_32bit_requirements.txt + # pytest-cov +pytest-cov==2.9.0 # via -r build_tools/azure/debian_atlas_32bit_requirements.txt threadpoolctl==2.2.0 # via -r build_tools/azure/debian_atlas_32bit_requirements.txt diff --git a/build_tools/azure/debian_atlas_32bit_requirements.txt b/build_tools/azure/debian_atlas_32bit_requirements.txt index 6ce3aa8615eb6..c13ab3700d7d3 100644 --- a/build_tools/azure/debian_atlas_32bit_requirements.txt +++ b/build_tools/azure/debian_atlas_32bit_requirements.txt @@ -5,3 +5,4 @@ cython joblib==1.1.1 # min threadpoolctl==2.2.0 pytest==5.3.1 # min +pytest-cov==2.9.0 # min diff --git a/build_tools/azure/posix-docker.yml b/build_tools/azure/posix-docker.yml index dff3ccaab1a5e..976d79d2e1250 100644 --- a/build_tools/azure/posix-docker.yml +++ b/build_tools/azure/posix-docker.yml @@ -56,13 +56,17 @@ jobs: - script: > docker container run --rm --volume $TEST_DIR:/temp_dir + --volume $BUILD_REPOSITORY_LOCALPATH:/repo_localpath --volume $PWD:/io --volume $CCACHE_DIR:/ccache -w /io --detach --name skcontainer + -e BUILD_SOURCESDIRECTORY=/io -e TEST_DIR=/temp_dir -e CCACHE_DIR=/ccache + -e BUILD_REPOSITORY_LOCALPATH=/repo_localpath + -e COVERAGE -e DISTRIB -e LOCK_FILE -e JUNITXML @@ -82,6 +86,11 @@ jobs: - script: > docker exec skcontainer ./build_tools/azure/test_script.sh displayName: 'Test Library' + - script: > + docker exec skcontainer ./build_tools/azure/combine_coverage_reports.sh + condition: and(succeeded(), eq(variables['COVERAGE'], 'true'), + eq(variables['SELECTED_TESTS'], '')) + displayName: 'Combine coverage' - task: PublishTestResults@2 inputs: testResultsFiles: '$(TEST_DIR)/$(JUNITXML)' @@ -116,3 +125,9 @@ jobs: JUNIT_FILE: $(TEST_DIR)/$(JUNITXML) condition: and(succeededOrFailed(), eq(variables['CREATE_ISSUE_ON_TRACKER'], 'true'), eq(variables['Build.Reason'], 'Schedule')) + - bash: bash build_tools/azure/upload_codecov.sh + condition: and(succeeded(), eq(variables['COVERAGE'], 'true'), + eq(variables['SELECTED_TESTS'], '')) + displayName: 'Upload To Codecov' + env: + CODECOV_TOKEN: $(CODECOV_TOKEN) diff --git a/build_tools/azure/posix.yml b/build_tools/azure/posix.yml index 9499060d9c3f2..8ee9839d24601 100644 --- a/build_tools/azure/posix.yml +++ b/build_tools/azure/posix.yml @@ -67,6 +67,11 @@ jobs: condition: and(succeeded(), eq(variables['CHECK_PYTEST_SOFT_DEPENDENCY'], 'true'), eq(variables['SELECTED_TESTS'], '')) + - script: | + build_tools/azure/combine_coverage_reports.sh + condition: and(succeeded(), eq(variables['COVERAGE'], 'true'), + eq(variables['SELECTED_TESTS'], '')) + displayName: 'Combine coverage' - task: PublishTestResults@2 inputs: testResultsFiles: '$(TEST_DIR)/$(JUNITXML)' diff --git a/build_tools/azure/test_script.sh b/build_tools/azure/test_script.sh index 52bc7b727e020..3918f510584fb 100755 --- a/build_tools/azure/test_script.sh +++ b/build_tools/azure/test_script.sh @@ -2,14 +2,10 @@ set -e -# defines the show_installed_libraries function +# Defines the show_installed_libraries and activate_environment functions. source build_tools/shared.sh -if [[ "$DISTRIB" =~ ^conda.* ]]; then - source activate $VIRTUALENV -elif [[ "$DISTRIB" == "ubuntu" || "$DISTRIB" == "debian-32" || "$DISTRIB" == "pip-nogil" ]]; then - source $VIRTUALENV/bin/activate -fi +activate_environment if [[ "$BUILD_REASON" == "Schedule" ]]; then # Enable global random seed randomization to discover seed-sensitive tests diff --git a/build_tools/azure/upload_codecov.sh b/build_tools/azure/upload_codecov.sh index e1fe65d496188..622d2e7fedeff 100755 --- a/build_tools/azure/upload_codecov.sh +++ b/build_tools/azure/upload_codecov.sh @@ -2,41 +2,48 @@ set -e -# called when COVERAGE=="true" and DISTRIB=="conda" -export PATH=$HOME/miniconda3/bin:$PATH -source activate $VIRTUALENV - -# Need to run codecov from a git checkout, so we copy .coverage -# from TEST_DIR where pytest has been run -pushd $TEST_DIR -coverage combine --append -popd -cp $TEST_DIR/.coverage $BUILD_REPOSITORY_LOCALPATH - # When we update the codecov uploader version, we need to update the checksums. # The checksum for each codecov binary is available at # https://uploader.codecov.io e.g. for linux -# https://uploader.codecov.io/v0.4.0/linux/codecov.SHA256SUM. In principle we -# need to check the signatures with the codecov gpg key as well, see +# https://uploader.codecov.io/v0.4.1/linux/codecov.SHA256SUM. + +# Instead of hardcoding a specific version and signature in this script, it +# would be possible to use the "latest" symlink URL but then we need to +# download both the codecov.SHA256SUM files each time and check the signatures +# with the codecov gpg key as well, see: # https://docs.codecov.com/docs/codecov-uploader#integrity-checking-the-uploader -# for more details -CODECOV_UPLOADER_VERSION=0.4.0 +# However this approach would yield a larger number of downloads from +# codecov.io and keybase.io, therefore increasing the risk of running into +# network failures. +CODECOV_UPLOADER_VERSION=0.4.1 CODECOV_BASE_URL="https://uploader.codecov.io/v$CODECOV_UPLOADER_VERSION" + + +# Check that the git repo is located at the expected location: +if [[ ! -d "$BUILD_REPOSITORY_LOCALPATH/.git" ]]; then + echo "Could not find the git checkout at $BUILD_REPOSITORY_LOCALPATH" + exit 1 +fi +# Check that the combined coverage file exists at the expected location: +if [[ ! -f "$BUILD_REPOSITORY_LOCALPATH/.coverage" ]]; then + echo "Could not find the combined coverage file at $BUILD_REPOSITORY_LOCALPATH/.coverage" + exit 1 +fi if [[ $OSTYPE == *"linux"* ]]; then curl -Os "$CODECOV_BASE_URL/linux/codecov" - SHA256SUM="671cf0d89d1c149f57e1a9a31f3fb567ab4209e4d5829f13ff7b8c104db7131f codecov" + SHA256SUM="32cb14b5f3aaacd67f4c1ff55d82f037d3cd10c8e7b69c051f27391d2e66e15c codecov" echo "$SHA256SUM" | shasum -a256 -c chmod +x codecov - ./codecov -t ${CODECOV_TOKEN} --rootDir $BUILD_REPOSITORY_LOCALPATH + ./codecov -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f .coverage -Z elif [[ $OSTYPE == *"darwin"* ]]; then curl -Os "$CODECOV_BASE_URL/macos/codecov" - SHA256SUM="7549819f0fe115e113ec3538e259d748e87d84f68afa5deadc798967ec716b8d codecov" + SHA256SUM="4ab0f06f06e9c4d25464f155b0aff36bfc1e8dbcdb19bfffd586beed1269f3af codecov" echo "$SHA256SUM" | shasum -a256 -c chmod +x codecov - ./codecov -t ${CODECOV_TOKEN} --rootDir $BUILD_REPOSITORY_LOCALPATH + ./codecov -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f .coverage -Z else curl -Os "$CODECOV_BASE_URL/windows/codecov.exe" - SHA256SUM="15fb34be4eb9949ad4e964a0e21c4efc79657de05b2c799e041d7293dccf60eb codecov.exe" + SHA256SUM="e0cda212aeaebe695509ce8fa2d608760ff70bc932003f544f1ad368ac5450a8 codecov.exe" echo "$SHA256SUM" | sha256sum -c - ./codecov.exe -t ${CODECOV_TOKEN} --rootDir $BUILD_REPOSITORY_LOCALPATH + ./codecov.exe -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f .coverage -Z fi diff --git a/build_tools/azure/windows.yml b/build_tools/azure/windows.yml index dc8556c1e09ce..02b0e1a4d609d 100644 --- a/build_tools/azure/windows.yml +++ b/build_tools/azure/windows.yml @@ -41,13 +41,10 @@ jobs: displayName: 'Install' - bash: ./build_tools/azure/test_script.sh displayName: 'Test Library' - - bash: ./build_tools/azure/upload_codecov.sh - condition: and(succeeded(), - eq(variables['COVERAGE'], 'true'), + - bash: ./build_tools/azure/combine_coverage_reports.sh + condition: and(succeeded(), eq(variables['COVERAGE'], 'true'), eq(variables['SELECTED_TESTS'], '')) - displayName: 'Upload To Codecov' - env: - CODECOV_TOKEN: $(CODECOV_TOKEN) + displayName: 'Combine coverage' - task: PublishTestResults@2 inputs: testResultsFiles: '$(TEST_DIR)/$(JUNITXML)' @@ -78,3 +75,10 @@ jobs: JUNIT_FILE: $(TEST_DIR)/$(JUNITXML) condition: and(succeededOrFailed(), eq(variables['CREATE_ISSUE_ON_TRACKER'], 'true'), eq(variables['Build.Reason'], 'Schedule')) + - bash: ./build_tools/azure/upload_codecov.sh + condition: and(succeeded(), + eq(variables['COVERAGE'], 'true'), + eq(variables['SELECTED_TESTS'], '')) + displayName: 'Upload To Codecov' + env: + CODECOV_TOKEN: $(CODECOV_TOKEN) diff --git a/build_tools/shared.sh b/build_tools/shared.sh index 29ce8b27a3810..4866c149d506f 100644 --- a/build_tools/shared.sh +++ b/build_tools/shared.sh @@ -25,3 +25,11 @@ show_installed_libraries(){ python -m pip list fi } + +activate_environment() { + if [[ "$DISTRIB" =~ ^conda.* ]]; then + source activate $VIRTUALENV + elif [[ "$DISTRIB" == "ubuntu" || "$DISTRIB" == "debian-32" || "$DISTRIB" == "pip-nogil" ]]; then + source $VIRTUALENV/bin/activate + fi +} diff --git a/build_tools/update_environments_and_lock_files.py b/build_tools/update_environments_and_lock_files.py index ec375078bfab8..396191fbe6a04 100644 --- a/build_tools/update_environments_and_lock_files.py +++ b/build_tools/update_environments_and_lock_files.py @@ -329,11 +329,18 @@ def remove_from(alist, to_remove): { "build_name": "debian_atlas_32bit", "folder": "build_tools/azure", - "pip_dependencies": ["cython", "joblib", "threadpoolctl", "pytest"], + "pip_dependencies": [ + "cython", + "joblib", + "threadpoolctl", + "pytest", + "pytest-cov", + ], "package_constraints": { "joblib": "min", "threadpoolctl": "2.2.0", "pytest": "min", + "pytest-cov": "min", # no pytest-xdist because it causes issue on 32bit }, # same Python version as in debian-32 build From 7d4cd14556317608a8dda80b528cb47b0b117ace Mon Sep 17 00:00:00 2001 From: John Pangas Date: Sun, 2 Apr 2023 16:02:04 +0300 Subject: [PATCH 136/230] API Replace `n_iter` in `Bayesian Ridge` and `ARDRegression` (#25697) Co-authored-by: Guillaume Lemaitre --- doc/whats_new/v1.3.rst | 18 +++- sklearn/linear_model/_bayes.py | 114 ++++++++++++++++++++--- sklearn/linear_model/tests/test_bayes.py | 34 ++++++- 3 files changed, 147 insertions(+), 19 deletions(-) diff --git a/doc/whats_new/v1.3.rst b/doc/whats_new/v1.3.rst index 458f3929f6ccf..4fede62e61b34 100644 --- a/doc/whats_new/v1.3.rst +++ b/doc/whats_new/v1.3.rst @@ -273,9 +273,21 @@ Changelog :mod:`sklearn.linear_model` ........................... -- |Enhancement| :class:`SGDClassifier`, :class:`SGDRegressor` and - :class:`SGDOneClassSVM` now preserve dtype for `numpy.float32`. - :pr:`25587` by :user:`Omar Salman ` +- |Enhancement| :class:`linear_model.SGDClassifier`, + :class:`linear_model.SGDRegressor` and :class:`linear_model.SGDOneClassSVM` + now preserve dtype for `numpy.float32`. + :pr:`25587` by :user:`Omar Salman `. + +- |API| Deprecates `n_iter` in favor of `max_iter` in + :class:`linear_model.BayesianRidge` and :class:`linear_model.ARDRegression`. + `n_iter` will be removed in scikit-learn 1.5. This change makes those + estimators consistent with the rest of estimators. + :pr:`25697` by :user:`John Pangas `. + +- |Enhancement| The `n_iter_` attribute has been included in + :class:`linear_model.ARDRegression` to expose the actual number of iterations + required to reach the stopping criterion. + :pr:`25697` by :user:`John Pangas `. :mod:`sklearn.metrics` ...................... diff --git a/sklearn/linear_model/_bayes.py b/sklearn/linear_model/_bayes.py index 7f712b12bca45..22d76162db936 100644 --- a/sklearn/linear_model/_bayes.py +++ b/sklearn/linear_model/_bayes.py @@ -5,6 +5,7 @@ # Authors: V. Michel, F. Pedregosa, A. Gramfort # License: BSD 3 clause +import warnings from math import log from numbers import Integral, Real import numpy as np @@ -15,7 +16,49 @@ from ..utils.extmath import fast_logdet from scipy.linalg import pinvh from ..utils.validation import _check_sample_weight -from ..utils._param_validation import Interval +from ..utils._param_validation import Interval, Hidden, StrOptions + + +# TODO(1.5) Remove +def _deprecate_n_iter(n_iter, max_iter): + """Deprecates n_iter in favour of max_iter. Checks if the n_iter has been + used instead of max_iter and generates a deprecation warning if True. + + Parameters + ---------- + n_iter : int, + Value of n_iter attribute passed by the estimator. + + max_iter : int, default=None + Value of max_iter attribute passed by the estimator. + If `None`, it corresponds to `max_iter=300`. + + Returns + ------- + max_iter : int, + Value of max_iter which shall further be used by the estimator. + + Notes + ----- + This function should be completely removed in 1.5. + """ + if n_iter != "deprecated": + if max_iter is not None: + raise ValueError( + "Both `n_iter` and `max_iter` attributes were set. Attribute" + " `n_iter` was deprecated in version 1.3 and will be removed in" + " 1.5. To avoid this error, only set the `max_iter` attribute." + ) + warnings.warn( + "'n_iter' was renamed to 'max_iter' in version 1.3 and " + "will be removed in 1.5", + FutureWarning, + ) + max_iter = n_iter + elif max_iter is None: + max_iter = 300 + return max_iter + ############################################################################### # BayesianRidge regression @@ -32,8 +75,12 @@ class BayesianRidge(RegressorMixin, LinearModel): Parameters ---------- - n_iter : int, default=300 - Maximum number of iterations. Should be greater than or equal to 1. + max_iter : int, default=None + Maximum number of iterations over the complete dataset before + stopping independently of any early stopping criterion. If `None`, it + corresponds to `max_iter=300`. + + .. versionchanged:: 1.3 tol : float, default=1e-3 Stop the algorithm if w has converged. @@ -83,6 +130,13 @@ class BayesianRidge(RegressorMixin, LinearModel): verbose : bool, default=False Verbose mode when fitting the model. + n_iter : int + Maximum number of iterations. Should be greater than or equal to 1. + + .. deprecated:: 1.3 + `n_iter` is deprecated in 1.3 and will be removed in 1.5. Use + `max_iter` instead. + Attributes ---------- coef_ : array-like of shape (n_features,) @@ -90,7 +144,7 @@ class BayesianRidge(RegressorMixin, LinearModel): intercept_ : float Independent term in decision function. Set to 0.0 if - ``fit_intercept = False``. + `fit_intercept = False`. alpha_ : float Estimated precision of the noise. @@ -162,7 +216,7 @@ class BayesianRidge(RegressorMixin, LinearModel): """ _parameter_constraints: dict = { - "n_iter": [Interval(Integral, 1, None, closed="left")], + "max_iter": [Interval(Integral, 1, None, closed="left"), None], "tol": [Interval(Real, 0, None, closed="neither")], "alpha_1": [Interval(Real, 0, None, closed="left")], "alpha_2": [Interval(Real, 0, None, closed="left")], @@ -174,12 +228,16 @@ class BayesianRidge(RegressorMixin, LinearModel): "fit_intercept": ["boolean"], "copy_X": ["boolean"], "verbose": ["verbose"], + "n_iter": [ + Interval(Integral, 1, None, closed="left"), + Hidden(StrOptions({"deprecated"})), + ], } def __init__( self, *, - n_iter=300, + max_iter=None, # TODO(1.5): Set to 300 tol=1.0e-3, alpha_1=1.0e-6, alpha_2=1.0e-6, @@ -191,8 +249,9 @@ def __init__( fit_intercept=True, copy_X=True, verbose=False, + n_iter="deprecated", # TODO(1.5): Remove ): - self.n_iter = n_iter + self.max_iter = max_iter self.tol = tol self.alpha_1 = alpha_1 self.alpha_2 = alpha_2 @@ -204,6 +263,7 @@ def __init__( self.fit_intercept = fit_intercept self.copy_X = copy_X self.verbose = verbose + self.n_iter = n_iter def fit(self, X, y, sample_weight=None): """Fit the model. @@ -228,6 +288,8 @@ def fit(self, X, y, sample_weight=None): """ self._validate_params() + max_iter = _deprecate_n_iter(self.n_iter, self.max_iter) + X, y = self._validate_data(X, y, dtype=[np.float64, np.float32], y_numeric=True) if sample_weight is not None: @@ -274,7 +336,7 @@ def fit(self, X, y, sample_weight=None): eigen_vals_ = S**2 # Convergence loop of the bayesian ridge regression - for iter_ in range(self.n_iter): + for iter_ in range(max_iter): # update posterior mean coef_ based on alpha_ and lambda_ and # compute corresponding rmse @@ -430,8 +492,10 @@ class ARDRegression(RegressorMixin, LinearModel): Parameters ---------- - n_iter : int, default=300 - Maximum number of iterations. + max_iter : int, default=None + Maximum number of iterations. If `None`, it corresponds to `max_iter=300`. + + .. versionchanged:: 1.3 tol : float, default=1e-3 Stop the algorithm if w has converged. @@ -470,6 +534,13 @@ class ARDRegression(RegressorMixin, LinearModel): verbose : bool, default=False Verbose mode when fitting the model. + n_iter : int + Maximum number of iterations. + + .. deprecated:: 1.3 + `n_iter` is deprecated in 1.3 and will be removed in 1.5. Use + `max_iter` instead. + Attributes ---------- coef_ : array-like of shape (n_features,) @@ -487,6 +558,11 @@ class ARDRegression(RegressorMixin, LinearModel): scores_ : float if computed, value of the objective function (to be maximized) + n_iter_ : int + The actual number of iterations to reach the stopping criterion. + + .. versionadded:: 1.3 + intercept_ : float Independent term in decision function. Set to 0.0 if ``fit_intercept = False``. @@ -542,7 +618,7 @@ class ARDRegression(RegressorMixin, LinearModel): """ _parameter_constraints: dict = { - "n_iter": [Interval(Integral, 1, None, closed="left")], + "max_iter": [Interval(Integral, 1, None, closed="left"), None], "tol": [Interval(Real, 0, None, closed="left")], "alpha_1": [Interval(Real, 0, None, closed="left")], "alpha_2": [Interval(Real, 0, None, closed="left")], @@ -553,12 +629,16 @@ class ARDRegression(RegressorMixin, LinearModel): "fit_intercept": ["boolean"], "copy_X": ["boolean"], "verbose": ["verbose"], + "n_iter": [ + Interval(Integral, 1, None, closed="left"), + Hidden(StrOptions({"deprecated"})), + ], } def __init__( self, *, - n_iter=300, + max_iter=None, # TODO(1.5): Set to 300 tol=1.0e-3, alpha_1=1.0e-6, alpha_2=1.0e-6, @@ -569,8 +649,9 @@ def __init__( fit_intercept=True, copy_X=True, verbose=False, + n_iter="deprecated", # TODO(1.5): Remove ): - self.n_iter = n_iter + self.max_iter = max_iter self.tol = tol self.fit_intercept = fit_intercept self.alpha_1 = alpha_1 @@ -581,6 +662,7 @@ def __init__( self.threshold_lambda = threshold_lambda self.copy_X = copy_X self.verbose = verbose + self.n_iter = n_iter def fit(self, X, y): """Fit the model according to the given training data and parameters. @@ -603,6 +685,8 @@ def fit(self, X, y): self._validate_params() + max_iter = _deprecate_n_iter(self.n_iter, self.max_iter) + X, y = self._validate_data( X, y, dtype=[np.float64, np.float32], y_numeric=True, ensure_min_samples=2 ) @@ -648,7 +732,7 @@ def update_coeff(X, y, coef_, alpha_, keep_lambda, sigma_): else self._update_sigma_woodbury ) # Iterative procedure of ARDRegression - for iter_ in range(self.n_iter): + for iter_ in range(max_iter): sigma_ = update_sigma(X, alpha_, lambda_, keep_lambda) coef_ = update_coeff(X, y, coef_, alpha_, keep_lambda, sigma_) @@ -688,6 +772,8 @@ def update_coeff(X, y, coef_, alpha_, keep_lambda, sigma_): if not keep_lambda.any(): break + self.n_iter_ = iter_ + 1 + if keep_lambda.any(): # update sigma and mu using updated params from the last iteration sigma_ = update_sigma(X, alpha_, lambda_, keep_lambda) diff --git a/sklearn/linear_model/tests/test_bayes.py b/sklearn/linear_model/tests/test_bayes.py index 5bb6ae210c5cf..b33e656335e1a 100644 --- a/sklearn/linear_model/tests/test_bayes.py +++ b/sklearn/linear_model/tests/test_bayes.py @@ -73,7 +73,7 @@ def test_bayesian_ridge_score_values(): alpha_2=alpha_2, lambda_1=lambda_1, lambda_2=lambda_2, - n_iter=1, + max_iter=1, fit_intercept=False, compute_score=True, ) @@ -174,7 +174,7 @@ def test_update_of_sigma_in_ard(): # of the ARDRegression algorithm. See issue #10128. X = np.array([[1, 0], [0, 0]]) y = np.array([0, 0]) - clf = ARDRegression(n_iter=1) + clf = ARDRegression(max_iter=1) clf.fit(X, y) # With the inputs above, ARDRegression prunes both of the two coefficients # in the first iteration. Hence, the expected shape of `sigma_` is (0, 0). @@ -292,3 +292,33 @@ def test_dtype_correctness(Estimator): coef_32 = model.fit(X.astype(np.float32), y).coef_ coef_64 = model.fit(X.astype(np.float64), y).coef_ np.testing.assert_allclose(coef_32, coef_64, rtol=1e-4) + + +# TODO(1.5) remove +@pytest.mark.parametrize("Estimator", [BayesianRidge, ARDRegression]) +def test_bayesian_ridge_ard_n_iter_deprecated(Estimator): + """Check the deprecation warning of `n_iter`.""" + depr_msg = ( + "'n_iter' was renamed to 'max_iter' in version 1.3 and will be removed in 1.5" + ) + X, y = diabetes.data, diabetes.target + model = Estimator(n_iter=5) + + with pytest.warns(FutureWarning, match=depr_msg): + model.fit(X, y) + + +# TODO(1.5) remove +@pytest.mark.parametrize("Estimator", [BayesianRidge, ARDRegression]) +def test_bayesian_ridge_ard_max_iter_and_n_iter_both_set(Estimator): + """Check that a ValueError is raised when both `max_iter` and `n_iter` are set.""" + err_msg = ( + "Both `n_iter` and `max_iter` attributes were set. Attribute" + " `n_iter` was deprecated in version 1.3 and will be removed in" + " 1.5. To avoid this error, only set the `max_iter` attribute." + ) + X, y = diabetes.data, diabetes.target + model = Estimator(n_iter=5, max_iter=5) + + with pytest.raises(ValueError, match=err_msg): + model.fit(X, y) From c98a18533095aad752c05b30f0414b07ffb34d0d Mon Sep 17 00:00:00 2001 From: "Thomas J. Fan" Date: Sun, 2 Apr 2023 09:04:39 -0400 Subject: [PATCH 137/230] CLN Make _NumPyAPIWrapper naming consistent to _ArrayAPIWrapper (#26039) --- sklearn/utils/_array_api.py | 10 +++++----- sklearn/utils/tests/test_array_api.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sklearn/utils/_array_api.py b/sklearn/utils/_array_api.py index fff8e1ee33a49..2afa6aba5d715 100644 --- a/sklearn/utils/_array_api.py +++ b/sklearn/utils/_array_api.py @@ -49,7 +49,7 @@ def take(self, X, indices, *, axis): return self._namespace.stack(selected, axis=axis) -class _NumPyApiWrapper: +class _NumPyAPIWrapper: """Array API compat wrapper for any numpy version NumPy < 1.22 does not expose the numpy.array_api namespace. This @@ -98,7 +98,7 @@ def get_namespace(*arrays): See: https://numpy.org/neps/nep-0047-array-api-standard.html If `arrays` are regular numpy arrays, an instance of the - `_NumPyApiWrapper` compatibility wrapper is returned instead. + `_NumPyAPIWrapper` compatibility wrapper is returned instead. Namespace support is not enabled by default. To enabled it call: @@ -110,7 +110,7 @@ def get_namespace(*arrays): with sklearn.config_context(array_api_dispatch=True): # your code here - Otherwise an instance of the `_NumPyApiWrapper` + Otherwise an instance of the `_NumPyAPIWrapper` compatibility wrapper is always returned irrespective of the fact that arrays implement the `__array_namespace__` protocol or not. @@ -133,7 +133,7 @@ def get_namespace(*arrays): # Returns a tuple: (array_namespace, is_array_api) if not get_config()["array_api_dispatch"]: - return _NumPyApiWrapper(), False + return _NumPyAPIWrapper(), False namespaces = { x.__array_namespace__() if hasattr(x, "__array_namespace__") else None @@ -152,7 +152,7 @@ def get_namespace(*arrays): (xp,) = namespaces if xp is None: # Use numpy as default - return _NumPyApiWrapper(), False + return _NumPyAPIWrapper(), False return _ArrayAPIWrapper(xp), True diff --git a/sklearn/utils/tests/test_array_api.py b/sklearn/utils/tests/test_array_api.py index 7318382ae9d66..9a88153a25615 100644 --- a/sklearn/utils/tests/test_array_api.py +++ b/sklearn/utils/tests/test_array_api.py @@ -4,7 +4,7 @@ from sklearn.base import BaseEstimator from sklearn.utils._array_api import get_namespace -from sklearn.utils._array_api import _NumPyApiWrapper +from sklearn.utils._array_api import _NumPyAPIWrapper from sklearn.utils._array_api import _ArrayAPIWrapper from sklearn.utils._array_api import _asarray_with_order from sklearn.utils._array_api import _convert_to_numpy @@ -27,7 +27,7 @@ def test_get_namespace_ndarray(): with config_context(array_api_dispatch=array_api_dispatch): xp_out, is_array_api = get_namespace(X_np) assert not is_array_api - assert isinstance(xp_out, _NumPyApiWrapper) + assert isinstance(xp_out, _NumPyAPIWrapper) def test_get_namespace_array_api(): From a5e6470043755522a861dc1ecb68a73d5d117b4a Mon Sep 17 00:00:00 2001 From: Olivier Grisel Date: Sun, 2 Apr 2023 16:58:26 +0200 Subject: [PATCH 138/230] CI disable coverage on Windows to keep CI times reasonable (#26052) --- azure-pipelines.yml | 7 ++++++- build_tools/azure/combine_coverage_reports.sh | 3 ++- build_tools/azure/upload_codecov.sh | 13 ++++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index af9044665a912..639cc85d2b989 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -277,6 +277,11 @@ jobs: DISTRIB: 'conda' LOCK_FILE: ./build_tools/azure/py38_conda_forge_mkl_win-64_conda.lock CHECK_WARNINGS: 'true' - COVERAGE: 'true' + # The Azure Windows runner is typically much slower than other CI + # runners due to the lack of compiler cache. Running the tests with + # coverage enabled make them run extra slower. Since very few parts of + # code should have windows-specific code branches, it should be enable + # to restrict the code coverage collection to the non-windows runners. + COVERAGE: 'false' SKLEARN_ENABLE_DEBUG_CYTHON_DIRECTIVES: '1' SKLEARN_TESTS_GLOBAL_RANDOM_SEED: '7' # non-default seed diff --git a/build_tools/azure/combine_coverage_reports.sh b/build_tools/azure/combine_coverage_reports.sh index e1f28c8f0e24a..c3b90fdd4fcdb 100755 --- a/build_tools/azure/combine_coverage_reports.sh +++ b/build_tools/azure/combine_coverage_reports.sh @@ -11,7 +11,8 @@ activate_environment # such as pytest-xdist and joblib/loky: pushd $TEST_DIR coverage combine --append +coverage xml popd # Copy the combined coverage file to the root of the repository: -cp $TEST_DIR/.coverage $BUILD_REPOSITORY_LOCALPATH +cp $TEST_DIR/coverage.xml $BUILD_REPOSITORY_LOCALPATH diff --git a/build_tools/azure/upload_codecov.sh b/build_tools/azure/upload_codecov.sh index 622d2e7fedeff..f4ef9d3fe4c1f 100755 --- a/build_tools/azure/upload_codecov.sh +++ b/build_tools/azure/upload_codecov.sh @@ -24,26 +24,29 @@ if [[ ! -d "$BUILD_REPOSITORY_LOCALPATH/.git" ]]; then echo "Could not find the git checkout at $BUILD_REPOSITORY_LOCALPATH" exit 1 fi + # Check that the combined coverage file exists at the expected location: -if [[ ! -f "$BUILD_REPOSITORY_LOCALPATH/.coverage" ]]; then - echo "Could not find the combined coverage file at $BUILD_REPOSITORY_LOCALPATH/.coverage" +export COVERAGE_XML="$BUILD_REPOSITORY_LOCALPATH/coverage.xml" +if [[ ! -f "$COVERAGE_XML" ]]; then + echo "Could not find the combined coverage file at $COVERAGE_XML" exit 1 fi + if [[ $OSTYPE == *"linux"* ]]; then curl -Os "$CODECOV_BASE_URL/linux/codecov" SHA256SUM="32cb14b5f3aaacd67f4c1ff55d82f037d3cd10c8e7b69c051f27391d2e66e15c codecov" echo "$SHA256SUM" | shasum -a256 -c chmod +x codecov - ./codecov -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f .coverage -Z + ./codecov -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f coverage.xml -Z elif [[ $OSTYPE == *"darwin"* ]]; then curl -Os "$CODECOV_BASE_URL/macos/codecov" SHA256SUM="4ab0f06f06e9c4d25464f155b0aff36bfc1e8dbcdb19bfffd586beed1269f3af codecov" echo "$SHA256SUM" | shasum -a256 -c chmod +x codecov - ./codecov -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f .coverage -Z + ./codecov -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f coverage.xml -Z else curl -Os "$CODECOV_BASE_URL/windows/codecov.exe" SHA256SUM="e0cda212aeaebe695509ce8fa2d608760ff70bc932003f544f1ad368ac5450a8 codecov.exe" echo "$SHA256SUM" | sha256sum -c - ./codecov.exe -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f .coverage -Z + ./codecov.exe -t ${CODECOV_TOKEN} -R $BUILD_REPOSITORY_LOCALPATH -f coverage.xml -Z fi From 03b4f9b145c4a7ef86cd748de7d0be3bc77b975b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= Date: Mon, 3 Apr 2023 11:04:13 +0200 Subject: [PATCH 139/230] DOC Use Scientific Python Plausible instance for analytics (#25547) --- doc/conf.py | 3 ++- doc/themes/scikit-learn-modern/javascript.html | 7 ++++++- doc/themes/scikit-learn-modern/theme.conf | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 52b084b331c8c..a326047cbec9f 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -171,7 +171,8 @@ # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - "google_analytics": True, + "legacy_google_analytics": True, + "analytics": True, "mathjax_path": mathjax_path, "link_to_live_contributing_page": not parsed_version.is_devrelease, } diff --git a/doc/themes/scikit-learn-modern/javascript.html b/doc/themes/scikit-learn-modern/javascript.html index fc8a3c815f677..635dfbd779b2a 100644 --- a/doc/themes/scikit-learn-modern/javascript.html +++ b/doc/themes/scikit-learn-modern/javascript.html @@ -1,4 +1,4 @@ -{% if theme_google_analytics|tobool %} +{% if theme_legacy_google_analytics|tobool %} {% endif %} +{% if theme_analytics|tobool %} + +{% endif %} +