ai-content-maker/.venv/Lib/site-packages/pandas/tests/window/test_api.py

490 lines
15 KiB
Python
Raw Permalink Normal View History

2024-05-03 04:18:51 +03:00
import numpy as np
import pytest
from pandas.errors import (
SpecificationError,
UnsupportedFunctionCall,
)
from pandas import (
DataFrame,
Index,
MultiIndex,
Period,
Series,
Timestamp,
concat,
date_range,
timedelta_range,
)
import pandas._testing as tm
def test_getitem(step):
frame = DataFrame(np.random.randn(5, 5))
r = frame.rolling(window=5, step=step)
tm.assert_index_equal(r._selected_obj.columns, frame[::step].columns)
r = frame.rolling(window=5, step=step)[1]
assert r._selected_obj.name == frame[::step].columns[1]
# technically this is allowed
r = frame.rolling(window=5, step=step)[1, 3]
tm.assert_index_equal(r._selected_obj.columns, frame[::step].columns[[1, 3]])
r = frame.rolling(window=5, step=step)[[1, 3]]
tm.assert_index_equal(r._selected_obj.columns, frame[::step].columns[[1, 3]])
def test_select_bad_cols():
df = DataFrame([[1, 2]], columns=["A", "B"])
g = df.rolling(window=5)
with pytest.raises(KeyError, match="Columns not found: 'C'"):
g[["C"]]
with pytest.raises(KeyError, match="^[^A]+$"):
# A should not be referenced as a bad column...
# will have to rethink regex if you change message!
g[["A", "C"]]
def test_attribute_access():
df = DataFrame([[1, 2]], columns=["A", "B"])
r = df.rolling(window=5)
tm.assert_series_equal(r.A.sum(), r["A"].sum())
msg = "'Rolling' object has no attribute 'F'"
with pytest.raises(AttributeError, match=msg):
r.F
def tests_skip_nuisance(step):
df = DataFrame({"A": range(5), "B": range(5, 10), "C": "foo"})
r = df.rolling(window=3, step=step)
result = r[["A", "B"]].sum()
expected = DataFrame(
{"A": [np.nan, np.nan, 3, 6, 9], "B": [np.nan, np.nan, 18, 21, 24]},
columns=list("AB"),
)[::step]
tm.assert_frame_equal(result, expected)
def test_skip_sum_object_raises(step):
df = DataFrame({"A": range(5), "B": range(5, 10), "C": "foo"})
r = df.rolling(window=3, step=step)
msg = r"nuisance columns.*Dropped columns were Index\(\['C'\], dtype='object'\)"
with tm.assert_produces_warning(FutureWarning, match=msg):
# GH#42738
result = r.sum()
expected = DataFrame(
{"A": [np.nan, np.nan, 3, 6, 9], "B": [np.nan, np.nan, 18, 21, 24]},
columns=list("AB"),
)[::step]
tm.assert_frame_equal(result, expected)
def test_agg(step):
df = DataFrame({"A": range(5), "B": range(0, 10, 2)})
r = df.rolling(window=3, step=step)
a_mean = r["A"].mean()
a_std = r["A"].std()
a_sum = r["A"].sum()
b_mean = r["B"].mean()
b_std = r["B"].std()
result = r.aggregate([np.mean, np.std])
expected = concat([a_mean, a_std, b_mean, b_std], axis=1)
expected.columns = MultiIndex.from_product([["A", "B"], ["mean", "std"]])
tm.assert_frame_equal(result, expected)
result = r.aggregate({"A": np.mean, "B": np.std})
expected = concat([a_mean, b_std], axis=1)
tm.assert_frame_equal(result, expected, check_like=True)
result = r.aggregate({"A": ["mean", "std"]})
expected = concat([a_mean, a_std], axis=1)
expected.columns = MultiIndex.from_tuples([("A", "mean"), ("A", "std")])
tm.assert_frame_equal(result, expected)
result = r["A"].aggregate(["mean", "sum"])
expected = concat([a_mean, a_sum], axis=1)
expected.columns = ["mean", "sum"]
tm.assert_frame_equal(result, expected)
msg = "nested renamer is not supported"
with pytest.raises(SpecificationError, match=msg):
# using a dict with renaming
r.aggregate({"A": {"mean": "mean", "sum": "sum"}})
with pytest.raises(SpecificationError, match=msg):
r.aggregate(
{"A": {"mean": "mean", "sum": "sum"}, "B": {"mean2": "mean", "sum2": "sum"}}
)
result = r.aggregate({"A": ["mean", "std"], "B": ["mean", "std"]})
expected = concat([a_mean, a_std, b_mean, b_std], axis=1)
exp_cols = [("A", "mean"), ("A", "std"), ("B", "mean"), ("B", "std")]
expected.columns = MultiIndex.from_tuples(exp_cols)
tm.assert_frame_equal(result, expected, check_like=True)
@pytest.mark.parametrize(
"func", [["min"], ["mean", "max"], {"b": "sum"}, {"b": "prod", "c": "median"}]
)
def test_multi_axis_1_raises(func):
# GH#46904
df = DataFrame({"a": [1, 1, 2], "b": [3, 4, 5], "c": [6, 7, 8]})
r = df.rolling(window=3, axis=1)
with pytest.raises(NotImplementedError, match="axis other than 0 is not supported"):
r.agg(func)
def test_agg_apply(raw):
# passed lambda
df = DataFrame({"A": range(5), "B": range(0, 10, 2)})
r = df.rolling(window=3)
a_sum = r["A"].sum()
result = r.agg({"A": np.sum, "B": lambda x: np.std(x, ddof=1)})
rcustom = r["B"].apply(lambda x: np.std(x, ddof=1), raw=raw)
expected = concat([a_sum, rcustom], axis=1)
tm.assert_frame_equal(result, expected, check_like=True)
def test_agg_consistency(step):
df = DataFrame({"A": range(5), "B": range(0, 10, 2)})
r = df.rolling(window=3, step=step)
result = r.agg([np.sum, np.mean]).columns
expected = MultiIndex.from_product([list("AB"), ["sum", "mean"]])
tm.assert_index_equal(result, expected)
result = r["A"].agg([np.sum, np.mean]).columns
expected = Index(["sum", "mean"])
tm.assert_index_equal(result, expected)
result = r.agg({"A": [np.sum, np.mean]}).columns
expected = MultiIndex.from_tuples([("A", "sum"), ("A", "mean")])
tm.assert_index_equal(result, expected)
def test_agg_nested_dicts():
# API change for disallowing these types of nested dicts
df = DataFrame({"A": range(5), "B": range(0, 10, 2)})
r = df.rolling(window=3)
msg = "nested renamer is not supported"
with pytest.raises(SpecificationError, match=msg):
r.aggregate({"r1": {"A": ["mean", "sum"]}, "r2": {"B": ["mean", "sum"]}})
expected = concat(
[r["A"].mean(), r["A"].std(), r["B"].mean(), r["B"].std()], axis=1
)
expected.columns = MultiIndex.from_tuples(
[("ra", "mean"), ("ra", "std"), ("rb", "mean"), ("rb", "std")]
)
with pytest.raises(SpecificationError, match=msg):
r[["A", "B"]].agg({"A": {"ra": ["mean", "std"]}, "B": {"rb": ["mean", "std"]}})
with pytest.raises(SpecificationError, match=msg):
r.agg({"A": {"ra": ["mean", "std"]}, "B": {"rb": ["mean", "std"]}})
def test_count_nonnumeric_types(step):
# GH12541
cols = [
"int",
"float",
"string",
"datetime",
"timedelta",
"periods",
"fl_inf",
"fl_nan",
"str_nan",
"dt_nat",
"periods_nat",
]
dt_nat_col = [Timestamp("20170101"), Timestamp("20170203"), Timestamp(None)]
df = DataFrame(
{
"int": [1, 2, 3],
"float": [4.0, 5.0, 6.0],
"string": list("abc"),
"datetime": date_range("20170101", periods=3),
"timedelta": timedelta_range("1 s", periods=3, freq="s"),
"periods": [
Period("2012-01"),
Period("2012-02"),
Period("2012-03"),
],
"fl_inf": [1.0, 2.0, np.Inf],
"fl_nan": [1.0, 2.0, np.NaN],
"str_nan": ["aa", "bb", np.NaN],
"dt_nat": dt_nat_col,
"periods_nat": [
Period("2012-01"),
Period("2012-02"),
Period(None),
],
},
columns=cols,
)
expected = DataFrame(
{
"int": [1.0, 2.0, 2.0],
"float": [1.0, 2.0, 2.0],
"string": [1.0, 2.0, 2.0],
"datetime": [1.0, 2.0, 2.0],
"timedelta": [1.0, 2.0, 2.0],
"periods": [1.0, 2.0, 2.0],
"fl_inf": [1.0, 2.0, 2.0],
"fl_nan": [1.0, 2.0, 1.0],
"str_nan": [1.0, 2.0, 1.0],
"dt_nat": [1.0, 2.0, 1.0],
"periods_nat": [1.0, 2.0, 1.0],
},
columns=cols,
)[::step]
result = df.rolling(window=2, min_periods=0, step=step).count()
tm.assert_frame_equal(result, expected)
result = df.rolling(1, min_periods=0, step=step).count()
expected = df.notna().astype(float)[::step]
tm.assert_frame_equal(result, expected)
def test_preserve_metadata():
# GH 10565
s = Series(np.arange(100), name="foo")
s2 = s.rolling(30).sum()
s3 = s.rolling(20).sum()
assert s2.name == "foo"
assert s3.name == "foo"
@pytest.mark.parametrize(
"func,window_size,expected_vals",
[
(
"rolling",
2,
[
[np.nan, np.nan, np.nan, np.nan],
[15.0, 20.0, 25.0, 20.0],
[25.0, 30.0, 35.0, 30.0],
[np.nan, np.nan, np.nan, np.nan],
[20.0, 30.0, 35.0, 30.0],
[35.0, 40.0, 60.0, 40.0],
[60.0, 80.0, 85.0, 80],
],
),
(
"expanding",
None,
[
[10.0, 10.0, 20.0, 20.0],
[15.0, 20.0, 25.0, 20.0],
[20.0, 30.0, 30.0, 20.0],
[10.0, 10.0, 30.0, 30.0],
[20.0, 30.0, 35.0, 30.0],
[26.666667, 40.0, 50.0, 30.0],
[40.0, 80.0, 60.0, 30.0],
],
),
],
)
def test_multiple_agg_funcs(func, window_size, expected_vals):
# GH 15072
df = DataFrame(
[
["A", 10, 20],
["A", 20, 30],
["A", 30, 40],
["B", 10, 30],
["B", 30, 40],
["B", 40, 80],
["B", 80, 90],
],
columns=["stock", "low", "high"],
)
f = getattr(df.groupby("stock"), func)
if window_size:
window = f(window_size)
else:
window = f()
index = MultiIndex.from_tuples(
[("A", 0), ("A", 1), ("A", 2), ("B", 3), ("B", 4), ("B", 5), ("B", 6)],
names=["stock", None],
)
columns = MultiIndex.from_tuples(
[("low", "mean"), ("low", "max"), ("high", "mean"), ("high", "min")]
)
expected = DataFrame(expected_vals, index=index, columns=columns)
result = window.agg({"low": ["mean", "max"], "high": ["mean", "min"]})
tm.assert_frame_equal(result, expected)
def test_is_datetimelike_deprecated():
s = Series(range(1)).rolling(1)
with tm.assert_produces_warning(FutureWarning):
assert not s.is_datetimelike
def test_validate_deprecated():
s = Series(range(1)).rolling(1)
with tm.assert_produces_warning(FutureWarning):
assert s.validate() is None
@pytest.mark.filterwarnings("ignore:min_periods:FutureWarning")
def test_dont_modify_attributes_after_methods(
arithmetic_win_operators, closed, center, min_periods, step
):
# GH 39554
roll_obj = Series(range(1)).rolling(
1, center=center, closed=closed, min_periods=min_periods, step=step
)
expected = {attr: getattr(roll_obj, attr) for attr in roll_obj._attributes}
getattr(roll_obj, arithmetic_win_operators)()
result = {attr: getattr(roll_obj, attr) for attr in roll_obj._attributes}
assert result == expected
def test_centered_axis_validation(step):
# ok
Series(np.ones(10)).rolling(window=3, center=True, axis=0, step=step).mean()
# bad axis
msg = "No axis named 1 for object type Series"
with pytest.raises(ValueError, match=msg):
Series(np.ones(10)).rolling(window=3, center=True, axis=1, step=step).mean()
# ok ok
DataFrame(np.ones((10, 10))).rolling(
window=3, center=True, axis=0, step=step
).mean()
DataFrame(np.ones((10, 10))).rolling(
window=3, center=True, axis=1, step=step
).mean()
# bad axis
msg = "No axis named 2 for object type DataFrame"
with pytest.raises(ValueError, match=msg):
(
DataFrame(np.ones((10, 10)))
.rolling(window=3, center=True, axis=2, step=step)
.mean()
)
def test_rolling_min_min_periods(step):
a = Series([1, 2, 3, 4, 5])
result = a.rolling(window=100, min_periods=1, step=step).min()
expected = Series(np.ones(len(a)))[::step]
tm.assert_series_equal(result, expected)
msg = "min_periods 5 must be <= window 3"
with pytest.raises(ValueError, match=msg):
Series([1, 2, 3]).rolling(window=3, min_periods=5, step=step).min()
def test_rolling_max_min_periods(step):
a = Series([1, 2, 3, 4, 5], dtype=np.float64)
result = a.rolling(window=100, min_periods=1, step=step).max()
expected = a[::step]
tm.assert_almost_equal(result, expected)
msg = "min_periods 5 must be <= window 3"
with pytest.raises(ValueError, match=msg):
Series([1, 2, 3]).rolling(window=3, min_periods=5, step=step).max()
@pytest.mark.parametrize(
"roll_type, class_name",
[
("rolling", "Rolling"),
("expanding", "Expanding"),
("ewm", "ExponentialMovingWindow"),
],
)
@pytest.mark.parametrize(
"kernel, has_args, raises",
[
("sum", True, True),
("max", True, True),
("min", True, True),
("mean", True, True),
("median", False, False),
("std", True, True),
("var", True, True),
("skew", False, False),
("sem", True, True),
("kurt", False, False),
("quantile", False, False),
("rank", False, False),
("cov", False, False),
("corr", False, False),
],
)
def test_args_kwargs_depr(roll_type, class_name, kernel, has_args, raises):
# GH#47836
r = getattr(Series([2, 4, 6]), roll_type)(2)
error_msg = "numpy operations are not valid with window objects"
if kernel == "quantile":
required_args = (0.5,)
else:
required_args = ()
if roll_type == "ewm" and kernel not in (
"sum",
"mean",
"std",
"var",
"cov",
"corr",
):
# kernels not implemented for ewm
with pytest.raises(AttributeError, match=f"has no attribute '{kernel}'"):
getattr(r, kernel)
else:
warn_msg = f"Passing additional kwargs to {class_name}.{kernel}"
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
if raises:
with pytest.raises(UnsupportedFunctionCall, match=error_msg):
getattr(r, kernel)(*required_args, dtype=np.float64)
else:
getattr(r, kernel)(*required_args, dtype=np.float64)
if has_args:
warn_msg = f"Passing additional args to {class_name}.{kernel}"
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
# sem raises for rolling but not expanding
if raises and (roll_type != "expanding" or kernel != "sem"):
with pytest.raises(UnsupportedFunctionCall, match=error_msg):
getattr(r, kernel)(*required_args, 1, 2, 3, 4)
else:
getattr(r, kernel)(*required_args, 1, 2, 3, 4)
warn_msg = f"Passing additional args and kwargs to {class_name}.{kernel}"
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
if raises:
with pytest.raises(UnsupportedFunctionCall, match=error_msg):
getattr(r, kernel)(*required_args, 1, 2, 3, 4, dtype=np.float64)
else:
getattr(r, kernel)(*required_args, 1, 2, 3, 4, dtype=np.float64)