Skip to content

Commit acd7218

Browse files
authored
DEPR: Index.is_monotonic for Index.is_monotonic_increasing (pandas-dev#45422)
1 parent 90e512f commit acd7218

34 files changed

+143
-129
lines changed

asv_bench/benchmarks/index_cached_properties.py

-3
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ def time_values(self, index_type):
5656
def time_shape(self, index_type):
5757
self.idx.shape
5858

59-
def time_is_monotonic(self, index_type):
60-
self.idx.is_monotonic
61-
6259
def time_is_monotonic_decreasing(self, index_type):
6360
self.idx.is_monotonic_decreasing
6461

asv_bench/benchmarks/multiindex_object.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def time_get_indexer_and_pad(self):
112112
self.mi_int.get_indexer(self.other_mi_many_mismatches, method="pad")
113113

114114
def time_is_monotonic(self):
115-
self.mi_int.is_monotonic
115+
self.mi_int.is_monotonic_increasing
116116

117117

118118
class Duplicated:

doc/source/whatsnew/v1.5.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ Other Deprecations
148148
- Deprecated behavior of :meth:`SparseArray.astype`, :meth:`Series.astype`, and :meth:`DataFrame.astype` with :class:`SparseDtype` when passing a non-sparse ``dtype``. In a future version, this will cast to that non-sparse dtype instead of wrapping it in a :class:`SparseDtype` (:issue:`34457`)
149149
- Deprecated behavior of :meth:`DatetimeIndex.intersection` and :meth:`DatetimeIndex.symmetric_difference` (``union`` behavior was already deprecated in version 1.3.0) with mixed timezones; in a future version both will be cast to UTC instead of object dtype (:issue:`39328`, :issue:`45357`)
150150
- Deprecated :meth:`DataFrame.iteritems`, :meth:`Series.iteritems`, :meth:`HDFStore.iteritems` in favor of :meth:`DataFrame.items`, :meth:`Series.items`, :meth:`HDFStore.items` (:issue:`45321`)
151+
- Deprecated :meth:`Series.is_monotonic` and :meth:`Index.is_monotonic` in favor of :meth:`Series.is_monotonic_increasing` and :meth:`Index.is_monotonic_increasing` (:issue:`45422`, :issue:`21335`)
151152
- Deprecated the ``__array_wrap__`` method of DataFrame and Series, rely on standard numpy ufuncs instead (:issue:`45451`)
152153
-
153154

pandas/core/base.py

+18-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
final,
1717
overload,
1818
)
19+
import warnings
1920

2021
import numpy as np
2122

@@ -35,6 +36,7 @@
3536
cache_readonly,
3637
doc,
3738
)
39+
from pandas.util._exceptions import find_stack_level
3840

