239 lines
7.6 KiB
Python
239 lines
7.6 KiB
Python
|
import numpy as np
|
||
|
import pytest
|
||
|
|
||
|
from pandas.core.dtypes.common import is_integer
|
||
|
|
||
|
import pandas as pd
|
||
|
from pandas import (
|
||
|
Index,
|
||
|
Series,
|
||
|
)
|
||
|
import pandas._testing as tm
|
||
|
from pandas.core.indexes.datetimes import Timestamp
|
||
|
|
||
|
|
||
|
class TestSeriesQuantile:
|
||
|
def test_quantile(self, datetime_series):
|
||
|
q = datetime_series.quantile(0.1)
|
||
|
assert q == np.percentile(datetime_series.dropna(), 10)
|
||
|
|
||
|
q = datetime_series.quantile(0.9)
|
||
|
assert q == np.percentile(datetime_series.dropna(), 90)
|
||
|
|
||
|
# object dtype
|
||
|
q = Series(datetime_series, dtype=object).quantile(0.9)
|
||
|
assert q == np.percentile(datetime_series.dropna(), 90)
|
||
|
|
||
|
# datetime64[ns] dtype
|
||
|
dts = datetime_series.index.to_series()
|
||
|
q = dts.quantile(0.2)
|
||
|
assert q == Timestamp("2000-01-10 19:12:00")
|
||
|
|
||
|
# timedelta64[ns] dtype
|
||
|
tds = dts.diff()
|
||
|
q = tds.quantile(0.25)
|
||
|
assert q == pd.to_timedelta("24:00:00")
|
||
|
|
||
|
# GH7661
|
||
|
result = Series([np.timedelta64("NaT")]).sum()
|
||
|
assert result == pd.Timedelta(0)
|
||
|
|
||
|
msg = "percentiles should all be in the interval \\[0, 1\\]"
|
||
|
for invalid in [-1, 2, [0.5, -1], [0.5, 2]]:
|
||
|
with pytest.raises(ValueError, match=msg):
|
||
|
datetime_series.quantile(invalid)
|
||
|
|
||
|
def test_quantile_multi(self, datetime_series):
|
||
|
qs = [0.1, 0.9]
|
||
|
result = datetime_series.quantile(qs)
|
||
|
expected = Series(
|
||
|
[
|
||
|
np.percentile(datetime_series.dropna(), 10),
|
||
|
np.percentile(datetime_series.dropna(), 90),
|
||
|
],
|
||
|
index=qs,
|
||
|
name=datetime_series.name,
|
||
|
)
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
dts = datetime_series.index.to_series()
|
||
|
dts.name = "xxx"
|
||
|
result = dts.quantile((0.2, 0.2))
|
||
|
expected = Series(
|
||
|
[Timestamp("2000-01-10 19:12:00"), Timestamp("2000-01-10 19:12:00")],
|
||
|
index=[0.2, 0.2],
|
||
|
name="xxx",
|
||
|
)
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
result = datetime_series.quantile([])
|
||
|
expected = Series(
|
||
|
[], name=datetime_series.name, index=Index([], dtype=float), dtype="float64"
|
||
|
)
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
def test_quantile_interpolation(self, datetime_series):
|
||
|
# see gh-10174
|
||
|
|
||
|
# interpolation = linear (default case)
|
||
|
q = datetime_series.quantile(0.1, interpolation="linear")
|
||
|
assert q == np.percentile(datetime_series.dropna(), 10)
|
||
|
q1 = datetime_series.quantile(0.1)
|
||
|
assert q1 == np.percentile(datetime_series.dropna(), 10)
|
||
|
|
||
|
# test with and without interpolation keyword
|
||
|
assert q == q1
|
||
|
|
||
|
def test_quantile_interpolation_dtype(self):
|
||
|
# GH #10174
|
||
|
|
||
|
# interpolation = linear (default case)
|
||
|
q = Series([1, 3, 4]).quantile(0.5, interpolation="lower")
|
||
|
assert q == np.percentile(np.array([1, 3, 4]), 50)
|
||
|
assert is_integer(q)
|
||
|
|
||
|
q = Series([1, 3, 4]).quantile(0.5, interpolation="higher")
|
||
|
assert q == np.percentile(np.array([1, 3, 4]), 50)
|
||
|
assert is_integer(q)
|
||
|
|
||
|
def test_quantile_nan(self):
|
||
|
# GH 13098
|
||
|
s = Series([1, 2, 3, 4, np.nan])
|
||
|
result = s.quantile(0.5)
|
||
|
expected = 2.5
|
||
|
assert result == expected
|
||
|
|
||
|
# all nan/empty
|
||
|
s1 = Series([], dtype=object)
|
||
|
cases = [s1, Series([np.nan, np.nan])]
|
||
|
|
||
|
for s in cases:
|
||
|
res = s.quantile(0.5)
|
||
|
assert np.isnan(res)
|
||
|
|
||
|
res = s.quantile([0.5])
|
||
|
tm.assert_series_equal(res, Series([np.nan], index=[0.5]))
|
||
|
|
||
|
res = s.quantile([0.2, 0.3])
|
||
|
tm.assert_series_equal(res, Series([np.nan, np.nan], index=[0.2, 0.3]))
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"case",
|
||
|
[
|
||
|
[
|
||
|
Timestamp("2011-01-01"),
|
||
|
Timestamp("2011-01-02"),
|
||
|
Timestamp("2011-01-03"),
|
||
|
],
|
||
|
[
|
||
|
Timestamp("2011-01-01", tz="US/Eastern"),
|
||
|
Timestamp("2011-01-02", tz="US/Eastern"),
|
||
|
Timestamp("2011-01-03", tz="US/Eastern"),
|
||
|
],
|
||
|
[pd.Timedelta("1 days"), pd.Timedelta("2 days"), pd.Timedelta("3 days")],
|
||
|
# NaT
|
||
|
[
|
||
|
Timestamp("2011-01-01"),
|
||
|
Timestamp("2011-01-02"),
|
||
|
Timestamp("2011-01-03"),
|
||
|
pd.NaT,
|
||
|
],
|
||
|
[
|
||
|
Timestamp("2011-01-01", tz="US/Eastern"),
|
||
|
Timestamp("2011-01-02", tz="US/Eastern"),
|
||
|
Timestamp("2011-01-03", tz="US/Eastern"),
|
||
|
pd.NaT,
|
||
|
],
|
||
|
[
|
||
|
pd.Timedelta("1 days"),
|
||
|
pd.Timedelta("2 days"),
|
||
|
pd.Timedelta("3 days"),
|
||
|
pd.NaT,
|
||
|
],
|
||
|
],
|
||
|
)
|
||
|
def test_quantile_box(self, case):
|
||
|
s = Series(case, name="XXX")
|
||
|
res = s.quantile(0.5)
|
||
|
assert res == case[1]
|
||
|
|
||
|
res = s.quantile([0.5])
|
||
|
exp = Series([case[1]], index=[0.5], name="XXX")
|
||
|
tm.assert_series_equal(res, exp)
|
||
|
|
||
|
def test_datetime_timedelta_quantiles(self):
|
||
|
# covers #9694
|
||
|
assert pd.isna(Series([], dtype="M8[ns]").quantile(0.5))
|
||
|
assert pd.isna(Series([], dtype="m8[ns]").quantile(0.5))
|
||
|
|
||
|
def test_quantile_nat(self):
|
||
|
res = Series([pd.NaT, pd.NaT]).quantile(0.5)
|
||
|
assert res is pd.NaT
|
||
|
|
||
|
res = Series([pd.NaT, pd.NaT]).quantile([0.5])
|
||
|
tm.assert_series_equal(res, Series([pd.NaT], index=[0.5]))
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"values, dtype",
|
||
|
[([0, 0, 0, 1, 2, 3], "Sparse[int]"), ([0.0, None, 1.0, 2.0], "Sparse[float]")],
|
||
|
)
|
||
|
def test_quantile_sparse(self, values, dtype):
|
||
|
ser = Series(values, dtype=dtype)
|
||
|
result = ser.quantile([0.5])
|
||
|
expected = Series(np.asarray(ser)).quantile([0.5]).astype("Sparse[float]")
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
def test_quantile_empty(self):
|
||
|
# floats
|
||
|
s = Series([], dtype="float64")
|
||
|
|
||
|
res = s.quantile(0.5)
|
||
|
assert np.isnan(res)
|
||
|
|
||
|
res = s.quantile([0.5])
|
||
|
exp = Series([np.nan], index=[0.5])
|
||
|
tm.assert_series_equal(res, exp)
|
||
|
|
||
|
# int
|
||
|
s = Series([], dtype="int64")
|
||
|
|
||
|
res = s.quantile(0.5)
|
||
|
assert np.isnan(res)
|
||
|
|
||
|
res = s.quantile([0.5])
|
||
|
exp = Series([np.nan], index=[0.5])
|
||
|
tm.assert_series_equal(res, exp)
|
||
|
|
||
|
# datetime
|
||
|
s = Series([], dtype="datetime64[ns]")
|
||
|
|
||
|
res = s.quantile(0.5)
|
||
|
assert res is pd.NaT
|
||
|
|
||
|
res = s.quantile([0.5])
|
||
|
exp = Series([pd.NaT], index=[0.5])
|
||
|
tm.assert_series_equal(res, exp)
|
||
|
|
||
|
@pytest.mark.parametrize("dtype", [int, float, "Int64"])
|
||
|
def test_quantile_dtypes(self, dtype):
|
||
|
result = Series([1, 2, 3], dtype=dtype).quantile(np.arange(0, 1, 0.25))
|
||
|
expected = Series(np.arange(1, 3, 0.5), index=np.arange(0, 1, 0.25))
|
||
|
if dtype == "Int64":
|
||
|
expected = expected.astype("Float64")
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
def test_quantile_all_na(self, any_int_ea_dtype):
|
||
|
# GH#50681
|
||
|
ser = Series([pd.NA, pd.NA], dtype=any_int_ea_dtype)
|
||
|
with tm.assert_produces_warning(None):
|
||
|
result = ser.quantile([0.1, 0.5])
|
||
|
expected = Series([pd.NA, pd.NA], dtype=any_int_ea_dtype, index=[0.1, 0.5])
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
def test_quantile_dtype_size(self, any_int_ea_dtype):
|
||
|
# GH#50681
|
||
|
ser = Series([pd.NA, pd.NA, 1], dtype=any_int_ea_dtype)
|
||
|
result = ser.quantile([0.1, 0.5])
|
||
|
expected = Series([1, 1], dtype=any_int_ea_dtype, index=[0.1, 0.5])
|
||
|
tm.assert_series_equal(result, expected)
|