diff --git a/doc/modules/array_api.rst b/doc/modules/array_api.rst index 17110b70bb239..26359f963963d 100644 --- a/doc/modules/array_api.rst +++ b/doc/modules/array_api.rst @@ -119,6 +119,7 @@ Metrics - :func:`sklearn.metrics.mean_gamma_deviance` - :func:`sklearn.metrics.mean_squared_error` - :func:`sklearn.metrics.mean_tweedie_deviance` +- :func:`sklearn.metrics.pairwise.additive_chi2_kernel` - :func:`sklearn.metrics.pairwise.cosine_similarity` - :func:`sklearn.metrics.pairwise.paired_cosine_distances` - :func:`sklearn.metrics.r2_score` diff --git a/doc/whats_new/v1.6.rst b/doc/whats_new/v1.6.rst index 2e70cbd48a3dd..7f96f169ad638 100644 --- a/doc/whats_new/v1.6.rst +++ b/doc/whats_new/v1.6.rst @@ -38,7 +38,8 @@ See :ref:`array_api` for more details. - :func:`sklearn.metrics.mean_gamma_deviance` :pr:`29239` by :usser:`Emily Chen `; - :func:`sklearn.metrics.mean_squared_error` :pr:`29142` by :user:`Yaroslav Korobko `; - :func:`sklearn.metrics.mean_tweedie_deviance` :pr:`28106` by :user:`Thomas Li `; -- :func:`sklearn.metrics.pairwise.cosine_similarity` :pr:`29014` by :user:`Edoardo Abati `. +- :func:`sklearn.metrics.pairwise.additive_chi2_kernel` :pr:`29144` by :user:`Yaroslav Korobko `; +- :func:`sklearn.metrics.pairwise.cosine_similarity` :pr:`29014` by :user:`Edoardo Abati `; - :func:`sklearn.metrics.pairwise.paired_cosine_distances` :pr:`29112` by :user:`Edoardo Abati `. **Classes:** diff --git a/sklearn/metrics/pairwise.py b/sklearn/metrics/pairwise.py index fe0498cfbde0a..b0e4b6f2a9738 100644 --- a/sklearn/metrics/pairwise.py +++ b/sklearn/metrics/pairwise.py @@ -1718,7 +1718,7 @@ def additive_chi2_kernel(X, Y=None): Returns ------- - kernel : ndarray of shape (n_samples_X, n_samples_Y) + kernel : array-like of shape (n_samples_X, n_samples_Y) The kernel matrix. See Also @@ -1750,15 +1750,26 @@ def additive_chi2_kernel(X, Y=None): array([[-1., -2.], [-2., -1.]]) """ + xp, _ = get_namespace(X, Y) X, Y = check_pairwise_arrays(X, Y, accept_sparse=False) - if (X < 0).any(): + if xp.any(X < 0): raise ValueError("X contains negative values.") - if Y is not X and (Y < 0).any(): + if Y is not X and xp.any(Y < 0): raise ValueError("Y contains negative values.") - result = np.zeros((X.shape[0], Y.shape[0]), dtype=X.dtype) - _chi2_kernel_fast(X, Y, result) - return result + if _is_numpy_namespace(xp): + result = np.zeros((X.shape[0], Y.shape[0]), dtype=X.dtype) + _chi2_kernel_fast(X, Y, result) + return result + else: + dtype = _find_matching_floating_dtype(X, Y, xp=xp) + xb = X[:, None, :] + yb = Y[None, :, :] + nom = -((xb - yb) ** 2) + denom = xb + yb + nom = xp.where(denom == 0, xp.asarray(0, dtype=dtype), nom) + denom = xp.where(denom == 0, xp.asarray(1, dtype=dtype), denom) + return xp.sum(nom / denom, axis=2) @validate_params( diff --git a/sklearn/metrics/tests/test_common.py b/sklearn/metrics/tests/test_common.py index 05c6cca7b14e2..51ecc82e2880c 100644 --- a/sklearn/metrics/tests/test_common.py +++ b/sklearn/metrics/tests/test_common.py @@ -51,7 +51,11 @@ zero_one_loss, ) from sklearn.metrics._base import _average_binary_score -from sklearn.metrics.pairwise import cosine_similarity, paired_cosine_distances +from sklearn.metrics.pairwise import ( + additive_chi2_kernel, + cosine_similarity, + paired_cosine_distances, +) from sklearn.preprocessing import LabelBinarizer from sklearn.utils import shuffle from sklearn.utils._array_api import ( @@ -1955,6 +1959,7 @@ def check_array_api_metric_pairwise(metric, array_namespace, device, dtype_name) check_array_api_regression_metric, ], paired_cosine_distances: [check_array_api_metric_pairwise], + additive_chi2_kernel: [check_array_api_metric_pairwise], mean_gamma_deviance: [check_array_api_regression_metric], max_error: [check_array_api_regression_metric], }