3941
from pandas.core.dtypes.common import (
4042
is_categorical_dtype,
@@ -1050,17 +1052,27 @@ def is_monotonic(self) -> bool:
10501052
-------
10511053
bool
10521054
"""
1053-
from pandas import Index
1054-
1055-
return Index(self).is_monotonic
1055+
warnings.warn(
1056+
"is_monotonic is deprecated and will be removed in a future version. "
1057+
"Use is_monotonic_increasing instead.",
1058+
FutureWarning,
1059+
stacklevel=find_stack_level(),
1060+
)
1061+
return self.is_monotonic_increasing
10561062

10571063
@property
10581064
def is_monotonic_increasing(self) -> bool:
10591065
"""
1060-
Alias for is_monotonic.
1066+
Return boolean if values in the object are
1067+
monotonic_increasing.
1068+
1069+
Returns
1070+
-------
1071+
bool
10611072
"""
1062-
# mypy complains if we alias directly
1063-
return self.is_monotonic
1073+
from pandas import Index
1074+
1075+
return Index(self).is_monotonic_increasing
10641076

10651077
@property
10661078
def is_monotonic_decreasing(self) -> bool:

pandas/core/generic.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7161,7 +7161,7 @@ def asof(self, where, subset=None):
71617161
if isinstance(where, str):
71627162
where = Timestamp(where)
71637163

7164-
if not self.index.is_monotonic:
7164+
if not self.index.is_monotonic_increasing:
71657165
raise ValueError("asof requires a sorted index")
71667166

71677167
is_series = isinstance(self, ABCSeries)

pandas/core/groupby/grouper.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ def _set_grouper(self, obj: NDFrame, sort: bool = False):
400400
raise ValueError(f"The level {level} is not valid")
401401

402402
# possibly sort
403-
if (self.sort or sort) and not ax.is_monotonic:
403+
if (self.sort or sort) and not ax.is_monotonic_increasing:
404404
# use stable sort to support first, last, nth
405405
# TODO: why does putting na_position="first" fix datetimelike cases?
406406
indexer = self.indexer = ax.array.argsort(

pandas/core/groupby/ops.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ def groups(self) -> dict[Hashable, np.ndarray]:
823823
@cache_readonly
824824
def is_monotonic(self) -> bool:
825825
# return if my group orderings are monotonic
826-
return Index(self.group_info[0]).is_monotonic
826+
return Index(self.group_info[0]).is_monotonic_increasing
827827

828828
@cache_readonly
829829
def group_info(self) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp], int]:

pandas/core/indexes/base.py

+17-7
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,12 @@ def is_monotonic(self) -> bool:
22002200
"""
22012201
Alias for is_monotonic_increasing.
22022202
"""
2203+
warnings.warn(
2204+
"is_monotonic is deprecated and will be removed in a future version. "
2205+
"Use is_monotonic_increasing instead.",
2206+
FutureWarning,
2207+
stacklevel=find_stack_level(),
2208+
)
22032209
return self.is_monotonic_increasing
22042210

22052211
@property
@@ -3263,8 +3269,8 @@ def _union(self, other: Index, sort):
32633269

32643270
if (
32653271
sort is None
3266-
and self.is_monotonic
3267-
and other.is_monotonic
3272+
and self.is_monotonic_increasing
3273+
and other.is_monotonic_increasing
32683274
and not (self.has_duplicates and other.has_duplicates)
32693275
and self._can_use_libjoin
32703276
):
@@ -3302,7 +3308,7 @@ def _union(self, other: Index, sort):
33023308
else:
33033309
result = lvals
33043310

3305-
if not self.is_monotonic or not other.is_monotonic:
3311+
if not self.is_monotonic_increasing or not other.is_monotonic_increasing:
33063312
# if both are monotonic then result should already be sorted
33073313
result = _maybe_try_sort(result, sort)
33083314

@@ -3407,7 +3413,11 @@ def _intersection(self, other: Index, sort=False):
34073413
"""
34083414
intersection specialized to the case with matching dtypes.
34093415
"""
3410-
if self.is_monotonic and other.is_monotonic and self._can_use_libjoin:
3416+
if (
3417+
self.is_monotonic_increasing
3418+
and other.is_monotonic_increasing
3419+
and self._can_use_libjoin
3420+
):
34113421
try:
34123422
result = self._inner_indexer(other)[0]
34133423
except TypeError:
@@ -4503,15 +4513,15 @@ def join(
45034513
if not self.is_unique and not other.is_unique:
45044514
return self._join_non_unique(other, how=how)
45054515
elif not self.is_unique or not other.is_unique:
4506-
if self.is_monotonic and other.is_monotonic:
4516+
if self.is_monotonic_increasing and other.is_monotonic_increasing:
45074517
if self._can_use_libjoin:
45084518
# otherwise we will fall through to _join_via_get_indexer
45094519
return self._join_monotonic(other, how=how)
45104520
else:
45114521
return self._join_non_unique(other, how=how)
45124522
elif (
4513-
self.is_monotonic
4514-
and other.is_monotonic
4523+
self.is_monotonic_increasing
4524+
and other.is_monotonic_increasing
45154525
and self._can_use_libjoin
45164526
and (
45174527
not isinstance(self, ABCMultiIndex)

pandas/core/indexes/multi.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -1557,7 +1557,7 @@ def is_monotonic_increasing(self) -> bool:
15571557
if any(-1 in code for code in self.codes):
15581558
return False
15591559

1560-
if all(level.is_monotonic for level in self.levels):
1560+
if all(level.is_monotonic_increasing for level in self.levels):
15611561
# If each level is sorted, we can operate on the codes directly. GH27495
15621562
return libalgos.is_lexsorted(
15631563
[x.astype("int64", copy=False) for x in self.codes]
@@ -1574,11 +1574,11 @@ def is_monotonic_increasing(self) -> bool:
15741574
# int, float, complex, str, bytes, _NestedSequence[Union[bool, int, float,
15751575
# complex, str, bytes]]]" [arg-type]
15761576
sort_order = np.lexsort(values) # type: ignore[arg-type]
1577-
return Index(sort_order).is_monotonic
1577+
return Index(sort_order).is_monotonic_increasing
15781578
except TypeError:
15791579

15801580
# we have mixed types and np.lexsort is not happy
1581-
return Index(self._values).is_monotonic
1581+
return Index(self._values).is_monotonic_increasing
15821582

15831583
@cache_readonly
15841584
def is_monotonic_decreasing(self) -> bool:
@@ -1946,15 +1946,15 @@ def _sort_levels_monotonic(self) -> MultiIndex:
19461946
('b', 'bb')],
19471947
)
19481948
"""
1949-
if self._is_lexsorted() and self.is_monotonic:
1949+
if self._is_lexsorted() and self.is_monotonic_increasing:
19501950
return self
19511951

19521952
new_levels = []
19531953
new_codes = []
19541954

19551955
for lev, level_codes in zip(self.levels, self.codes):
19561956

1957-
if not lev.is_monotonic:
1957+
if not lev.is_monotonic_increasing:
19581958
try:
19591959
# indexer to reorder the levels
19601960
indexer = lev.argsort()

pandas/core/missing.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def clean_interp_method(method: str, index: Index, **kwargs) -> str:
161161
raise ValueError(f"method must be one of {valid}. Got '{method}' instead.")
162162

163163
if method in ("krogh", "piecewise_polynomial", "pchip"):
164-
if not index.is_monotonic:
164+
if not index.is_monotonic_increasing:
165165
raise ValueError(
166166
f"{method} interpolation requires that the index be monotonic."
167167
)

pandas/core/reshape/merge.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1929,14 +1929,14 @@ def flip(xs) -> np.ndarray:
19291929
tolerance = self.tolerance
19301930

19311931
# we require sortedness and non-null values in the join keys
1932-
if not Index(left_values).is_monotonic:
1932+
if not Index(left_values).is_monotonic_increasing:
19331933
side = "left"
19341934
if isna(left_values).any():
19351935
raise ValueError(f"Merge keys contain null values on {side} side")
19361936
else:
19371937
raise ValueError(f"{side} keys must be sorted")
19381938

1939-
if not Index(right_values).is_monotonic:
1939+
if not Index(right_values).is_monotonic_increasing:
19401940
side = "right"
19411941
if isna(right_values).any():
19421942
raise ValueError(f"Merge keys contain null values on {side} side")

pandas/tests/frame/methods/test_sort_index.py

+9-11
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def test_sort_index_and_reconstruction_doc_example(self):
2525
),
2626
)
2727
assert df.index._is_lexsorted()
28-
assert not df.index.is_monotonic
28+
assert not df.index.is_monotonic_increasing
2929

