Пример #1
0
    def to_absolute_int(self, start, cutoff=None):
        """Return absolute values as zero-based integer index starting from `start`.

        Parameters
        ----------
        start : pd.Period, pd.Timestamp, int
            Start value returned as zero.
        cutoff : pd.Period, pd.Timestamp, int, optional (default=None)
            Cutoff value required to convert a relative forecasting
            horizon to an absolute one (and vice versa).

        Returns
        -------
        fh : ForecastingHorizon
            Absolute representation of forecasting horizon as zero-based
            integer index.
        """
        # We here check the start value, the cutoff value is checked when we use it
        # to convert the horizon to the absolute representation below
        absolute = self.to_absolute(cutoff).to_pandas()
        _check_start(start, absolute)

        # Note: We should here also coerce to periods for more reliable arithmetic
        # operations as in `to_relative` but currently doesn't work with
        # `update_predict` and incomplete time indices where the `freq` information
        # is lost, see comment on issue #534
        integers = absolute - start

        if isinstance(absolute, (pd.PeriodIndex, pd.DatetimeIndex)):
            integers = _coerce_duration_to_int(integers,
                                               freq=_get_freq(cutoff))

        return self._new(integers, is_relative=False)
Пример #2
0
 def _align_seasonal(self, y):
     """Align seasonal components with y's time index"""
     shift = (-_get_duration(
         y.index[0],
         self._y_index[0],
         coerce_to_int=True,
         unit=_get_freq(self._y_index),
     ) % self.sp)
     return np.resize(np.roll(self.seasonal_, shift=shift), y.shape[0])
Пример #3
0
def _to_relative(fh: ForecastingHorizon, cutoff=None) -> ForecastingHorizon:
    """Return forecasting horizon values relative to a cutoff.

    Parameters
    ----------
    fh : ForecastingHorizon
    cutoff : pd.Period, pd.Timestamp, int, optional (default=None)
        Cutoff value required to convert a relative forecasting
        horizon to an absolute one (and vice versa).

    Returns
    -------
    fh : ForecastingHorizon
        Relative representation of forecasting horizon.
    """
    if fh.is_relative:
        return fh._new()

    else:
        absolute = fh.to_pandas()
        _check_cutoff(cutoff, absolute)

        # We cannot use the freq from the ForecastingHorizon itself (or its
        # wrapped pd.DatetimeIndex) because it may be none for non-regular
        # indices, so instead we use the freq of cutoff.
        freq = _get_freq(cutoff)

        if isinstance(absolute, pd.DatetimeIndex):
            # coerce to pd.Period for reliable arithmetics and computations of
            # time deltas
            absolute = _coerce_to_period(absolute, freq)
            cutoff = _coerce_to_period(cutoff, freq)

        # TODO: Replace when we upgrade our lower pandas bound
        #  to a version where this is fixed
        # Compute relative values
        # The following line circumvents the bug in pandas
        # periods = pd.period_range(start="2021-01-01", periods=3, freq="2H")
        # periods - periods[0]
        # Out: Index([<0 * Hours>, <4 * Hours>, <8 * Hours>], dtype = 'object')
        # [v - periods[0] for v in periods]
        # Out: Index([<0 * Hours>, <2 * Hours>, <4 * Hours>], dtype='object')
        # TODO: v0.12.0: Check if this comment below can be removed,
        # so check if pandas has released the fix to PyPI:
        # This bug was reported: https://github.com/pandas-dev/pandas/issues/45999
        # and fixed: https://github.com/pandas-dev/pandas/pull/46006
        # Most likely it will be released with pandas 1.5
        # Once the bug is fixed the line should simply be:
        # relative = absolute - cutoff
        relative = pd.Index([date - cutoff for date in absolute])

        # Coerce durations (time deltas) into integer values for given frequency
        if isinstance(absolute, (pd.PeriodIndex, pd.DatetimeIndex)):
            relative = _coerce_duration_to_int(relative, freq=freq)

        return fh._new(relative, is_relative=True)
