diff --git a/python/cuml/cuml/internals/array.py b/python/cuml/cuml/internals/array.py index 4027b31d82..b111bce537 100644 --- a/python/cuml/cuml/internals/array.py +++ b/python/cuml/cuml/internals/array.py @@ -983,12 +983,12 @@ def from_input( if is_sparse(X): # We don't support coercing sparse arrays to dense via this method. - # Raising a NotImplementedError here lets us nicely error - # for estimators that don't support sparse arrays without requiring - # an additional external check. Otherwise they'd get an opaque error - # for code below. - raise NotImplementedError( - "Sparse inputs are not currently supported for this method" + # Raising a TypeError here lets us nicely error for estimators that + # don't support sparse arrays without requiring an additional + # external check. Using TypeError with "sparse" in the message + # satisfies sklearn's check_estimator_sparse_tag check. + raise TypeError( + "A sparse matrix was passed, but dense data is required. " ) if convert_to_mem_type is not False: convert_to_mem_type = MemoryType.from_str(convert_to_mem_type) diff --git a/python/cuml/tests/test_exceptions.py b/python/cuml/tests/test_exceptions.py index fc8d520fca..c4d45cd392 100644 --- a/python/cuml/tests/test_exceptions.py +++ b/python/cuml/tests/test_exceptions.py @@ -1,5 +1,5 @@ # -# SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION. +# SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: Apache-2.0 # @@ -24,7 +24,7 @@ NearestNeighbors, ) -# Currently only certain estimators raise a NotImplementedError +# Estimators that raise TypeError when given sparse input (they don't support sparse) estimators = { "KMeans": lambda: KMeans(n_clusters=2, random_state=0), "DBSCAN": lambda: DBSCAN(eps=1.0), @@ -44,7 +44,7 @@ def test_sparse_not_implemented_exception(estimator_name): y_reg = np.array([0.0, 1.0]) estimator = estimators[estimator_name]() # Fit or fit_transform depending on the estimator type - with pytest.raises(NotImplementedError): + with pytest.raises(TypeError, match="sparse"): if isinstance( estimator, (KMeans, DBSCAN, TruncatedSVD, NearestNeighbors) ): diff --git a/python/cuml/tests/test_sklearn_compatibility.py b/python/cuml/tests/test_sklearn_compatibility.py index 97156680b7..e88b18f500 100644 --- a/python/cuml/tests/test_sklearn_compatibility.py +++ b/python/cuml/tests/test_sklearn_compatibility.py @@ -56,9 +56,6 @@ "check_complex_data": "KMeans does not handle complex data", "check_dtype_object": "KMeans does not handle object dtype", "check_estimators_nan_inf": "KMeans does not check for NaN and inf", - "check_estimator_sparse_tag": "KMeans does not support sparse data", - "check_estimator_sparse_array": "KMeans does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "KMeans does not handle sparse matrices gracefully", "check_transformer_data_not_an_array": "KMeans does not handle non-array data", "check_fit1d": "KMeans does not raise ValueError for 1D input", "check_fit2d_predict1d": "KMeans does not handle 1D prediction input gracefully", @@ -74,9 +71,6 @@ "check_dtype_object": "KernelRidge does not handle object dtype", "check_estimators_empty_data_messages": "KernelRidge does not handle empty data", "check_estimators_nan_inf": "KernelRidge does not check for NaN and inf", - "check_estimator_sparse_tag": "KernelRidge does not support sparse data", - "check_estimator_sparse_array": "KernelRidge does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "KernelRidge does not handle sparse matrices gracefully", "check_regressors_train": "KernelRidge does not handle list inputs", "check_regressors_train(readonly_memmap=True)": "KernelRidge does not handle readonly memmap", "check_regressors_train(readonly_memmap=True,X_dtype=float32)": "KernelRidge does not handle readonly memmap with float32", @@ -122,9 +116,6 @@ "check_dtype_object": "LinearRegression does not handle object dtype", "check_estimators_empty_data_messages": "LinearRegression does not handle empty data", "check_estimators_nan_inf": "LinearRegression does not check for NaN and inf", - "check_estimator_sparse_tag": "LinearRegression does not support sparse data", - "check_estimator_sparse_array": "LinearRegression does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "LinearRegression does not handle sparse matrices gracefully", "check_regressors_train": "LinearRegression does not handle list inputs", "check_regressors_train(readonly_memmap=True)": "LinearRegression does not handle readonly memmap", "check_regressors_train(readonly_memmap=True,X_dtype=float32)": "LinearRegression does not handle readonly memmap with float32", @@ -145,9 +136,6 @@ "check_complex_data": "Ridge does not handle complex data", "check_dtype_object": "Ridge does not handle object dtype", "check_estimators_nan_inf": "Ridge does not check for NaN and inf", - "check_estimator_sparse_tag": "Ridge does not support sparse data", - "check_estimator_sparse_array": "Ridge does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "Ridge does not handle sparse matrices gracefully", "check_regressors_train": "Ridge does not handle list inputs", "check_regressors_train(readonly_memmap=True)": "Ridge does not handle readonly memmap", "check_regressors_train(readonly_memmap=True,X_dtype=float32)": "Ridge does not handle readonly memmap with float32", @@ -167,9 +155,6 @@ "check_dtype_object": "RandomForestRegressor does not handle object dtype", "check_estimators_empty_data_messages": "RandomForestRegressor does not handle empty data", "check_estimators_nan_inf": "RandomForestRegressor does not check for NaN and inf", - "check_estimator_sparse_tag": "RandomForestRegressor does not support sparse data", - "check_estimator_sparse_array": "RandomForestRegressor does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "RandomForestRegressor does not handle sparse matrices gracefully", "check_regressors_train": "RandomForestRegressor does not handle list inputs", "check_regressors_train(readonly_memmap=True)": "RandomForestRegressor does not handle readonly memmap", "check_regressors_train(readonly_memmap=True,X_dtype=float32)": "RandomForestRegressor does not handle readonly memmap with float32", @@ -208,9 +193,6 @@ "check_dtype_object": "RandomForestClassifier does not handle object dtype", "check_estimators_empty_data_messages": "RandomForestClassifier does not handle empty data", "check_estimators_nan_inf": "RandomForestClassifier does not check for NaN and inf", - "check_estimator_sparse_tag": "RandomForestClassifier does not support sparse data", - "check_estimator_sparse_array": "RandomForestClassifier does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "RandomForestClassifier does not handle sparse matrices gracefully", "check_classifier_data_not_an_array": "RandomForestClassifier does not handle non-array data", "check_classifiers_train": "RandomForestClassifier does not handle list inputs", "check_classifiers_train(readonly_memmap=True)": "RandomForestClassifier does not handle readonly memmap", @@ -263,9 +245,6 @@ "check_complex_data": "LinearSVC does not handle complex data", "check_dtype_object": "LinearSVC does not handle object dtype", "check_estimators_nan_inf": "LinearSVC does not check for NaN and inf", - "check_estimator_sparse_tag": "LinearSVC does not support sparse data", - "check_estimator_sparse_array": "LinearSVC does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "LinearSVC does not handle sparse matrices gracefully", "check_estimators_pickle": "LinearSVC does not support pickling", "check_estimators_pickle(readonly_memmap=True)": "LinearSVC does not support pickling with readonly memmap", "check_classifier_data_not_an_array": "LinearSVC does not handle non-array data", @@ -293,9 +272,6 @@ "check_complex_data": "LinearSVR does not handle complex data", "check_dtype_object": "LinearSVR does not handle object dtype", "check_estimators_nan_inf": "LinearSVR does not check for NaN and inf", - "check_estimator_sparse_tag": "LinearSVR does not support sparse data", - "check_estimator_sparse_array": "LinearSVR does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "LinearSVR does not handle sparse matrices gracefully", "check_regressors_train": "LinearSVR does not handle list inputs", "check_regressors_train(readonly_memmap=True)": "LinearSVR does not handle readonly memmap", "check_regressors_train(readonly_memmap=True,X_dtype=float32)": "LinearSVR does not handle readonly memmap with float32", @@ -387,9 +363,6 @@ "check_dtype_object": "TruncatedSVD does not handle object dtype", "check_estimators_empty_data_messages": "TruncatedSVD does not handle empty data", "check_estimators_nan_inf": "TruncatedSVD does not check for NaN and inf", - "check_estimator_sparse_tag": "TruncatedSVD does not support sparse data", - "check_estimator_sparse_array": "TruncatedSVD does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "TruncatedSVD does not handle sparse matrices gracefully", "check_transformer_data_not_an_array": "TruncatedSVD does not handle non-array data", "check_fit2d_1sample": "TruncatedSVD does not handle single sample", "check_fit2d_1feature": "TruncatedSVD does not handle single feature", @@ -429,9 +402,6 @@ "check_complex_data": "Lasso does not handle complex data", "check_dtype_object": "Lasso does not handle object dtype", "check_estimators_nan_inf": "Lasso does not check for NaN and inf", - "check_estimator_sparse_tag": "Lasso does not support sparse data", - "check_estimator_sparse_array": "Lasso does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "Lasso does not handle sparse matrices gracefully", "check_regressors_train": "Lasso does not handle list inputs", "check_regressors_train(readonly_memmap=True)": "Lasso does not handle readonly memmap", "check_regressors_train(readonly_memmap=True,X_dtype=float32)": "Lasso does not handle readonly memmap with float32", @@ -452,9 +422,6 @@ "check_complex_data": "ElasticNet does not handle complex data", "check_dtype_object": "ElasticNet does not handle object dtype", "check_estimators_nan_inf": "ElasticNet does not check for NaN and inf", - "check_estimator_sparse_tag": "ElasticNet does not support sparse data", - "check_estimator_sparse_array": "ElasticNet does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "ElasticNet does not handle sparse matrices gracefully", "check_regressors_train": "ElasticNet does not handle list inputs", "check_regressors_train(readonly_memmap=True)": "ElasticNet does not handle readonly memmap", "check_regressors_train(readonly_memmap=True,X_dtype=float32)": "ElasticNet does not handle readonly memmap with float32", @@ -474,9 +441,6 @@ "check_complex_data": "KernelDensity does not handle complex data", "check_dtype_object": "KernelDensity does not handle object dtype", "check_estimators_nan_inf": "KernelDensity does not check for NaN and inf", - "check_estimator_sparse_tag": "KernelDensity does not support sparse data", - "check_estimator_sparse_array": "KernelDensity does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "KernelDensity does not handle sparse matrices gracefully", "check_fit1d": "KernelDensity does not raise ValueError for 1D input", }, LedoitWolf: { @@ -486,9 +450,6 @@ "check_dtype_object": "LedoitWolf does not handle object dtype", "check_estimators_empty_data_messages": "LedoitWolf does not handle empty data", "check_estimators_nan_inf": "LedoitWolf does not check for NaN and inf", - "check_estimator_sparse_tag": "LedoitWolf does not support sparse data", - "check_estimator_sparse_array": "LedoitWolf does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "LedoitWolf does not handle sparse matrices gracefully", }, DBSCAN: { "check_estimator_tags_renamed": "No support for modern tags infrastructure", @@ -499,9 +460,6 @@ "check_dtype_object": "DBSCAN does not handle object dtype", "check_estimators_empty_data_messages": "DBSCAN does not handle empty data", "check_estimators_nan_inf": "DBSCAN does not check for NaN and inf", - "check_estimator_sparse_tag": "DBSCAN does not support sparse data", - "check_estimator_sparse_array": "DBSCAN does not handle sparse arrays gracefully", - "check_estimator_sparse_matrix": "DBSCAN does not handle sparse matrices gracefully", "check_fit1d": "DBSCAN does not raise ValueError for 1D input", }, HDBSCAN: { @@ -512,7 +470,6 @@ "check_dtype_object": "HDBSCAN does not handle object dtype", "check_estimators_empty_data_messages": "HDBSCAN does not handle empty data", "check_estimators_nan_inf": "HDBSCAN does not check for NaN and inf", - "check_estimator_sparse_tag": "HDBSCAN does not support sparse data", "check_estimator_sparse_array": "HDBSCAN does not handle sparse arrays gracefully", "check_estimator_sparse_matrix": "HDBSCAN does not handle sparse matrices gracefully", "check_parameters_default_constructible": "HDBSCAN parameters are mutated on init", @@ -537,7 +494,6 @@ "check_complex_data": "AgglomerativeClustering does not handle complex data", "check_dtype_object": "AgglomerativeClustering does not handle object dtype", "check_estimators_nan_inf": "AgglomerativeClustering does not check for NaN and inf", - "check_estimator_sparse_tag": "AgglomerativeClustering does not support sparse data", "check_estimator_sparse_array": "AgglomerativeClustering does not handle sparse arrays gracefully", "check_estimator_sparse_matrix": "AgglomerativeClustering does not handle sparse matrices gracefully", "check_parameters_default_constructible": "AgglomerativeClustering parameters are mutated on init", @@ -556,8 +512,6 @@ "check_dtype_object": "GaussianNB does not handle object dtype", "check_estimators_empty_data_messages": "GaussianNB does not handle empty data", "check_estimators_nan_inf": "GaussianNB does not check for NaN and inf", - "check_estimator_sparse_tag": "GaussianNB does not support sparse data", - "check_estimator_sparse_array": "GaussianNB does not handle sparse arrays gracefully", "check_classifier_data_not_an_array": "GaussianNB does not handle non-array data", "check_classifiers_classes": "GaussianNB does not handle string data properly", "check_estimators_partial_fit_n_features": "GaussianNB does not check n_features consistency in partial_fit", @@ -586,7 +540,7 @@ "check_estimators_empty_data_messages": "GaussianRandomProjection does not handle empty data", "check_pipeline_consistency": "GaussianRandomProjection raises ValueError with small datasets", "check_estimators_nan_inf": "GaussianRandomProjection does not check for NaN and inf", - "check_estimator_sparse_tag": "GaussianRandomProjection does not support sparse data", + "check_estimator_sparse_tag": "GaussianRandomProjection raises ValueError with small datasets even though it supports sparse inputs", "check_estimator_sparse_array": "GaussianRandomProjection does not handle sparse arrays gracefully", "check_estimator_sparse_matrix": "GaussianRandomProjection does not handle sparse matrices gracefully", "check_estimators_pickle": "GaussianRandomProjection raises ValueError with small datasets", @@ -615,7 +569,7 @@ "check_estimators_empty_data_messages": "SparseRandomProjection does not handle empty data", "check_pipeline_consistency": "SparseRandomProjection raises ValueError with small datasets", "check_estimators_nan_inf": "SparseRandomProjection does not check for NaN and inf", - "check_estimator_sparse_tag": "SparseRandomProjection does not support sparse data", + "check_estimator_sparse_tag": "SparseRandomProjection raises ValueError with small datasets", "check_estimator_sparse_array": "SparseRandomProjection does not handle sparse arrays gracefully", "check_estimator_sparse_matrix": "SparseRandomProjection does not handle sparse matrices gracefully", "check_estimators_pickle": "SparseRandomProjection raises ValueError with small datasets", @@ -644,8 +598,6 @@ "check_dtype_object": "BernoulliNB does not handle object dtype", "check_estimators_empty_data_messages": "BernoulliNB does not provide proper error messages for empty data", "check_estimators_nan_inf": "BernoulliNB does not check for NaN and inf", - "check_estimator_sparse_tag": "BernoulliNB sparse data handling does not follow sklearn conventions", - "check_estimator_sparse_array": "BernoulliNB does not handle sparse arrays gracefully", "check_classifier_data_not_an_array": "BernoulliNB does not handle list inputs", "check_classifiers_classes": "BernoulliNB does not handle string labels properly", "check_estimators_partial_fit_n_features": "BernoulliNB does not check n_features consistency in partial_fit", @@ -677,8 +629,6 @@ "check_estimators_empty_data_messages": "ComplementNB does not provide proper error messages for empty data", "check_pipeline_consistency": "ComplementNB pipeline consistency issues", "check_estimators_nan_inf": "ComplementNB does not check for NaN and inf", - "check_estimator_sparse_tag": "ComplementNB sparse data handling does not follow sklearn conventions", - "check_estimator_sparse_array": "ComplementNB does not handle sparse arrays gracefully", "check_estimators_pickle": "ComplementNB pickling issues", "check_estimators_pickle(readonly_memmap=True)": "ComplementNB pickling with readonly memmap issues", "check_classifier_data_not_an_array": "ComplementNB does not handle list inputs", @@ -711,8 +661,6 @@ "check_dtype_object": "CategoricalNB does not handle object dtype", "check_estimators_empty_data_messages": "CategoricalNB does not provide proper error messages for empty data", "check_estimators_nan_inf": "CategoricalNB does not check for NaN and inf", - "check_estimator_sparse_tag": "CategoricalNB sparse data handling does not follow sklearn conventions", - "check_estimator_sparse_array": "CategoricalNB does not handle sparse arrays gracefully", "check_classifier_data_not_an_array": "CategoricalNB does not handle list inputs", "check_classifiers_classes": "CategoricalNB does not handle string labels properly", "check_estimators_partial_fit_n_features": "CategoricalNB does not check n_features consistency in partial_fit", @@ -739,8 +687,6 @@ "check_dtype_object": "MultinomialNB does not handle object dtype", "check_estimators_empty_data_messages": "MultinomialNB does not provide proper error messages for empty data", "check_estimators_nan_inf": "MultinomialNB does not check for NaN and inf", - "check_estimator_sparse_tag": "MultinomialNB sparse data handling does not follow sklearn conventions", - "check_estimator_sparse_array": "MultinomialNB does not handle sparse arrays gracefully", "check_classifier_data_not_an_array": "MultinomialNB does not handle non-array data", "check_classifiers_classes": "MultinomialNB does not handle string labels properly", "check_estimators_partial_fit_n_features": "MultinomialNB does not check n_features consistency in partial_fit",