Make `zero_division` parameter consistent in the different metric

This is an issue to report the step to actually take over the work of @marctorsoc in https://github.com/scikit-learn/scikit-learn/pull/23183 and split the PR into smaller one to facilitate the review process.

The intend is to make the `zero_division` parameter consistent across different metrics in scikit-learn. In this regards, we have the following TODO list:

- [x] Introduce the `zero_division` parameter to the `accuracy_score` function when `y_true` and `y_pred` are empty.
    - https://github.com/scikit-learn/scikit-learn/pull/29213
- [x] Introduce the `zero_division` parameter to the `class_likelihood_ratios` and remove `raise_warning`.
    - https://github.com/scikit-learn/scikit-learn/pull/31331
- [x] Introduce the `zero_division` parameter to the `cohen_kappa_score` function
  - https://github.com/scikit-learn/scikit-learn/pull/29210
- [x] Introduce the `zero_division` parameter to the `matthew_corr_coeff` function
  - #23183
  - #28509
- [ ] <del>Open a PR to make sure the empty input lead to `np.nan` in `classification_report` function.</del> `classification_report` should raise an error instead: see https://github.com/scikit-learn/scikit-learn/issues/29048#issuecomment-2857931743

All those items have been addressed in #23183 and can be extracted in individual PRs. The changelog presenting the changes should acknowledge @marctorsoc.

In addition, we should investigate #27047 and check if we should add the `zero_division` parameter to the `precision_recall_curve` and `roc_curve` as well. This might add two additional items to the list above.

COMMENT:
After a discussion that happened on https://github.com/scikit-learn/scikit-learn/pull/28038#discussion_r1830576013, with @glemaitre and @ogrisel we had a call, discussing the issues. Here's a summary.

There are two groups of functions accepting `zero_division` argument at the time of writing this (https://github.com/scikit-learn/scikit-learn/tree/8f620fd7a39d1bf1292b09192575d25cddc7888b).

In the first group, there is one place where a division by zero can happen, and the result is replaced by the input to the `zero_division` argument, and the docstring for them looks like this:

```
    zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn"
        Sets the value to return when there is a zero division,
        e.g. when `y_true` and `y_pred` are empty.
        If set to "warn", returns 0.0 input, but a warning is also raised.

        versionadded:: 1.6
```

Note that `classification_report` also has the above docstring, but it's wrong and it indeed belongs to the second group, and calls a function which falls under the second group.

The second group are functions where there are multiple places in the computation where a zero division can happen, and then an array is created and then the mean of the members of that array is calculated. In this case, `zero_division` sets the value of the computation for where the division by zero happens individually, and then that array is passed to `nanmean`, which then ignores `nan` values. Meaning `zero_division=np.nan` in effect makes those values to be ignored. This brings a few issues:
- Ignoring them might not be a desired action, and might be misleading, but sometimes users might want it
- `score(..., zero_division=np.nan)` wouldn't be returning `np.nan`, and it would simply be ignoring those `nan` values in mean calculation, which isn't intuitive by looking at the user code
- There is no way for the user to get a `np.nan` when there's a division by zero, which is the case for metrics in the first group.
- There are no warnings raised in the case of user passing `zero_division=np.nan` and this might not be ideal.
- The control of whether or not a warning is raised and what to replace the value with, are both in a single argument, but they're different things.

So in conclusion, considering how painful it would be to change the semantics of already released `zero_division`, we think this is a better path forward:

Introduce a `replace_undefined_by` argument, deprecating `zero_division` away. The new argument takes the following values:
- `np.nan`: it makes the function to return `np.nan` if there's ANY zero division happening
- 0, 1, or a range of real values if that's meaningful for the metric in question: replace the result of division by zero with this value. This means returning this value in the first group of metrics, and putting this value in the pool of calculating the mean in the second group of metrics
- `ignore`: this is only available for metrics which calculate mean, and isn't a valid input when the metric doesn't calculate the aggregate. This will ignore the members of the array which were the result of a division by zero.

On top of that, the metric would _always_ warn when a division by zero happens, and the user can silence the warning by setting a filter. We can add a parameter to control the raising of the warning at a later stage if there's need for it.

We also noticed that the warning messages could be a lot more informative, and in some cases we raise a wrong warning when there shouldn't be a warning. The docstring should also mention concretely when a division by zero or an invalid metric can happen. So all these need to be checked and fixed.

cc @glemaitre @ogrisel

Labels: Enhancement