Esempio n. 1
0
    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")
Esempio n. 2
0
    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)
Esempio n. 3
0
    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
Esempio n. 4
0
    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)
Esempio n. 5
0
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)
Esempio n. 6
0
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)
Esempio n. 7
0
    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
Esempio n. 8
0
    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)
Esempio n. 9
0
    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)
Esempio n. 10
0
    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)
Esempio n. 11
0
    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)
Esempio n. 12
0
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)
Esempio n. 13
0
    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)
Esempio n. 14
0
    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)
Esempio n. 15
0
 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