3030
# sort it
3131
expected = DataFrame(
@@ -35,23 +35,21 @@ def test_sort_index_and_reconstruction_doc_example(self):
3535
),
3636
)
3737
result = df.sort_index()
38-
assert result.index.is_monotonic
39-
38+
assert result.index.is_monotonic_increasing
4039
tm.assert_frame_equal(result, expected)
4140

4241
# reconstruct
4342
result = df.sort_index().copy()
4443
result.index = result.index._sort_levels_monotonic()
45-
assert result.index.is_monotonic
46-
44+
assert result.index.is_monotonic_increasing
4745
tm.assert_frame_equal(result, expected)
4846

4947
def test_sort_index_non_existent_label_multiindex(self):
5048
# GH#12261
5149
df = DataFrame(0, columns=[], index=MultiIndex.from_product([[], []]))
5250
df.loc["b", "2"] = 1
5351
df.loc["a", "3"] = 1
54-
result = df.sort_index().index.is_monotonic
52+
result = df.sort_index().index.is_monotonic_increasing
5553
assert result is True
5654

5755
def test_sort_index_reorder_on_ops(self):
@@ -549,7 +547,7 @@ def test_sort_index_and_reconstruction(self):
549547
index=MultiIndex.from_product([[0.5, 0.8], list("ab")]),
550548
)
551549
result = result.sort_index()
552-
assert result.index.is_monotonic
550+
assert result.index.is_monotonic_increasing
553551

554552
tm.assert_frame_equal(result, expected)
555553

@@ -567,7 +565,7 @@ def test_sort_index_and_reconstruction(self):
567565
concatted = pd.concat([df, df], keys=[0.8, 0.5])
568566
result = concatted.sort_index()
569567

570-
assert result.index.is_monotonic
568+
assert result.index.is_monotonic_increasing
571569

572570
tm.assert_frame_equal(result, expected)
573571

@@ -583,11 +581,11 @@ def test_sort_index_and_reconstruction(self):
583581
df.columns = df.columns.set_levels(
584582
pd.to_datetime(df.columns.levels[1]), level=1
585583
)
586-
assert not df.columns.is_monotonic
584+
assert not df.columns.is_monotonic_increasing
587585
result = df.sort_index(axis=1)
588-
assert result.columns.is_monotonic
586+
assert result.columns.is_monotonic_increasing
589587
result = df.sort_index(axis=1, level=1)
590-
assert result.columns.is_monotonic
588+
assert result.columns.is_monotonic_increasing
591589