Пример #4
0
def test_get_freq():
    """Test whether get_freq runs without error."""
    x = pd.Series(
        index=pd.date_range(start="2017-01-01", periods=700, freq="W"),
        data=np.random.randn(700),
    )
    x1 = x.index
    x2 = x.resample("W").sum().index
    x3 = pd.Series(index=[
        datetime.datetime(2017, 1, 1) + datetime.timedelta(days=int(i))
        for i in np.arange(1, 100, 7)
    ]).index
    x4 = [
        datetime.datetime(2017, 1, 1) + datetime.timedelta(days=int(i))
        for i in np.arange(1, 100, 7)
    ]
    assert _get_freq(x1) == "W"
    assert _get_freq(x2) == "W"
    assert _get_freq(x3) is None
    assert _get_freq(x4) is None
Пример #5
0
    def to_relative(self, cutoff=None):
        """Return forecasting horizon values relative to a cutoff.

        Parameters
        ----------
        cutoff : pd.Period, pd.Timestamp, int, optional (default=None)
            Cutoff value required to convert a relative forecasting
            horizon to an absolute one (and vice versa).

        Returns
        -------
        fh : ForecastingHorizon
            Relative representation of forecasting horizon.
        """
        if self.is_relative:
            return self._new()

        else:
            absolute = self.to_pandas()
            _check_cutoff(cutoff, absolute)

            if isinstance(absolute, pd.DatetimeIndex):
                # We cannot use the freq from the the ForecastingHorizon itself (or its
                # wrapped pd.DatetimeIndex) because it may be none for non-regular
                # indices, so instead we use the freq of cutoff.
                freq = _get_freq(cutoff)

                # coerce to pd.Period for reliable arithmetics and computations of
                # time deltas
                absolute = _coerce_to_period(absolute, freq)
                cutoff = _coerce_to_period(cutoff, freq)

            # Compute relative values
            relative = absolute - cutoff

            # Coerce durations (time deltas) into integer values for given frequency
            if isinstance(absolute, (pd.PeriodIndex, pd.DatetimeIndex)):
                relative = _coerce_duration_to_int(relative,
                                                   freq=_get_freq(cutoff))

            return self._new(relative, is_relative=True)
Пример #6
0
def test_coerce_duration_to_int(duration):
    ret = _coerce_duration_to_int(duration, freq=_get_freq(duration))

    # check output type is always integer
    assert type(ret) in (pd.Int64Index, np.integer, int)

    # check result
    if isinstance(duration, pd.Index):
        np.testing.assert_array_equal(ret, range(3))

    if isinstance(duration, pd.tseries.offsets.BaseOffset):
        assert ret == 3
Пример #7
0
def test_coerce_duration_to_int(duration):
    """Test coercion of duration to int."""
    ret = _coerce_duration_to_int(duration, freq=_get_freq(duration))

    # check output type is always integer
    assert (type(ret) in (np.integer, int)) or is_integer_index(ret)

    # check result
    if isinstance(duration, pd.Index):
        np.testing.assert_array_equal(ret, range(3))

    if isinstance(duration, pd.tseries.offsets.BaseOffset):
        assert ret == 3
Пример #8
0
def _coerce_to_period(x, freq=None):
    """Helper function to coerce pd.Timestamp to pd.Period or pd.DatetimeIndex to
    pd.PeriodIndex for more reliable arithmetic operations with time indices"""
    if freq is None:
        freq = _get_freq(x)
    try:
        return x.to_period(freq)
    except (ValueError, AttributeError) as e:
        msg = str(e)
        if "Invalid frequency" in msg or "_period_dtype_code" in msg:
            raise ValueError(
                "Invalid frequency. Please select a frequency that can "
                "be converted to a regular `pd.PeriodIndex`. For other "
                "frequencies, basic arithmetic operation to compute "
                "durations currently do not work reliably.")
        else:
            raise
Пример #9
0
def test_coerce_duration_to_int_with_non_allowed_durations(duration):
    """Test coercion of duration to int."""
    with pytest.raises(ValueError, match="frequency is missing"):
        _coerce_duration_to_int(duration, freq=_get_freq(duration))