def wrapper(self, other): op = getattr(self._ndarray_values, opname) 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, PeriodArrayMixin): if other.freq != self.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) result = op(other._ndarray_values) mask = self._isnan | other._isnan if mask.any(): result[mask] = nat_result return result elif other is NaT: result = np.empty(len(self._ndarray_values), 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 _add_offset(self, other): assert not isinstance(other, Tick) base = frequencies.get_base_alias(other.rule_code) if base != self.freq.rule_code: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) return self.shift(other.n)
def __init__(self, values, freq=None, dtype=None, copy=False): freq = dtl.validate_dtype_freq(dtype, freq) if freq is not None: freq = Period._maybe_convert_freq(freq) if isinstance(values, ABCSeries): values = values._values if not isinstance(values, type(self)): raise TypeError("Incorrect dtype") elif isinstance(values, ABCPeriodIndex): values = values._values if isinstance(values, type(self)): if freq is not None and freq != values.freq: msg = DIFFERENT_FREQ_INDEX.format(values.freq.freqstr, freq.freqstr) raise IncompatibleFrequency(msg) values, freq = values._data, values.freq values = np.array(values, dtype='int64', copy=copy) self._data = values if freq is None: raise ValueError('freq is not specified and cannot be inferred') self._dtype = PeriodDtype(freq)
def _assert_can_do_setop(self, other): super(PeriodIndex, self)._assert_can_do_setop(other) if not isinstance(other, PeriodIndex): raise ValueError('can only call with other PeriodIndex-ed objects') if self.freq != other.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg)
def __setitem__( self, key, # type: Union[int, Sequence[int], Sequence[bool], slice] value # type: Union[NaTType, Period, Sequence[Period]] ): # type: (...) -> None # n.b. the type on `value` is a bit too restrictive. # we also accept a sequence of stuff coercible to a PeriodArray # by period_array, which includes things like ndarray[object], # ndarray[datetime64ns]. I think ndarray[int] / ndarray[str] won't # work, since the freq can't be inferred. if is_list_like(value): is_slice = isinstance(key, slice) if (not is_slice and len(key) != len(value) and not com.is_bool_indexer(key)): msg = ("shape mismatch: value array of length '{}' does not " "match indexing result of length '{}'.") raise ValueError(msg.format(len(key), len(value))) if not is_slice and len(key) == 0: return value = period_array(value) if self.freqstr != value.freqstr: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, value.freqstr) raise IncompatibleFrequency(msg) value = value.asi8 elif isinstance(value, Period): if self.freqstr != value.freqstr: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, value.freqstr) raise IncompatibleFrequency(msg) value = value.ordinal elif isna(value): value = iNaT else: msg = ("'value' should be a 'Period', 'NaT', or array of those. " "Got '{}' instead.".format(type(value).__name__)) raise TypeError(msg) self._data[key] = value
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 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 _add_offset(self, other): assert not isinstance(other, Tick) base = frequencies.get_base_alias(other.rule_code) if base != self.freq.rule_code: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) # Note: when calling parent class's _add_timedeltalike_scalar, # it will call delta_to_nanoseconds(delta). Because delta here # is an integer, delta_to_nanoseconds will return it unchanged. result = super(PeriodArray, self)._add_timedeltalike_scalar(other.n) return type(self)(result, freq=self.freq)
def _validate_fill_value(self, fill_value): if isna(fill_value): fill_value = iNaT elif isinstance(fill_value, Period): if fill_value.freq != self.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freq.freqstr, fill_value.freqstr) raise IncompatibleFrequency(msg) fill_value = fill_value.ordinal else: raise ValueError("'fill_value' should be a Period. " "Got '{got}'.".format(got=fill_value)) return fill_value
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 get_indexer(self, target, method=None, limit=None, tolerance=None): target = ensure_index(target) if hasattr(target, 'freq') and target.freq != self.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, target.freqstr) raise IncompatibleFrequency(msg) if isinstance(target, PeriodIndex): target = target.asi8 if tolerance is not None: tolerance = self._convert_tolerance(tolerance, target) return Index.get_indexer(self._int64index, target, method, limit, tolerance)
def get_indexer(self, target, method=None, limit=None, tolerance=None): target = _ensure_index(target) if hasattr(target, 'freq') and target.freq != self.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, target.freqstr) raise IncompatibleFrequency(msg) if isinstance(target, PeriodIndex): target = target.asi8 if tolerance is not None: tolerance = self._convert_tolerance(tolerance, target) return Index.get_indexer(self._int64index, target, method, limit, tolerance)
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 _sub_period(self, other): # If the operation is well-defined, we return an object-Index # of DateOffsets. Null entries are filled with pd.NaT if self.freq != other.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) asi8 = self.asi8 new_data = asi8 - other.ordinal new_data = np.array([self.freq * x for x in new_data]) if self.hasnans: new_data[self._isnan] = NaT return new_data
def _maybe_convert_timedelta(self, other): """ Convert timedelta-like input to an integer multiple of self.freq Parameters ---------- other : timedelta, np.timedelta64, DateOffset, int, np.ndarray Returns ------- converted : int, np.ndarray[int64] Raises ------ IncompatibleFrequency : if the input cannot be written as a multiple of self.freq. Note IncompatibleFrequency subclasses ValueError. """ if isinstance( other, (timedelta, np.timedelta64, Tick, np.ndarray)): offset = frequencies.to_offset(self.freq.rule_code) if isinstance(offset, Tick): if isinstance(other, np.ndarray): nanos = np.vectorize(delta_to_nanoseconds)(other) else: nanos = delta_to_nanoseconds(other) offset_nanos = delta_to_nanoseconds(offset) check = np.all(nanos % offset_nanos == 0) if check: return nanos // offset_nanos elif isinstance(other, DateOffset): freqstr = other.rule_code base = frequencies.get_base_alias(freqstr) if base == self.freq.rule_code: return other.n msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) elif lib.is_integer(other): # integer is passed to .shift via # _add_datetimelike_methods basically # but ufunc may pass integer to _add_delta return other # raise when input doesn't have freq msg = "Input has different freq from {cls}(freq={freqstr})" raise IncompatibleFrequency(msg.format(cls=type(self).__name__, freqstr=self.freqstr))
def _maybe_convert_timedelta(self, other): """ Convert timedelta-like input to an integer multiple of self.freq Parameters ---------- other : timedelta, np.timedelta64, DateOffset, int, np.ndarray Returns ------- converted : int, np.ndarray[int64] Raises ------ IncompatibleFrequency : if the input cannot be written as a multiple of self.freq. Note IncompatibleFrequency subclasses ValueError. """ if isinstance( other, (timedelta, np.timedelta64, Tick, np.ndarray)): offset = frequencies.to_offset(self.freq.rule_code) if isinstance(offset, Tick): if isinstance(other, np.ndarray): nanos = np.vectorize(delta_to_nanoseconds)(other) else: nanos = delta_to_nanoseconds(other) offset_nanos = delta_to_nanoseconds(offset) check = np.all(nanos % offset_nanos == 0) if check: return nanos // offset_nanos elif isinstance(other, DateOffset): freqstr = other.rule_code base = frequencies.get_base_alias(freqstr) if base == self.freq.rule_code: return other.n msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) elif lib.is_integer(other): # integer is passed to .shift via # _add_datetimelike_methods basically # but ufunc may pass integer to _add_delta return other # raise when input doesn't have freq msg = "Input has different freq from {cls}(freq={freqstr})" raise IncompatibleFrequency(msg.format(cls=type(self).__name__, freqstr=self.freqstr))
def take(self, indices, allow_fill=False, fill_value=None): if allow_fill: if isna(fill_value): fill_value = iNaT elif isinstance(fill_value, Period): if self.freq != fill_value.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freq.freqstr, fill_value.freqstr) raise IncompatibleFrequency(msg) fill_value = fill_value.ordinal else: msg = "'fill_value' should be a Period. Got '{}'." raise ValueError(msg.format(fill_value)) new_values = algos.take(self._data, indices, allow_fill=allow_fill, fill_value=fill_value) return type(self)(new_values, self.freq)
def take(self, indices, allow_fill=False, fill_value=None): if allow_fill: if isna(fill_value): fill_value = iNaT elif isinstance(fill_value, Period): if self.freq != fill_value.freq: msg = DIFFERENT_FREQ_INDEX.format( self.freq.freqstr, fill_value.freqstr ) raise IncompatibleFrequency(msg) fill_value = fill_value.ordinal else: msg = "'fill_value' should be a Period. Got '{}'." raise ValueError(msg.format(fill_value)) new_values = algos.take(self._data, indices, allow_fill=allow_fill, fill_value=fill_value) return type(self)(new_values, self.freq)
def __init__(self, values, freq=None, copy=False): if freq is not None: freq = Period._maybe_convert_freq(freq) if isinstance(values, ABCSeries): values = values._values if not isinstance(values, type(self)): raise TypeError("Incorrect dtype") elif isinstance(values, ABCPeriodIndex): values = values._values if isinstance(values, type(self)): if freq is not None and freq != values.freq: msg = DIFFERENT_FREQ_INDEX.format(values.freq.freqstr, freq.freqstr) raise IncompatibleFrequency(msg) values, freq = values._data, values.freq values = np.array(values, dtype='int64', copy=copy) self._data = values if freq is None: raise ValueError('freq is not specified and cannot be inferred') self._dtype = PeriodDtype(freq)
def _sub_period_array(self, other): """ Subtract a Period Array/Index from self. This is only valid if self is itself a Period Array/Index, raises otherwise. Both objects must have the same frequency. Parameters ---------- other : PeriodIndex or PeriodArray Returns ------- result : np.ndarray[object] Array of DateOffset objects; nulls represented by NaT """ if not is_period_dtype(self): raise TypeError("cannot subtract {dtype}-dtype from {cls}".format( dtype=other.dtype, cls=type(self).__name__)) if len(self) != len(other): raise ValueError("cannot subtract arrays/indices of " "unequal length") if self.freq != other.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) new_values = checked_add_with_arr(self.asi8, -other.asi8, arr_mask=self._isnan, b_mask=other._isnan) new_values = np.array([self.freq * x for x in new_values]) if self.hasnans or other.hasnans: mask = (self._isnan) | (other._isnan) new_values[mask] = NaT return new_values
def _sub_period_array(self, other): """ Subtract a Period Array/Index from self. This is only valid if self is itself a Period Array/Index, raises otherwise. Both objects must have the same frequency. Parameters ---------- other : PeriodIndex or PeriodArray Returns ------- result : np.ndarray[object] Array of DateOffset objects; nulls represented by NaT """ if not is_period_dtype(self): raise TypeError("cannot subtract {dtype}-dtype to {cls}" .format(dtype=other.dtype, cls=type(self).__name__)) if not len(self) == len(other): raise ValueError("cannot subtract arrays/indices of " "unequal length") if self.freq != other.freq: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) new_values = checked_add_with_arr(self.asi8, -other.asi8, arr_mask=self._isnan, b_mask=other._isnan) new_values = np.array([self.freq * x for x in new_values]) if self.hasnans or other.hasnans: mask = (self._isnan) | (other._isnan) new_values[mask] = NaT return new_values
def _check_compatible_with(self, other): if self.freqstr != other.freqstr: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg)
def _check_compatible_with(self, other): if self.freqstr != other.freqstr: msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg)