Skip to content

Commit 2263982

Browse files
TomAugspurgerjreback
authored andcommitted
BUG: partial string indexing with scalar (#27712)
Closes #27516
1 parent 6af6d51 commit 2263982

File tree

6 files changed

+31
-4
lines changed

6 files changed

+31
-4
lines changed

doc/source/whatsnew/v0.25.1.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ Interval
8282
Indexing
8383
^^^^^^^^
8484

85-
-
85+
- Bug in partial-string indexing returning a NumPy array rather than a ``Series`` when indexing with a scalar like ``.loc['2015']`` (:issue:`27516`)
8686
-
8787
-
8888

pandas/core/indexes/base.py

+3
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ def _outer_indexer(self, left, right):
243243
_infer_as_myclass = False
244244

245245
_engine_type = libindex.ObjectEngine
246+
# whether we support partial string indexing. Overridden
247+
# in DatetimeIndex and PeriodIndex
248+
_supports_partial_string_indexing = False
246249

247250
_accessors = {"str"}
248251

pandas/core/indexes/datetimes.py

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ def _join_i8_wrapper(joinf, **kwargs):
238238
)
239239

240240
_engine_type = libindex.DatetimeEngine
241+
_supports_partial_string_indexing = True
241242

242243
_tz = None
243244
_freq = None

pandas/core/indexes/period.py

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ class PeriodIndex(DatetimeIndexOpsMixin, Int64Index, PeriodDelegateMixin):
173173
_data = None
174174

175175
_engine_type = libindex.PeriodEngine
176+
_supports_partial_string_indexing = True
176177

177178
# ------------------------------------------------------------------------
178179
# Index Constructors

pandas/core/indexing.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -1704,6 +1704,11 @@ def _is_scalar_access(self, key: Tuple):
17041704
if isinstance(ax, MultiIndex):
17051705
return False
17061706

1707+
if isinstance(k, str) and ax._supports_partial_string_indexing:
1708+
# partial string indexing, df.loc['2000', 'A']
1709+
# should not be considered scalar
1710+
return False
1711+
17071712
if not ax.is_unique:
17081713
return False
17091714

@@ -1719,7 +1724,10 @@ def _get_partial_string_timestamp_match_key(self, key, labels):
17191724
"""Translate any partial string timestamp matches in key, returning the
17201725
new key (GH 10331)"""
17211726
if isinstance(labels, MultiIndex):
1722-
if isinstance(key, str) and labels.levels[0].is_all_dates:
1727+
if (
1728+
isinstance(key, str)
1729+
and labels.levels[0]._supports_partial_string_indexing
1730+
):
17231731
# Convert key '2016-01-01' to
17241732
# ('2016-01-01'[, slice(None, None, None)]+)
17251733
key = tuple([key] + [slice(None)] * (len(labels.levels) - 1))
@@ -1729,7 +1737,10 @@ def _get_partial_string_timestamp_match_key(self, key, labels):
17291737
# (..., slice('2016-01-01', '2016-01-01', None), ...)
17301738
new_key = []
17311739
for i, component in enumerate(key):
1732-
if isinstance(component, str) and labels.levels[i].is_all_dates:
1740+
if (
1741+
isinstance(component, str)
1742+
and labels.levels[i]._supports_partial_string_indexing
1743+
):
17331744
new_key.append(slice(component, component, None))
17341745
else:
17351746
new_key.append(component)
@@ -2334,7 +2345,7 @@ def convert_to_index_sliceable(obj, key):
23342345

23352346
# We might have a datetimelike string that we can translate to a
23362347
# slice here via partial string indexing
2337-
if idx.is_all_dates:
2348+
if idx._supports_partial_string_indexing:
23382349
try:
23392350
return idx._get_string_slice(key)
23402351
except (KeyError, ValueError, NotImplementedError):

pandas/tests/indexes/datetimes/test_partial_slicing.py

+11
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,14 @@ def test_getitem_with_datestring_with_UTC_offset(self, start, end):
468468
with pytest.raises(ValueError, match="The index must be timezone"):
469469
df = df.tz_localize(None)
470470
df[start:end]
471+
472+
def test_slice_reduce_to_series(self):
473+
# GH 27516
474+
df = pd.DataFrame(
475+
{"A": range(24)}, index=pd.date_range("2000", periods=24, freq="M")
476+
)
477+
expected = pd.Series(
478+
range(12), index=pd.date_range("2000", periods=12, freq="M"), name="A"
479+
)
480+
result = df.loc["2000", "A"]
481+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)