Repository: scikit-learn/scikit-learn
File: sklearn/metrics/_classification.py (Python)

Code before:
        confusion = confusion_matrix(y1, y2, labels=labels, sample_weight=sample_weight)
    except ValueError as e:
        if "At least one label specified must be in y_true" in str(e):
            msg = (
                "At least one label in `labels` must be present in `y1` (even though "
                "`cohen_kappa_score` is otherwise agnostic to the order of `y1` and "
                "`y2`)."
            )
            raise ValueError(msg) from e
        raise

    xp, _, device_ = get_namespace_and_device(y1, y2)
    n_classes = confusion.shape[0]
    # array_api_strict only supports floating point dtypes for __truediv__
    # which is used below to compute `expected` as well as `k`. Therefore
    # we use the maximum floating point dtype available for relevant arrays
    # to avoid running into this problem.
    max_float_dtype = _max_precision_float_dtype(xp, device=device_)
    confusion = xp.astype(confusion, max_float_dtype, copy=False)
    sum0 = xp.sum(confusion, axis=0)
    sum1 = xp.sum(confusion, axis=1)

    numerator = xp.linalg.outer(sum0, sum1)
    denominator = xp.sum(sum0)
    msg_zero_division = (
        "`y2` contains no labels that are presented in both `y1` and `labels`."
        "`cohen_kappa_score` is undefined and set to the value defined by "
        "the `replace_undefined_by` param, which defaults to `np.nan`."
    )
    if np.isclose(_convert_to_numpy(denominator, xp), 0):
        warnings.warn(msg_zero_division, UndefinedMetricWarning, stacklevel=2)
        return replace_undefined_by

    expected = numerator / denominator

    if weights is None:
        w_mat = xp.ones([n_classes, n_classes], dtype=max_float_dtype, device=device_)
        _fill_diagonal(w_mat, 0, xp=xp)
    else:  # "linear" or "quadratic"
        w_mat = xp.zeros([n_classes, n_classes], dtype=max_float_dtype, device=device_)
        w_mat += xp.arange(n_classes)
        if weights == "linear":
            w_mat = xp.abs(w_mat - w_mat.T)
        else:
            w_mat = (w_mat - w_mat.T) ** 2

    numerator = xp.sum(w_mat * confusion)
    denominator = xp.sum(w_mat * expected)
    msg_zero_division = (
        "`y1`, `y2` and `labels` have only one label in common. "
        "`cohen_kappa_score` is undefined and set to the value defined by the "

Review comment (suggestion):
```suggestion
        "`y2` contains no labels that are present in both `y1` and `labels`."
```

Code after:
        confusion = confusion_matrix(y1, y2, labels=labels, sample_weight=sample_weight)
    except ValueError as e:
        if "At least one label specified must be in y_true" in str(e):
            msg = (
                "At least one label in `labels` must be present in `y1` (even though "
                "`cohen_kappa_score` is otherwise agnostic to the order of `y1` and "
                "`y2`)."
            )
            raise ValueError(msg) from e
        raise

    xp, _, device_ = get_namespace_and_device(y1, y2)
    n_classes = confusion.shape[0]
    # array_api_strict only supports floating point dtypes for __truediv__
    # which is used below to compute `expected` as well as `k`. Therefore
    # we use the maximum floating point dtype available for relevant arrays
    # to avoid running into this problem.
    max_float_dtype = _max_precision_float_dtype(xp, device=device_)
    confusion = xp.astype(confusion, max_float_dtype, copy=False)
    sum0 = xp.sum(confusion, axis=0)
    sum1 = xp.sum(confusion, axis=1)

    numerator = xp.linalg.outer(sum0, sum1)
    denominator = xp.sum(sum0)
    msg_zero_division = (
        "`y2` contains no labels that are present in both `y1` and `labels`."
        "`cohen_kappa_score` is undefined and set to the value defined by "
        f"the `replace_undefined_by` param, which is set to {replace_undefined_by}."
    )
    # exact equality is safe here, since denominator is a sum of positive terms:
    if denominator == 0:
        warnings.warn(msg_zero_division, UndefinedMetricWarning, stacklevel=2)
        return replace_undefined_by

    expected = numerator / denominator

    if weights is None:
        w_mat = xp.ones([n_classes, n_classes], dtype=max_float_dtype, device=device_)
        _fill_diagonal(w_mat, 0, xp=xp)
    else:  # "linear" or "quadratic"
        w_mat = xp.zeros([n_classes, n_classes], dtype=max_float_dtype, device=device_)
        w_mat += xp.arange(n_classes)
        if weights == "linear":
            w_mat = xp.abs(w_mat - w_mat.T)
        else:
            w_mat = (w_mat - w_mat.T) ** 2

    numerator = xp.sum(w_mat * confusion)
    denominator = xp.sum(w_mat * expected)
    msg_zero_division = (
        "`y1`, `y2` and `labels` have only one label in common. "