Repository: scikit-learn/scikit-learn
File: sklearn/utils/tests/test_stats.py (Python)

Code before:
def test_weighted_percentile_matches_numpy(
    global_random_seed, size, percentile_rank, average
):
    """Check `_weighted_percentile` with unit weights is correct.

    `average=True` results should be the same as `np.percentile`'s
    'averaged_inverted_cdf'.
    `average=False` results should be the same as `np.percentile`'s
    'inverted_cdf'.
    Note `np.percentile` is the same as `np.quantile` except `q` is in range [0, 100].

    We parametrize through different `percentile_rank` and `size` to
    ensure we get cases where `g=0` and `g>0` (see Hyndman and Fan 1996 for details).
    """
    rng = np.random.RandomState(global_random_seed)
    y = rng.randint(20, size=size)
    sw = np.ones_like(y)

    score = _weighted_percentile(y, sw, percentile_rank, average=average)

    if average:
        method = "averaged_inverted_cdf"
    else:
        method = "inverted_cdf"

    assert score == np.percentile(y, percentile_rank, method=method)


@pytest.mark.parametrize("percentile_rank", [50, 100])
def test_weighted_percentile_plus_one_clip_max(percentile_rank):
    """Check `j+1` index is clipped to max, when `average=True`.

    `percentile_plus_one_indices` can exceed max index when `percentile_indices`
    is already at max index.
    Note that when `g` (Hyndman and Fan) / `fraction_above` is greater than 0,
    `j+1` (Hyndman and Fan) / `percentile_plus_one_indices` is calculated but
    never used, so it does not matter what this value is.
    When percentile of percentile rank 100 falls exactly on the last value in the
    `weighted_cdf`, `g=0` and `percentile_indices` is at max index. In this case
    we set `percentile_plus_one_indices` to be max index as well, so the result is
    the average of 2x the max index (i.e. last value of `weighted_cdf`).
    """
    # Note for both `percentile_rank`s 50 and 100,`percentile_indices` is already at
    # max index
    y = np.array([[0, 0], [1, 1]])
    sw = np.array([[0.1, 0.1], [2, 2]])
    score = _weighted_percentile(y, sw, percentile_rank)
    for idx in range(2):
        assert score[idx] == approx(1.0)



Review comment (suggestion):
Since `score` might be a floating point value, I think we should ignore rounding errors:

```suggestion
    assert score == pytest.approx(np.percentile(y, percentile_rank, method=method))
```

Code after:

    `average=True` results should be the same as `np.percentile`'s
    'averaged_inverted_cdf'.
    `average=False` results should be the same as `np.percentile`'s
    'inverted_cdf'.
    Note `np.percentile` is the same as `np.quantile` except `q` is in range [0, 100].

    We parametrize through different `percentile_rank` and `size` to
    ensure we get cases where `g=0` and `g>0` (see Hyndman and Fan 1996 for details).
    """
    rng = np.random.RandomState(global_random_seed)
    y = rng.randint(20, size=size)
    sw = np.ones_like(y)

    score = _weighted_percentile(y, sw, percentile_rank, average=average)

    if average:
        method = "averaged_inverted_cdf"
    else:
        method = "inverted_cdf"

    assert approx(score) == np.percentile(y, percentile_rank, method=method)


@pytest.mark.parametrize("percentile_rank", [50, 100])
def test_weighted_percentile_plus_one_clip_max(percentile_rank):
    """Check `j+1` index is clipped to max, when `average=True`.

    `percentile_plus_one_indices` can exceed max index when `percentile_indices`
    is already at max index.
    Note that when `g` (Hyndman and Fan) / `fraction_above` is greater than 0,
    `j+1` (Hyndman and Fan) / `percentile_plus_one_indices` is calculated but
    never used, so it does not matter what this value is.
    When percentile of percentile rank 100 falls exactly on the last value in the
    `weighted_cdf`, `g=0` and `percentile_indices` is at max index. In this case
    we set `percentile_plus_one_indices` to be max index as well, so the result is
    the average of 2x the max index (i.e. last value of `weighted_cdf`).
    """
    # Note for both `percentile_rank`s 50 and 100,`percentile_indices` is already at
    # max index
    y = np.array([[0, 0], [1, 1]])
    sw = np.array([[0.1, 0.2], [2, 3]])
    score = _weighted_percentile(y, sw, percentile_rank, average=True)
    for idx in range(2):
        assert score[idx] == approx(1.0)


def test_weighted_percentile_equal():
    """Check `weighted_percentile` with unit weights and all 0 values in `array`."""
    y = np.zeros(102, dtype=np.float64)
    sw = np.ones(102, dtype=np.float64)