def get_value(self, series, key): """ Fast lookup of value from 1-dimensional ndarray. Only use this if you know what you're doing """ s = com.values_from_object(series) try: return com.maybe_box(self, super(PeriodIndex, self).get_value(s, key), series, key) except (KeyError, IndexError): try: asdt, parsed, reso = parse_time_string(key, self.freq) grp = resolution.Resolution.get_freq_group(reso) freqn = resolution.get_freq_group(self.freq) vals = self._ndarray_values # if our data is higher resolution than requested key, slice if grp < freqn: iv = Period(asdt, freq=(grp, 1)) ord1 = iv.asfreq(self.freq, how='S').ordinal ord2 = iv.asfreq(self.freq, how='E').ordinal if ord2 < vals[0] or ord1 > vals[-1]: raise KeyError(key) pos = np.searchsorted(self._ndarray_values, [ord1, ord2]) key = slice(pos[0], pos[1] + 1) return series[key] elif grp == freqn: key = Period(asdt, freq=self.freq).ordinal return com.maybe_box(self, self._engine.get_value(s, key), series, key) else: raise KeyError(key) except TypeError: pass period = Period(key, self.freq) key = period.value if isna(period) else period.ordinal return com.maybe_box(self, self._engine.get_value(s, key), series, key)
def _parsed_string_to_bounds(self, reso: str, parsed: datetime): if reso not in [ "year", "month", "quarter", "day", "hour", "minute", "second" ]: raise KeyError(reso) grp = resolution.Resolution.get_freq_group(reso) iv = Period(parsed, freq=(grp, 1)) return (iv.asfreq(self.freq, how="start"), iv.asfreq(self.freq, how="end"))
def get_loc(self, key, method=None, tolerance=None): """ Get integer location for requested label. Parameters ---------- key : Period, NaT, str, or datetime String or datetime key must be parseable as Period. Returns ------- loc : int or ndarray[int64] Raises ------ KeyError Key is not present in the index. TypeError If key is listlike or otherwise not hashable. """ if isinstance(key, str): try: asdt, reso = parse_time_string(key, self.freq) key = asdt except DateParseError: # A string with invalid format raise KeyError(f"Cannot interpret '{key}' as period") elif is_integer(key): # Period constructor will cast to string, which we dont want raise KeyError(key) try: key = Period(key, freq=self.freq) except ValueError: # we cannot construct the Period # as we have an invalid type if is_list_like(key): raise TypeError(f"'{key}' is an invalid key") raise KeyError(key) ordinal = key.ordinal if key is not NaT else key.value try: return self._engine.get_loc(ordinal) except KeyError: try: if tolerance is not None: tolerance = self._convert_tolerance( tolerance, np.asarray(key)) return self._int64index.get_loc(ordinal, method, tolerance) except KeyError: raise KeyError(key)
def _get_ordinal_range(start, end, periods, freq, mult=1): if com.count_not_none(start, end, periods) != 2: raise ValueError('Of the three parameters: start, end, and periods, ' 'exactly two must be specified') if freq is not None: _, mult = frequencies.get_freq_code(freq) if start is not None: start = Period(start, freq) if end is not None: end = Period(end, freq) is_start_per = isinstance(start, Period) is_end_per = isinstance(end, Period) if is_start_per and is_end_per and start.freq != end.freq: raise ValueError('start and end must have same freq') if (start is NaT or end is NaT): raise ValueError('start and end must not be NaT') if freq is None: if is_start_per: freq = start.freq elif is_end_per: freq = end.freq else: # pragma: no cover raise ValueError('Could not infer freq from start/end') if periods is not None: periods = periods * mult if start is None: data = np.arange(end.ordinal - periods + mult, end.ordinal + 1, mult, dtype=np.int64) else: data = np.arange(start.ordinal, start.ordinal + periods, mult, dtype=np.int64) else: data = np.arange(start.ordinal, end.ordinal + 1, mult, dtype=np.int64) return data, freq
def get_value(self, series, key): """ Fast lookup of value from 1-dimensional ndarray. Only use this if you know what you're doing """ if is_integer(key): return series.iat[key] if isinstance(key, str): asdt, reso = parse_time_string(key, self.freq) grp = resolution.Resolution.get_freq_group(reso) freqn = resolution.get_freq_group(self.freq) vals = self._ndarray_values # if our data is higher resolution than requested key, slice if grp < freqn: iv = Period(asdt, freq=(grp, 1)) ord1 = iv.asfreq(self.freq, how="S").ordinal ord2 = iv.asfreq(self.freq, how="E").ordinal if ord2 < vals[0] or ord1 > vals[-1]: raise KeyError(key) pos = np.searchsorted(self._ndarray_values, [ord1, ord2]) key = slice(pos[0], pos[1] + 1) return series[key] elif grp == freqn: key = Period(asdt, freq=self.freq) loc = self.get_loc(key) return series.iloc[loc] else: raise KeyError(key) elif isinstance(key, Period) or key is NaT: ordinal = key.ordinal if key is not NaT else NaT.value loc = self._engine.get_loc(ordinal) return series[loc] # slice, PeriodIndex, np.ndarray, List[Period] value = Index.get_value(self, series, key) return com.maybe_box(self, value, series, key)
def searchsorted(self, value, side='left', sorter=None): if isinstance(value, Period): if value.freq != self.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, value.freqstr) raise IncompatibleFrequency(msg) value = value.ordinal elif isinstance(value, compat.string_types): value = Period(value, freq=self.freq).ordinal return self._ndarray_values.searchsorted(value, side=side, sorter=sorter)
def searchsorted(self, value, side="left", sorter=None): if isinstance(value, Period): if value.freq != self.freq: raise raise_on_incompatible(self, value) value = value.ordinal elif isinstance(value, str): try: value = Period(value, freq=self.freq).ordinal except DateParseError: raise KeyError(f"Cannot interpret '{value}' as period") return self._ndarray_values.searchsorted(value, side=side, sorter=sorter)
def searchsorted(self, value, side="left", sorter=None): if isinstance(value, Period) or value is NaT: self._data._check_compatible_with(value) elif isinstance(value, str): try: value = Period(value, freq=self.freq) except DateParseError: raise KeyError(f"Cannot interpret '{value}' as period") elif not isinstance(value, PeriodArray): raise TypeError( "PeriodIndex.searchsorted requires either a Period or PeriodArray" ) return self._data.searchsorted(value, side=side, sorter=sorter)
def searchsorted(self, value, side='left', sorter=None): if isinstance(value, Period): if value.freq != self.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, value.freqstr) raise IncompatibleFrequency(msg) value = value.ordinal elif isinstance(value, compat.string_types): try: value = Period(value, freq=self.freq).ordinal except DateParseError: raise KeyError("Cannot interpret '{}' as period".format(value)) return self._ndarray_values.searchsorted(value, side=side, sorter=sorter)
def searchsorted(self, value, side="left", sorter=None): if isinstance(value, Period): if value.freq != self.freq: msg = DIFFERENT_FREQ.format( cls=type(self).__name__, own_freq=self.freqstr, other_freq=value.freqstr, ) raise IncompatibleFrequency(msg) value = value.ordinal elif isinstance(value, str): try: value = Period(value, freq=self.freq).ordinal except DateParseError: raise KeyError("Cannot interpret '{}' as period".format(value)) return self._ndarray_values.searchsorted(value, side=side, sorter=sorter)
def wrapper(self, other): ordinal_op = getattr(self.asi8, opname) if is_list_like(other) and len(other) != len(self): raise ValueError("Lengths must match") if isinstance(other, str): try: other = self._scalar_from_string(other) except ValueError: # string that can't be parsed as Period return invalid_comparison(self, other, op) elif isinstance(other, int): # TODO: sure we want to allow this? we dont for DTA/TDA # 2 tests rely on this other = Period(other, freq=self.freq) result = ordinal_op(other.ordinal) if isinstance(other, Period): self._check_compatible_with(other) result = ordinal_op(other.ordinal) elif isinstance(other, cls): self._check_compatible_with(other) result = ordinal_op(other.asi8) mask = self._isnan | other._isnan if mask.any(): result[mask] = nat_result return result elif other is NaT: result = np.empty(len(self.asi8), dtype=bool) result.fill(nat_result) else: return invalid_comparison(self, other, op) if self._hasnans: result[self._isnan] = nat_result return result
def _parsed_string_to_bounds(self, reso, parsed): if reso == "year": t1 = Period(year=parsed.year, freq="A") elif reso == "month": t1 = Period(year=parsed.year, month=parsed.month, freq="M") elif reso == "quarter": q = (parsed.month - 1) // 3 + 1 t1 = Period(year=parsed.year, quarter=q, freq="Q-DEC") elif reso == "day": t1 = Period(year=parsed.year, month=parsed.month, day=parsed.day, freq="D") elif reso == "hour": t1 = Period( year=parsed.year, month=parsed.month, day=parsed.day, hour=parsed.hour, freq="H", ) elif reso == "minute": t1 = Period( year=parsed.year, month=parsed.month, day=parsed.day, hour=parsed.hour, minute=parsed.minute, freq="T", ) elif reso == "second": t1 = Period( year=parsed.year, month=parsed.month, day=parsed.day, hour=parsed.hour, minute=parsed.minute, second=parsed.second, freq="S", ) else: raise KeyError(reso) return (t1.asfreq(self.freq, how="start"), t1.asfreq(self.freq, how="end"))
def wrapper(self, other): op = getattr(self.asi8, opname) # We want to eventually defer to the Series or PeriodIndex (which will # return here with an unboxed PeriodArray). But before we do that, # we do a bit of validation on type (Period) and freq, so that our # error messages are sensible not_implemented = isinstance(other, (ABCSeries, ABCIndexClass)) if not_implemented: other = other._values if isinstance(other, Period): if other.freq != self.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) result = op(other.ordinal) elif isinstance(other, cls): if other.freq != self.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) if not_implemented: return NotImplemented result = op(other.asi8) mask = self._isnan | other._isnan if mask.any(): result[mask] = nat_result return result elif other is NaT: result = np.empty(len(self.asi8), dtype=bool) result.fill(nat_result) else: other = Period(other, freq=self.freq) result = op(other.ordinal) if self.hasnans: result[self._isnan] = nat_result return result
def wrapper(self, other): op = getattr(self.asi8, opname) # We want to eventually defer to the Series or PeriodIndex (which will # return here with an unboxed PeriodArray). But before we do that, # we do a bit of validation on type (Period) and freq, so that our # error messages are sensible if is_list_like(other) and len(other) != len(self): raise ValueError("Lengths must match") not_implemented = isinstance(other, (ABCSeries, ABCIndexClass)) if not_implemented: other = other._values if isinstance(other, Period): self._check_compatible_with(other) result = op(other.ordinal) elif isinstance(other, cls): self._check_compatible_with(other) if not_implemented: return NotImplemented result = op(other.asi8) mask = self._isnan | other._isnan if mask.any(): result[mask] = nat_result return result elif other is NaT: result = np.empty(len(self.asi8), dtype=bool) result.fill(nat_result) else: other = Period(other, freq=self.freq) result = op(other.ordinal) if self._hasnans: result[self._isnan] = nat_result return result
def get_loc(self, key, method=None, tolerance=None): """ Get integer location for requested label Returns ------- loc : int """ try: return self._engine.get_loc(key) except KeyError: if is_integer(key): raise try: asdt, parsed, reso = parse_time_string(key, self.freq) key = asdt except TypeError: pass except DateParseError: # A string with invalid format raise KeyError("Cannot interpret '{}' as period".format(key)) try: key = Period(key, freq=self.freq) except ValueError: # we cannot construct the Period # as we have an invalid type raise KeyError(key) try: ordinal = iNaT if key is NaT else key.ordinal if tolerance is not None: tolerance = self._convert_tolerance(tolerance, np.asarray(key)) return self._int64index.get_loc(ordinal, method, tolerance) except KeyError: raise KeyError(key)
def _maybe_cast_slice_bound(self, label, side, kind): """ If label is a string or a datetime, cast it to Period.ordinal according to resolution. Parameters ---------- label : object side : {'left', 'right'} kind : {'ix', 'loc', 'getitem'} Returns ------- bound : Period or object Notes ----- Value of `side` parameter should be validated in caller. """ assert kind in ["ix", "loc", "getitem"] if isinstance(label, datetime): return Period(label, freq=self.freq) elif isinstance(label, str): try: _, parsed, reso = parse_time_string(label, self.freq) bounds = self._parsed_string_to_bounds(reso, parsed) return bounds[0 if side == "left" else 1] except ValueError: # string cannot be parsed as datetime-like # TODO: we need tests for this case raise KeyError(label) elif is_integer(label) or is_float(label): self._invalid_indexer("slice", label) return label
def get_value(self, series, key): """ Fast lookup of value from 1-dimensional ndarray. Only use this if you know what you're doing """ if is_integer(key): return series.iat[key] if isinstance(key, str): try: loc = self._get_string_slice(key) return series[loc] except (TypeError, ValueError): pass asdt, reso = parse_time_string(key, self.freq) grp = resolution.Resolution.get_freq_group(reso) freqn = resolution.get_freq_group(self.freq) # _get_string_slice will handle cases where grp < freqn assert grp >= freqn if grp == freqn: key = Period(asdt, freq=self.freq) loc = self.get_loc(key) return series.iloc[loc] else: raise KeyError(key) elif isinstance(key, Period) or key is NaT: ordinal = key.ordinal if key is not NaT else NaT.value loc = self._engine.get_loc(ordinal) return series[loc] # slice, PeriodIndex, np.ndarray, List[Period] value = Index.get_value(self, series, key) return com.maybe_box(self, value, series, key)
def _parsed_string_to_bounds(self, reso, parsed): if reso == 'year': t1 = Period(year=parsed.year, freq='A') elif reso == 'month': t1 = Period(year=parsed.year, month=parsed.month, freq='M') elif reso == 'quarter': q = (parsed.month - 1) // 3 + 1 t1 = Period(year=parsed.year, quarter=q, freq='Q-DEC') elif reso == 'day': t1 = Period(year=parsed.year, month=parsed.month, day=parsed.day, freq='D') elif reso == 'hour': t1 = Period(year=parsed.year, month=parsed.month, day=parsed.day, hour=parsed.hour, freq='H') elif reso == 'minute': t1 = Period(year=parsed.year, month=parsed.month, day=parsed.day, hour=parsed.hour, minute=parsed.minute, freq='T') elif reso == 'second': t1 = Period(year=parsed.year, month=parsed.month, day=parsed.day, hour=parsed.hour, minute=parsed.minute, second=parsed.second, freq='S') else: raise KeyError(reso) return (t1.asfreq(self.freq, how='start'), t1.asfreq(self.freq, how='end'))
def _format_coord(freq, t, y): return "t = {0} y = {1:8f}".format(Period(ordinal=int(t), freq=freq), y)
def _format_coord(freq, t, y): time_period = Period(ordinal=int(t), freq=freq) return f"t = {time_period} y = {y:8f}"
def wrapper(self, other): ordinal_op = getattr(self.asi8, opname) if is_list_like(other) and len(other) != len(self): raise ValueError("Lengths must match") if isinstance(other, str): try: other = self._scalar_from_string(other) except ValueError: # string that can't be parsed as Period return invalid_comparison(self, other, op) elif isinstance(other, int): # TODO: sure we want to allow this? we dont for DTA/TDA # 2 tests rely on this other = Period(other, freq=self.freq) result = ordinal_op(other.ordinal) if isinstance(other, Period): self._check_compatible_with(other) result = ordinal_op(other.ordinal) elif other is NaT: result = np.empty(len(self.asi8), dtype=bool) result.fill(nat_result) elif not is_list_like(other): return invalid_comparison(self, other, op) else: if isinstance(other, list): # TODO: could use pd.Index to do inference? other = np.array(other) if not isinstance(other, (np.ndarray, cls)): return invalid_comparison(self, other, op) if is_object_dtype(other): with np.errstate(all="ignore"): result = ops.comp_method_OBJECT_ARRAY( op, self.astype(object), other ) o_mask = isna(other) elif not is_period_dtype(other): # e.g. is_timedelta64_dtype(other) return invalid_comparison(self, other, op) else: assert isinstance(other, cls), type(other) self._check_compatible_with(other) result = ordinal_op(other.asi8) o_mask = other._isnan if o_mask.any(): result[o_mask] = nat_result if self._hasnans: result[self._isnan] = nat_result return result
def _scalar_from_string(self, value: str) -> Period: return Period(value, freq=self.freq)
def setup(self, freq): self.per = Period("2012-06-01", freq=freq)
def time_period_constructor(self, freq, is_offset): Period("2012-06-01", freq=freq)
def get_loc(self, key, method=None, tolerance=None): """ Get integer location for requested label. Parameters ---------- key : Period, NaT, str, or datetime String or datetime key must be parseable as Period. Returns ------- loc : int or ndarray[int64] Raises ------ KeyError Key is not present in the index. TypeError If key is listlike or otherwise not hashable. """ orig_key = key if not is_scalar(key): raise InvalidIndexError(key) if isinstance(key, str): try: loc = self._get_string_slice(key) return loc except (TypeError, ValueError): pass try: asdt, reso = parse_time_string(key, self.freq) except DateParseError as err: # A string with invalid format raise KeyError(f"Cannot interpret '{key}' as period") from err grp = resolution.Resolution.get_freq_group(reso) freqn = resolution.get_freq_group(self.freq) # _get_string_slice will handle cases where grp < freqn assert grp >= freqn if grp == freqn: key = Period(asdt, freq=self.freq) loc = self.get_loc(key, method=method, tolerance=tolerance) return loc elif method is None: raise KeyError(key) else: key = asdt elif is_integer(key): # Period constructor will cast to string, which we dont want raise KeyError(key) try: key = Period(key, freq=self.freq) except ValueError as err: # we cannot construct the Period raise KeyError(orig_key) from err try: return Index.get_loc(self, key, method, tolerance) except KeyError as err: raise KeyError(orig_key) from err
def _scalar_from_string(self, value): # type: (str) -> Period return Period(value, freq=self.freq)