Skip to content

BUG: Series.loc[dtstr] type depends on monotonicity #42265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 1, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 2 additions & 17 deletions pandas/core/indexes/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,23 +604,8 @@ def _parsed_string_to_bounds(self, reso: Resolution, parsed: datetime):
return start, end

def _can_partial_date_slice(self, reso: Resolution) -> bool:
assert isinstance(reso, Resolution), (type(reso), reso)
if (
self.is_monotonic
and reso.attrname in ["day", "hour", "minute", "second"]
and self._resolution_obj >= reso
):
# These resolution/monotonicity validations came from GH3931,
# GH3452 and GH2369.

# See also GH14826
return False

if reso.attrname == "microsecond":
# _partial_date_slice doesn't allow microsecond resolution, but
# _parsed_string_to_bounds allows it.
return False
return True
# History of conversation GH#3452, GH#3931, GH#2369, GH#14826
return reso > self._resolution_obj

def _deprecate_mismatched_indexing(self, key) -> None:
# GH#36148
Expand Down
65 changes: 62 additions & 3 deletions pandas/tests/indexes/datetimes/test_partial_slicing.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,55 @@


class TestSlicing:
def test_return_type_doesnt_depend_on_monotonicity(self):
# GH#24892 we get Series back regardless of whether our DTI is monotonic
dti = date_range(start="2015-5-13 23:59:00", freq="min", periods=3)
ser = Series(range(3), index=dti)

# non-monotonic index
ser2 = Series(range(3), index=[dti[1], dti[0], dti[2]])

# key with resolution strictly lower than "min"
key = "2015-5-14 00"

# monotonic increasing index
result = ser.loc[key]
expected = ser.iloc[1:]
tm.assert_series_equal(result, expected)

# monotonic decreasing index
result = ser.iloc[::-1].loc[key]
expected = ser.iloc[::-1][:-1]
tm.assert_series_equal(result, expected)

# non-monotonic index
result2 = ser2.loc[key]
expected2 = ser2.iloc[::2]
tm.assert_series_equal(result2, expected2)

def test_return_type_doesnt_depend_on_monotonicity_higher_reso(self):
# GH#24892 we get Series back regardless of whether our DTI is monotonic
dti = date_range(start="2015-5-13 23:59:00", freq="min", periods=3)
ser = Series(range(3), index=dti)

# non-monotonic index
ser2 = Series(range(3), index=[dti[1], dti[0], dti[2]])

# key with resolution strictly *higher) than "min"
key = "2015-5-14 00:00:00"

# monotonic increasing index
result = ser.loc[key]
assert result == 1

# monotonic decreasing index
result = ser.iloc[::-1].loc[key]
assert result == 1

# non-monotonic index
result2 = ser2.loc[key]
assert result2 == 0

def test_monotone_DTI_indexing_bug(self):
# GH 19362
# Testing accessing the first element in a monotonic descending
Expand All @@ -38,9 +87,19 @@ def test_monotone_DTI_indexing_bug(self):
expected = DataFrame({0: list(range(5)), "date": date_index})
tm.assert_frame_equal(df, expected)

df = DataFrame({"A": [1, 2, 3]}, index=date_range("20170101", periods=3)[::-1])
expected = DataFrame({"A": 1}, index=date_range("20170103", periods=1)[::-1])
tm.assert_frame_equal(df.loc["2017-01-03"], expected)
# We get a slice because df.index's resolution is hourly and we
# are slicing with a daily-resolution string. If both were daily,
# we would get a single item back
dti = date_range("20170101 01:00:00", periods=3)
df = DataFrame({"A": [1, 2, 3]}, index=dti[::-1])

expected = DataFrame({"A": 1}, index=dti[-1:][::-1])
result = df.loc["2017-01-03"]
tm.assert_frame_equal(result, expected)

result2 = df.iloc[::-1].loc["2017-01-03"]
expected2 = expected.iloc[::-1]
tm.assert_frame_equal(result2, expected2)

def test_slice_year(self):
dti = date_range(freq="B", start=datetime(2005, 1, 1), periods=500)
Expand Down