592590
# TODO: better name, de-duplicate with test_sort_index_level above
593591
def test_sort_index_level2(self, multiindex_dataframe_random_data):

pandas/tests/frame/test_constructors.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1530,7 +1530,7 @@ def test_constructor_mixed_dict_and_Series(self):
15301530
data["B"] = Series([4, 3, 2, 1], index=["bar", "qux", "baz", "foo"])
15311531

15321532
result = DataFrame(data)
1533-
assert result.index.is_monotonic
1533+
assert result.index.is_monotonic_increasing
15341534

15351535
# ordering ambiguous, raise exception
15361536
with pytest.raises(ValueError, match="ambiguous ordering"):

pandas/tests/indexes/datetimelike_/test_is_monotonic.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
def test_is_monotonic_with_nat():
99
# GH#31437
10-
# PeriodIndex.is_monotonic should behave analogously to DatetimeIndex,
10+
# PeriodIndex.is_monotonic_increasing should behave analogously to DatetimeIndex,
1111
# in particular never be monotonic when we have NaT
1212
dti = date_range("2016-01-01", periods=3)
1313
pi = dti.to_period("D")
@@ -16,7 +16,7 @@ def test_is_monotonic_with_nat():
1616
for obj in [pi, pi._engine, dti, dti._engine, tdi, tdi._engine]:
1717
if isinstance(obj, Index):
1818
# i.e. not Engines
19-
assert obj.is_monotonic
19+
assert obj.is_monotonic_increasing
2020
assert obj.is_monotonic_increasing
2121
assert not obj.is_monotonic_decreasing
2222
assert obj.is_unique
@@ -28,7 +28,7 @@ def test_is_monotonic_with_nat():
2828
for obj in [pi1, pi1._engine, dti1, dti1._engine, tdi1, tdi1._engine]:
2929
if isinstance(obj, Index):
3030
# i.e. not Engines
31-
assert not obj.is_monotonic
31+
assert not obj.is_monotonic_increasing
3232
assert not obj.is_monotonic_increasing
3333
assert not obj.is_monotonic_decreasing
3434
assert obj.is_unique
@@ -40,7 +40,7 @@ def test_is_monotonic_with_nat():
4040
for obj in [pi2, pi2._engine, dti2, dti2._engine, tdi2, tdi2._engine]:
4141
if isinstance(obj, Index):
4242
# i.e. not Engines
43-
assert not obj.is_monotonic
43+
assert not obj.is_monotonic_increasing
4444
assert not obj.is_monotonic_increasing
4545
assert not obj.is_monotonic_decreasing
4646
assert obj.is_unique

pandas/tests/indexes/datetimelike_/test_sort_values.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,16 @@ def test_argmin_argmax(self, non_monotonic_idx):
5959
def test_sort_values(self, non_monotonic_idx):
6060
idx = non_monotonic_idx
6161
ordered = idx.sort_values()
62-
assert ordered.is_monotonic
63-
62+
assert ordered.is_monotonic_increasing
6463
ordered = idx.sort_values(ascending=False)
65-
assert ordered[::-1].is_monotonic
64+
assert ordered[::-1].is_monotonic_increasing
6665

6766
ordered, dexer = idx.sort_values(return_indexer=True)
68-
assert ordered.is_monotonic
67+
assert ordered.is_monotonic_increasing
6968
tm.assert_numpy_array_equal(dexer, np.array([1, 2, 0], dtype=np.intp))
7069

7170
ordered, dexer = idx.sort_values(return_indexer=True, ascending=False)
72-
assert ordered[::-1].is_monotonic
71+
assert ordered[::-1].is_monotonic_increasing
7372
tm.assert_numpy_array_equal(dexer, np.array([0, 2, 1], dtype=np.intp))
7473

7574
def check_sort_values_with_freq(self, idx):

pandas/tests/indexes/datetimes/test_join.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def test_join_nonunique(self):
8989
idx1 = to_datetime(["2012-11-06 16:00:11.477563", "2012-11-06 16:00:11.477563"])
9090
idx2 = to_datetime(["2012-11-06 15:11:09.006507", "2012-11-06 15:11:09.006507"])
9191
rs = idx1.join(idx2, how="outer")
92-
assert rs.is_monotonic
92+
assert rs.is_monotonic_increasing
9393

9494
@pytest.mark.parametrize("freq", ["B", "C"])
9595
def test_outer_join(self, freq):

0 commit comments

Comments
 (0)