def __setstate__(self, state): """Necessary for making this object picklable""" if isinstance(state, dict): super(PeriodIndex, self).__setstate__(state) elif isinstance(state, tuple): # < 0.15 compat if len(state) == 2: nd_state, own_state = state data = np.empty(nd_state[1], dtype=nd_state[2]) np.ndarray.__setstate__(data, nd_state) # backcompat freq = Period._maybe_convert_freq(own_state[1]) else: # pragma: no cover data = np.empty(state) np.ndarray.__setstate__(self, state) freq = None # ? data = PeriodArray(data, freq=freq) self._data = data else: raise Exception("invalid pickle state")
def _shallow_copy(self, values=None, **kwargs): # TODO: simplify, figure out type of values if values is None: values = self._data if isinstance(values, type(self)): values = values._values if not isinstance(values, PeriodArray): if (isinstance(values, np.ndarray) and is_integer_dtype(values.dtype)): values = PeriodArray(values, freq=self.freq) else: # in particular, I would like to avoid period_array here. # Some people seem to be calling use with unexpected types # Index.difference -> ndarray[Period] # DatetimelikeIndexOpsMixin.repeat -> ndarray[ordinal] # I think that once all of Datetime* are EAs, we can simplify # this quite a bit. values = period_array(values, freq=self.freq) # I don't like overloading shallow_copy with freq changes. # See if it's used anywhere outside of test_resample_empty_dataframe attributes = self._get_attributes_dict() freq = kwargs.pop("freq", None) if freq: values = values.asfreq(freq) attributes.pop("freq", None) attributes.update(kwargs) if not len(values) and 'dtype' not in kwargs: attributes['dtype'] = self.dtype return self._simple_new(values, **attributes)
def _simple_new(cls, values, name=None, freq=None, **kwargs): """ Create a new PeriodIndex. Parameters ---------- values : PeriodArray, PeriodIndex, Index[int64], ndarray[int64] Values that can be converted to a PeriodArray without inference or coercion. """ # TODO: raising on floats is tested, but maybe not useful. # Should the callers know not to pass floats? # At the very least, I think we can ensure that lists aren't passed. if isinstance(values, list): values = np.asarray(values) if is_float_dtype(values): raise TypeError("PeriodIndex._simple_new does not accept floats.") values = PeriodArray(values, freq=freq) if not isinstance(values, PeriodArray): raise TypeError("PeriodIndex._simple_new only accepts PeriodArray") result = object.__new__(cls) result._data = values result.name = name result._reset_identity() return result
def _shallow_copy(self, values=None, **kwargs): # TODO: simplify, figure out type of values if values is None: values = self._data if isinstance(values, type(self)): values = values._values if not isinstance(values, PeriodArray): if isinstance(values, np.ndarray) and is_integer_dtype(values.dtype): values = PeriodArray(values, freq=self.freq) else: # in particular, I would like to avoid period_array here. # Some people seem to be calling use with unexpected types # Index.difference -> ndarray[Period] # DatetimelikeIndexOpsMixin.repeat -> ndarray[ordinal] # I think that once all of Datetime* are EAs, we can simplify # this quite a bit. values = period_array(values, freq=self.freq) # We don't allow changing `freq` in _shallow_copy. validate_dtype_freq(self.dtype, kwargs.get("freq")) attributes = self._get_attributes_dict() attributes.update(kwargs) if not len(values) and "dtype" not in kwargs: attributes["dtype"] = self.dtype return self._simple_new(values, **attributes)
def _new_PeriodIndex(cls, **d): # GH13277 for unpickling values = d.pop('data') if values.dtype == 'int64': freq = d.pop('freq', None) values = PeriodArray(values, freq=freq) return cls._simple_new(values, **d) else: return cls(values, **d)
def _new_PeriodIndex(cls, **d): # GH13277 for unpickling values = d.pop("area_data") if values.dtype == "int64": freq = d.pop("freq", None) values = PeriodArray(values, freq=freq) return cls._simple_new(values, **d) else: return cls(values, **d)
def _add_period(self, other: Period): """ Add a Period object. """ # We will wrap in a PeriodArray and defer to the reversed operation from pandas.core.arrays.period import PeriodArray i8vals = np.broadcast_to(other.ordinal, self.shape) oth = PeriodArray(i8vals, freq=other.freq) return oth + self
def _maybe_box_as_values(self, values, **attribs): """Box an array of ordinals to a PeriodArray This is purely for compatibility between PeriodIndex and Datetime/TimedeltaIndex. Once these are all backed by an ExtensionArray, this can be removed """ # TODO(DatetimeArray): remove freq = attribs['freq'] return PeriodArray(values, freq=freq)
def __new__(cls, data=None, ordinal=None, freq=None, start=None, end=None, periods=None, tz=None, dtype=None, copy=False, name=None, **fields): valid_field_set = {'year', 'month', 'day', 'quarter', 'hour', 'minute', 'second'} if not set(fields).issubset(valid_field_set): raise TypeError('__new__() got an unexpected keyword argument {}'. format(list(set(fields) - valid_field_set)[0])) if name is None and hasattr(data, 'name'): name = data.name if data is None and ordinal is None: # range-based. data, freq = PeriodArray._generate_range(start, end, periods, freq, fields) data = PeriodArray(data, freq=freq) else: freq = dtl.validate_dtype_freq(dtype, freq) # PeriodIndex allow PeriodIndex(period_index, freq=different) # Let's not encourage that kind of behavior in PeriodArray. if freq and isinstance(data, cls) and data.freq != freq: # TODO: We can do some of these with no-copy / coercion? # e.g. D -> 2D seems to be OK data = data.asfreq(freq) if data is None and ordinal is not None: # we strangely ignore `ordinal` if data is passed. ordinal = np.asarray(ordinal, dtype=np.int64) data = PeriodArray(ordinal, freq) else: # don't pass copy here, since we copy later. data = period_array(data=data, freq=freq) if copy: data = data.copy() return cls._simple_new(data, name=name)
def _shallow_copy(self, values=None, name: Label = no_default): # TODO: simplify, figure out type of values name = name if name is not no_default else self.name if values is None: values = self._data if isinstance(values, type(self)): values = values._data if not isinstance(values, PeriodArray): if isinstance(values, np.ndarray) and values.dtype == "i8": values = PeriodArray(values, freq=self.freq) else: # GH#30713 this should never be reached raise TypeError(type(values), getattr(values, "dtype", None)) return self._simple_new(values, name=name)
def _shallow_copy(self, values=None, **kwargs): # TODO: simplify, figure out type of values if values is None: values = self._data if isinstance(values, type(self)): values = values._data if not isinstance(values, PeriodArray): if isinstance(values, np.ndarray) and values.dtype == "i8": values = PeriodArray(values, freq=self.freq) else: # GH#30713 this should never be reached raise TypeError(type(values), getattr(values, "dtype", None)) # We don't allow changing `freq` in _shallow_copy. validate_dtype_freq(self.dtype, kwargs.get("freq")) attributes = self._get_attributes_dict() attributes.update(kwargs) if not len(values) and "dtype" not in kwargs: attributes["dtype"] = self.dtype return self._simple_new(values, **attributes)
def period_range( start=None, end=None, periods=None, freq=None, name=None ) -> PeriodIndex: """ Return a fixed frequency PeriodIndex. The day (calendar) is the default frequency. Parameters ---------- start : str or period-like, default None Left bound for generating periods. end : str or period-like, default None Right bound for generating periods. periods : int, default None Number of periods to generate. freq : str or DateOffset, optional Frequency alias. By default the freq is taken from `start` or `end` if those are Period objects. Otherwise, the default is ``"D"`` for daily frequency. name : str, default None Name of the resulting PeriodIndex. Returns ------- PeriodIndex Notes ----- Of the three parameters: ``start``, ``end``, and ``periods``, exactly two must be specified. To learn more about the frequency strings, please see `this link <https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases>`__. Examples -------- >>> pd.period_range(start='2017-01-01', end='2018-01-01', freq='M') PeriodIndex(['2017-01', '2017-02', '2017-03', '2017-04', '2017-05', '2017-06', '2017-07', '2017-08', '2017-09', '2017-10', '2017-11', '2017-12', '2018-01'], dtype='period[M]', freq='M') If ``start`` or ``end`` are ``Period`` objects, they will be used as anchor endpoints for a ``PeriodIndex`` with frequency matching that of the ``period_range`` constructor. >>> pd.period_range(start=pd.Period('2017Q1', freq='Q'), ... end=pd.Period('2017Q2', freq='Q'), freq='M') PeriodIndex(['2017-03', '2017-04', '2017-05', '2017-06'], dtype='period[M]', freq='M') """ 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 None and (not isinstance(start, Period) and not isinstance(end, Period)): freq = "D" data, freq = PeriodArray._generate_range(start, end, periods, freq, fields={}) data = PeriodArray(data, freq=freq) return PeriodIndex(data, name=name)
def __new__(cls, data=None, ordinal=None, freq=None, start=None, end=None, periods=None, tz=None, dtype=None, copy=False, name=None, **fields): valid_field_set = { "year", "month", "day", "quarter", "hour", "minute", "second", } if not set(fields).issubset(valid_field_set): raise TypeError( "__new__() got an unexpected keyword argument {}".format( list(set(fields) - valid_field_set)[0])) if name is None and hasattr(data, "name"): name = data.name if data is None and ordinal is None: # range-based. data, freq2 = PeriodArray._generate_range(start, end, periods, freq, fields) # PeriodArray._generate range does validate that fields is # empty when really using the range-based constructor. if not fields: msg = ("Creating a PeriodIndex by passing range " "endpoints is deprecated. Use " "`pandas.period_range` instead.") # period_range differs from PeriodIndex for cases like # start="2000", periods=4 # PeriodIndex interprets that as A-DEC freq. # period_range interprets it as 'D' freq. cond = freq is None and ( (start and not isinstance(start, Period)) or (end and not isinstance(end, Period))) if cond: msg += (" Note that the default `freq` may differ. Pass " "'freq=\"{}\"' to ensure the same output.").format( freq2.freqstr) warnings.warn(msg, FutureWarning, stacklevel=2) freq = freq2 data = PeriodArray(data, freq=freq) else: freq = validate_dtype_freq(dtype, freq) # PeriodIndex allow PeriodIndex(period_index, freq=different) # Let's not encourage that kind of behavior in PeriodArray. if freq and isinstance(data, cls) and data.freq != freq: # TODO: We can do some of these with no-copy / coercion? # e.g. D -> 2D seems to be OK data = data.asfreq(freq) if data is None and ordinal is not None: # we strangely ignore `ordinal` if data is passed. ordinal = np.asarray(ordinal, dtype=np.int64) data = PeriodArray(ordinal, freq) else: # don't pass copy here, since we copy later. data = period_array(data=data, freq=freq) if copy: data = data.copy() return cls._simple_new(data, name=name)
def __new__( cls, data=None, ordinal=None, freq=None, tz=None, dtype=None, copy=False, name=None, **fields, ): valid_field_set = { "year", "month", "day", "quarter", "hour", "minute", "second", } if not set(fields).issubset(valid_field_set): argument = list(set(fields) - valid_field_set)[0] raise TypeError( f"__new__() got an unexpected keyword argument {argument}") name = maybe_extract_name(name, data, cls) if data is None and ordinal is None: # range-based. data, freq2 = PeriodArray._generate_range(None, None, None, freq, fields) # PeriodArray._generate range does validation that fields is # empty when really using the range-based constructor. freq = freq2 data = PeriodArray(data, freq=freq) else: freq = validate_dtype_freq(dtype, freq) # PeriodIndex allow PeriodIndex(period_index, freq=different) # Let's not encourage that kind of behavior in PeriodArray. if freq and isinstance(data, cls) and data.freq != freq: # TODO: We can do some of these with no-copy / coercion? # e.g. D -> 2D seems to be OK data = data.asfreq(freq) if data is None and ordinal is not None: # we strangely ignore `ordinal` if data is passed. ordinal = np.asarray(ordinal, dtype=np.int64) data = PeriodArray(ordinal, freq) else: # don't pass copy here, since we copy later. data = period_array(data=data, freq=freq) if copy: data = data.copy() return cls._simple_new(data, name=name)
def _apply_meta(self, rawarr) -> "PeriodIndex": if not isinstance(rawarr, PeriodIndex): if not isinstance(rawarr, PeriodArray): rawarr = PeriodArray(rawarr, freq=self.freq) rawarr = PeriodIndex._simple_new(rawarr, name=self.name) return rawarr