Skip to content

Commit cd20c95

Browse files
jbrockmendeljreback
authored andcommitted
REF: use _get_string_slice in PeriodIndex.get_value (#31058)
1 parent e0bd394 commit cd20c95

File tree

1 file changed

+29
-56
lines changed

1 file changed

+29
-56
lines changed

pandas/core/indexes/period.py

Lines changed: 29 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -483,25 +483,20 @@ def get_value(self, series, key):
483483
return series.iat[key]
484484

485485
if isinstance(key, str):
486+
try:
487+
loc = self._get_string_slice(key)
488+
return series[loc]
489+
except (TypeError, ValueError):
490+
pass
491+
486492
asdt, reso = parse_time_string(key, self.freq)
487493
grp = resolution.Resolution.get_freq_group(reso)
488494
freqn = resolution.get_freq_group(self.freq)
489495

490-
vals = self._ndarray_values
491-
492-
# if our data is higher resolution than requested key, slice
493-
if grp < freqn:
494-
iv = Period(asdt, freq=(grp, 1))
495-
ord1 = iv.asfreq(self.freq, how="S").ordinal
496-
ord2 = iv.asfreq(self.freq, how="E").ordinal
496+
# _get_string_slice will handle cases where grp < freqn
497+
assert grp >= freqn
497498

498-
if ord2 < vals[0] or ord1 > vals[-1]:
499-
raise KeyError(key)
500-
501-
pos = np.searchsorted(self._ndarray_values, [ord1, ord2])
502-
key = slice(pos[0], pos[1] + 1)
503-
return series[key]
504-
elif grp == freqn:
499+
if grp == freqn:
505500
key = Period(asdt, freq=self.freq)
506501
loc = self.get_loc(key)
507502
return series.iloc[loc]
@@ -643,61 +638,39 @@ def _maybe_cast_slice_bound(self, label, side, kind):
643638

644639
return label
645640

646-
def _parsed_string_to_bounds(self, reso, parsed):
647-
if reso == "year":
648-
t1 = Period(year=parsed.year, freq="A")
649-
elif reso == "month":
650-
t1 = Period(year=parsed.year, month=parsed.month, freq="M")
651-
elif reso == "quarter":
652-
q = (parsed.month - 1) // 3 + 1
653-
t1 = Period(year=parsed.year, quarter=q, freq="Q-DEC")
654-
elif reso == "day":
655-
t1 = Period(year=parsed.year, month=parsed.month, day=parsed.day, freq="D")
656-
elif reso == "hour":
657-
t1 = Period(
658-
year=parsed.year,
659-
month=parsed.month,
660-
day=parsed.day,
661-
hour=parsed.hour,
662-
freq="H",
663-
)
664-
elif reso == "minute":
665-
t1 = Period(
666-
year=parsed.year,
667-
month=parsed.month,
668-
day=parsed.day,
669-
hour=parsed.hour,
670-
minute=parsed.minute,
671-
freq="T",
672-
)
673-
elif reso == "second":
674-
t1 = Period(
675-
year=parsed.year,
676-
month=parsed.month,
677-
day=parsed.day,
678-
hour=parsed.hour,
679-
minute=parsed.minute,
680-
second=parsed.second,
681-
freq="S",
682-
)
683-
else:
641+
def _parsed_string_to_bounds(self, reso: str, parsed: datetime):
642+
if reso not in ["year", "month", "quarter", "day", "hour", "minute", "second"]:
684643
raise KeyError(reso)
685-
return (t1.asfreq(self.freq, how="start"), t1.asfreq(self.freq, how="end"))
644+
645+
grp = resolution.Resolution.get_freq_group(reso)
646+
iv = Period(parsed, freq=(grp, 1))
647+
return (iv.asfreq(self.freq, how="start"), iv.asfreq(self.freq, how="end"))
686648

687649
def _get_string_slice(self, key: str, use_lhs: bool = True, use_rhs: bool = True):
688650
# TODO: Check for non-True use_lhs/use_rhs
651+
raw = key
689652
if not self.is_monotonic:
690653
raise ValueError("Partial indexing only valid for ordered time series")
691654

692655
parsed, reso = parse_time_string(key, self.freq)
693656
grp = resolution.Resolution.get_freq_group(reso)
694657
freqn = resolution.get_freq_group(self.freq)
695-
if reso in ["day", "hour", "minute", "second"] and not grp < freqn:
696-
raise KeyError(key)
658+
659+
if not grp < freqn:
660+
# TODO: we used to also check for
661+
# reso in ["day", "hour", "minute", "second"]
662+
# why is that check not needed?
663+
raise TypeError(key)
697664

698665
t1, t2 = self._parsed_string_to_bounds(reso, parsed)
666+
if len(self):
667+
if t2 < self.min() or t1 > self.max():
668+
raise KeyError(raw)
669+
670+
# Use asi8 searchsorted to avoid overhead of re-validating inputs
699671
return slice(
700-
self.searchsorted(t1, side="left"), self.searchsorted(t2, side="right")
672+
self.asi8.searchsorted(t1.ordinal, side="left"),
673+
self.asi8.searchsorted(t2.ordinal, side="right"),
701674
)
702675

703676
def _convert_tolerance(self, tolerance, target):

0 commit comments

Comments
 (0)