def test_is_superperiod_subperiod(): assert (frequencies.is_superperiod(offsets.YearEnd(), offsets.MonthEnd())) assert (frequencies.is_subperiod(offsets.MonthEnd(), offsets.YearEnd())) assert (frequencies.is_superperiod(offsets.Hour(), offsets.Minute())) assert (frequencies.is_subperiod(offsets.Minute(), offsets.Hour())) assert (frequencies.is_superperiod(offsets.Second(), offsets.Milli())) assert (frequencies.is_subperiod(offsets.Milli(), offsets.Second())) assert (frequencies.is_superperiod(offsets.Milli(), offsets.Micro())) assert (frequencies.is_subperiod(offsets.Micro(), offsets.Milli())) assert (frequencies.is_superperiod(offsets.Micro(), offsets.Nano())) assert (frequencies.is_subperiod(offsets.Nano(), offsets.Micro()))
def test_is_superperiod_subperiod(): assert frequencies.is_superperiod(offsets.YearEnd(), offsets.MonthEnd()) assert frequencies.is_subperiod(offsets.MonthEnd(), offsets.YearEnd()) assert frequencies.is_superperiod(offsets.Hour(), offsets.Minute()) assert frequencies.is_subperiod(offsets.Minute(), offsets.Hour()) assert frequencies.is_superperiod(offsets.Second(), offsets.Milli()) assert frequencies.is_subperiod(offsets.Milli(), offsets.Second()) assert frequencies.is_superperiod(offsets.Milli(), offsets.Micro()) assert frequencies.is_subperiod(offsets.Micro(), offsets.Milli()) assert frequencies.is_superperiod(offsets.Micro(), offsets.Nano()) assert frequencies.is_subperiod(offsets.Nano(), offsets.Micro())
def _resample_periods(self, obj): axlabels = obj._get_axis(self.axis) # Start vs. end of period memb = axlabels.asfreq(self.freq, how=self.convention) if is_subperiod(axlabels.freq, self.freq): # Downsampling if len(memb) > 1: rng = np.arange(memb.values[0], memb.values[-1]) bins = memb.searchsorted(rng, side='right') else: bins = np.array([], dtype=np.int32) index = period_range(memb[0], memb[-1], freq=self.freq) grouper = BinGrouper(bins, index) grouped = obj.groupby(grouper, axis=self.axis) return grouped.agg(self.how) elif is_superperiod(axlabels.freq, self.freq): # Generate full range new_index = period_range(memb[0], memb[-1], freq=self.freq) # Get the fill indexer indexer = memb.get_indexer(new_index, method=self.fill_method, limit=self.limit) return _take_new_index(obj, indexer, new_index, axis=self.axis) else: raise ValueError('Frequency %s cannot be resampled to %s' % (axlabels.freq, self.freq))
def _upsample(self, method, limit=None): """ method : string {'backfill', 'bfill', 'pad', 'ffill'} method for upsampling limit : int, default None Maximum size gap to fill when reindexing See also -------- .fillna """ # we may need to actually resample as if we are timestamps if self.kind == "timestamp": return super(PeriodIndexResampler, self)._upsample(method, limit=limit) ax = self.ax obj = self.obj new_index = self._get_new_index() if len(new_index) == 0: return self._wrap_result(new_index) if not is_superperiod(ax.freq, self.freq): return self.asfreq() # Start vs. end of period memb = ax.asfreq(self.freq, how=self.convention) # Get the fill indexer indexer = memb.get_indexer(new_index, method=method, limit=limit) return self._wrap_result(_take_new_index(obj, indexer, new_index, axis=self.axis))
def _downsample(self, how, **kwargs): """ Downsample the cython defined function Parameters ---------- how : string / cython mapped function **kwargs : kw args passed to how function """ # we may need to actually resample as if we are timestamps if self.kind == 'timestamp': return super(PeriodIndexResampler, self)._downsample(how, **kwargs) how = self._is_cython_func(how) or how ax = self.ax if is_subperiod(ax.freq, self.freq): # Downsampling return self._groupby_and_aggregate(how, grouper=self.grouper) elif is_superperiod(ax.freq, self.freq): if how == 'ohlc': # GH #13083 # upsampling to subperiods is handled as an asfreq, which works # for pure aggregating/reducing methods # OHLC reduces along the time dimension, but creates multiple # values for each period -> handle by _groupby_and_aggregate() return self._groupby_and_aggregate(how, grouper=self.grouper) return self.asfreq() elif ax.freq == self.freq: return self.asfreq() raise IncompatibleFrequency( 'Frequency {} cannot be resampled to {}, as they are not ' 'sub or super periods'.format(ax.freq, self.freq))
def _maybe_resample(series, ax, kwargs): # resample against axes freq if necessary freq, ax_freq = _get_freq(ax, series) if freq is None: # pragma: no cover raise ValueError('Cannot use dynamic axis without frequency info') # Convert DatetimeIndex to PeriodIndex if isinstance(series.index, DatetimeIndex): series = series.to_period(freq=freq) if ax_freq is not None and freq != ax_freq: if frequencies.is_superperiod(freq, ax_freq): # upsample input series = series.copy() series.index = series.index.asfreq(ax_freq, how='s') freq = ax_freq elif _is_sup(freq, ax_freq): # one is weekly how = kwargs.pop('how', 'last') series = getattr(series.resample('D'), how)().dropna() series = getattr(series.resample(ax_freq), how)().dropna() freq = ax_freq elif frequencies.is_subperiod(freq, ax_freq) or _is_sub(freq, ax_freq): _upsample_others(ax, freq, kwargs) ax_freq = freq else: # pragma: no cover raise ValueError('Incompatible frequency conversion') return freq, series
def _upsample(self, method, limit=None): """ method : string {'backfill', 'bfill', 'pad', 'ffill'} method for upsampling limit : int, default None Maximum size gap to fill when reindexing See also -------- .fillna """ # we may need to actually resample as if we are timestamps if self.kind == 'timestamp': return super(PeriodIndexResampler, self)._upsample(method, limit=limit) ax = self.ax obj = self.obj new_index = self._get_new_index() if len(new_index) == 0: return self._wrap_result(new_index) if not is_superperiod(ax.freq, self.freq): return self.asfreq() # Start vs. end of period memb = ax.asfreq(self.freq, how=self.convention) # Get the fill indexer indexer = memb.get_indexer(new_index, method=method, limit=limit) return self._wrap_result( _take_new_index(obj, indexer, new_index, axis=self.axis))
def _resample_periods(self, obj): axlabels = obj._get_axis(self.axis) if len(axlabels) == 0: new_index = PeriodIndex(data=[], freq=self.freq) return obj.reindex(new_index) else: start = axlabels[0].asfreq(self.freq, how=self.convention) end = axlabels[-1].asfreq(self.freq, how='end') new_index = period_range(start, end, freq=self.freq) # Start vs. end of period memb = axlabels.asfreq(self.freq, how=self.convention) if is_subperiod(axlabels.freq, self.freq) or self.how is not None: # Downsampling rng = np.arange(memb.values[0], memb.values[-1] + 1) bins = memb.searchsorted(rng, side='right') grouper = BinGrouper(bins, new_index) grouped = obj.groupby(grouper, axis=self.axis) return grouped.aggregate(self._agg_method) elif is_superperiod(axlabels.freq, self.freq): # Get the fill indexer indexer = memb.get_indexer(new_index, method=self.fill_method, limit=self.limit) return _take_new_index(obj, indexer, new_index, axis=self.axis) else: raise ValueError('Frequency %s cannot be resampled to %s' % (axlabels.freq, self.freq))
def _downsample(self, how, **kwargs): """ Downsample the cython defined function Parameters ---------- how : string / cython mapped function **kwargs : kw args passed to how function """ # we may need to actually resample as if we are timestamps if self.kind == "timestamp": return super(PeriodIndexResampler, self)._downsample(how, **kwargs) how = self._is_cython_func(how) or how ax = self.ax new_index = self._get_new_index() if len(new_index) == 0: return self._wrap_result(new_index) # Start vs. end of period memb = ax.asfreq(self.freq, how=self.convention) if is_subperiod(ax.freq, self.freq): # Downsampling rng = np.arange(memb.values[0], memb.values[-1] + 1) bins = memb.searchsorted(rng, side="right") grouper = BinGrouper(bins, new_index) return self._groupby_and_aggregate(grouper, how) elif is_superperiod(ax.freq, self.freq): return self.asfreq() raise ValueError("Frequency {axfreq} cannot be " "resampled to {freq}".format(axfreq=ax.freq, freq=self.freq))
def _maybe_resample(series, ax, kwargs): # resample against axes freq if necessary freq, ax_freq = _get_freq(ax, series) if freq is None: # pragma: no cover raise ValueError('Cannot use dynamic axis without frequency info') # Convert DatetimeIndex to PeriodIndex if isinstance(series.index, ABCDatetimeIndex): series = series.to_period(freq=freq) if ax_freq is not None and freq != ax_freq: if frequencies.is_superperiod(freq, ax_freq): # upsample input series = series.copy() series.index = series.index.asfreq(ax_freq, how='s') freq = ax_freq elif _is_sup(freq, ax_freq): # one is weekly how = kwargs.pop('how', 'last') series = getattr(series.resample('D'), how)().dropna() series = getattr(series.resample(ax_freq), how)().dropna() freq = ax_freq elif frequencies.is_subperiod(freq, ax_freq) or _is_sub(freq, ax_freq): _upsample_others(ax, freq, kwargs) else: # pragma: no cover raise ValueError('Incompatible frequency conversion') return freq, series
def _maybe_resample(series: "Series", ax, kwargs): # resample against axes freq if necessary freq, ax_freq = _get_freq(ax, series) if freq is None: # pragma: no cover raise ValueError("Cannot use dynamic axis without frequency info") # Convert DatetimeIndex to PeriodIndex if isinstance(series.index, ABCDatetimeIndex): series = series.to_period(freq=freq) if ax_freq is not None and freq != ax_freq: if is_superperiod(freq, ax_freq): # upsample input series = series.copy() # error: "Index" has no attribute "asfreq" series.index = series.index.asfreq( # type: ignore[attr-defined] ax_freq, how="s") freq = ax_freq elif _is_sup(freq, ax_freq): # one is weekly how = kwargs.pop("how", "last") series = getattr(series.resample("D"), how)().dropna() series = getattr(series.resample(ax_freq), how)().dropna() freq = ax_freq elif is_subperiod(freq, ax_freq) or _is_sub(freq, ax_freq): _upsample_others(ax, freq, kwargs) else: # pragma: no cover raise ValueError("Incompatible frequency conversion") return freq, series
def _resample_periods(self, obj): axlabels = obj._get_axis(self.axis) if len(axlabels) == 0: new_index = PeriodIndex(data=[], freq=self.freq) return obj.reindex(new_index) else: start = axlabels[0].asfreq(self.freq, how=self.convention) end = axlabels[-1].asfreq(self.freq, how=self.convention) new_index = period_range(start, end, freq=self.freq) # Start vs. end of period memb = axlabels.asfreq(self.freq, how=self.convention) if is_subperiod(axlabels.freq, self.freq) or self.how is not None: # Downsampling rng = np.arange(memb.values[0], memb.values[-1]) bins = memb.searchsorted(rng, side='right') grouper = BinGrouper(bins, new_index) grouped = obj.groupby(grouper, axis=self.axis) return grouped.aggregate(self._agg_method) elif is_superperiod(axlabels.freq, self.freq): # Get the fill indexer indexer = memb.get_indexer(new_index, method=self.fill_method, limit=self.limit) return _take_new_index(obj, indexer, new_index, axis=self.axis) else: raise ValueError('Frequency %s cannot be resampled to %s' % (axlabels.freq, self.freq))
def _get_time_bins(self, axis): assert (isinstance(axis, DatetimeIndex)) if len(axis) == 0: binner = labels = DatetimeIndex(data=[], freq=self.freq) return binner, [], labels first, last = _get_range_edges(axis, self.begin, self.end, self.freq, closed=self.closed, base=self.base) binner = labels = DatetimeIndex(freq=self.freq, start=first, end=last) # a little hack trimmed = False if len(binner) > 2 and binner[-2] == axis[-1]: binner = binner[:-1] trimmed = True ax_values = axis.asi8 bin_edges = binner.asi8 # Some hacks for > daily data, see #1471, #1458 if self.freq != 'D' and is_superperiod(self.freq, 'D'): day_nanos = _delta_to_nanoseconds(timedelta(1)) if self.closed == 'right': bin_edges = bin_edges + day_nanos - 1 else: bin_edges = bin_edges + day_nanos # intraday values on last day if bin_edges[-2] > ax_values[-1]: bin_edges = bin_edges[:-1] binner = binner[:-1] # general version, knowing nothing about relative frequencies bins = lib.generate_bins_dt64(ax_values, bin_edges, self.closed) if self.closed == 'right': labels = binner if self.label == 'right': labels = labels[1:] elif not trimmed: labels = labels[:-1] else: if self.label == 'right': labels = labels[1:] elif not trimmed: labels = labels[:-1] return binner, bins, labels
def _get_time_bins(self, axis): assert(isinstance(axis, DatetimeIndex)) if len(axis) == 0: binner = labels = DatetimeIndex(data=[], freq=self.freq) return binner, [], labels first, last = _get_range_edges(axis, self.begin, self.end, self.freq, closed=self.closed, base=self.base) binner = labels = DatetimeIndex(freq=self.freq, start=first, end=last) # a little hack trimmed = False if len(binner) > 2 and binner[-2] == axis[-1]: binner = binner[:-1] trimmed = True ax_values = axis.asi8 bin_edges = binner.asi8 # Some hacks for > daily data, see #1471, #1458 if self.freq != 'D' and is_superperiod(self.freq, 'D'): day_nanos = _delta_to_nanoseconds(timedelta(1)) if self.closed == 'right': bin_edges = bin_edges + day_nanos - 1 else: bin_edges = bin_edges + day_nanos # intraday values on last day if bin_edges[-2] > ax_values[-1]: bin_edges = bin_edges[:-1] binner = binner[:-1] # general version, knowing nothing about relative frequencies bins = lib.generate_bins_dt64(ax_values, bin_edges, self.closed) if self.closed == 'right': labels = binner if self.label == 'right': labels = labels[1:] elif not trimmed: labels = labels[:-1] else: if self.label == 'right': labels = labels[1:] elif not trimmed: labels = labels[:-1] return binner, bins, labels
def _adjust_bin_edges(self, binner, ax_values): # Some hacks for > daily data, see #1471, #1458, #1483 bin_edges = binner.asi8 if self.freq != 'D' and is_superperiod(self.freq, 'D'): day_nanos = _delta_to_nanoseconds(timedelta(1)) if self.closed == 'right': bin_edges = bin_edges + day_nanos - 1 # intraday values on last day if bin_edges[-2] > ax_values[-1]: bin_edges = bin_edges[:-1] binner = binner[:-1] return binner, bin_edges
def _adjust_bin_edges(self, binner, ax_values): # Some hacks for > daily data, see #1471, #1458, #1483 bin_edges = binner.asi8 if self.freq != 'D' and is_superperiod(self.freq, 'D'): day_nanos = _delta_to_nanoseconds(timedelta(1)) if self.closed == 'right': bin_edges = bin_edges + day_nanos - 1 # intraday values on last day if bin_edges[-2] > ax_values.max(): bin_edges = bin_edges[:-1] binner = binner[:-1] return binner, bin_edges
def _maybe_resample(series, ax, freq, plotf, kwargs): ax_freq = _get_ax_freq(ax) if ax_freq is not None and freq != ax_freq: if frequencies.is_superperiod(freq, ax_freq): # upsample input series = series.copy() series.index = series.index.asfreq(ax_freq, how='s') freq = ax_freq elif _is_sup(freq, ax_freq): # one is weekly how = kwargs.pop('how', 'last') series = series.resample('D', how=how).dropna() series = series.resample(ax_freq, how=how).dropna() freq = ax_freq elif frequencies.is_subperiod(freq, ax_freq) or _is_sub(freq, ax_freq): _upsample_others(ax, freq, plotf, kwargs) ax_freq = freq else: # pragma: no cover raise ValueError('Incompatible frequency conversion') return freq, ax_freq, series
def _downsample(self, how, **kwargs): """ Downsample the cython defined function Parameters ---------- how : string / cython mapped function **kwargs : kw args passed to how function """ # we may need to actually resample as if we are timestamps if self.kind == 'timestamp': return super(PeriodIndexResampler, self)._downsample(how, **kwargs) how = self._is_cython_func(how) or how ax = self.ax new_index = self._get_new_index() # Start vs. end of period memb = ax.asfreq(self.freq, how=self.convention) if is_subperiod(ax.freq, self.freq): # Downsampling if len(new_index) == 0: bins = [] else: i8 = memb.asi8 rng = np.arange(i8[0], i8[-1] + 1) bins = memb.searchsorted(rng, side='right') grouper = BinGrouper(bins, new_index) return self._groupby_and_aggregate(how, grouper=grouper) elif is_superperiod(ax.freq, self.freq): return self.asfreq() elif ax.freq == self.freq: return self.asfreq() raise IncompatibleFrequency( 'Frequency {} cannot be resampled to {}, as they are not ' 'sub or super periods'.format(ax.freq, self.freq))
def _downsample(self, how, **kwargs): """ Downsample the cython defined function Parameters ---------- how : string / cython mapped function **kwargs : kw args passed to how function """ # we may need to actually resample as if we are timestamps if self.kind == 'timestamp': return super(PeriodIndexResampler, self)._downsample(how, **kwargs) how = self._is_cython_func(how) or how ax = self.ax new_index = self._get_new_index() if len(new_index) == 0: return self._wrap_result(self._selected_obj.reindex(new_index)) # Start vs. end of period memb = ax.asfreq(self.freq, how=self.convention) if is_subperiod(ax.freq, self.freq): # Downsampling rng = np.arange(memb.values[0], memb.values[-1] + 1) bins = memb.searchsorted(rng, side='right') grouper = BinGrouper(bins, new_index) return self._groupby_and_aggregate(how, grouper=grouper) elif is_superperiod(ax.freq, self.freq): return self.asfreq() elif ax.freq == self.freq: return self.asfreq() raise ValueError('Frequency {axfreq} cannot be ' 'resampled to {freq}'.format( axfreq=ax.freq, freq=self.freq))
def test_is_superperiod_subperiod(): # input validation assert not (frequencies.is_superperiod(offsets.YearEnd(), None)) assert not (frequencies.is_subperiod(offsets.MonthEnd(), None)) assert not (frequencies.is_superperiod(None, offsets.YearEnd())) assert not (frequencies.is_subperiod(None, offsets.MonthEnd())) assert not (frequencies.is_superperiod(None, None)) assert not (frequencies.is_subperiod(None, None)) assert (frequencies.is_superperiod(offsets.YearEnd(), offsets.MonthEnd())) assert (frequencies.is_subperiod(offsets.MonthEnd(), offsets.YearEnd())) assert (frequencies.is_superperiod(offsets.Hour(), offsets.Minute())) assert (frequencies.is_subperiod(offsets.Minute(), offsets.Hour())) assert (frequencies.is_superperiod(offsets.Second(), offsets.Milli())) assert (frequencies.is_subperiod(offsets.Milli(), offsets.Second())) assert (frequencies.is_superperiod(offsets.Milli(), offsets.Micro())) assert (frequencies.is_subperiod(offsets.Micro(), offsets.Milli())) assert (frequencies.is_superperiod(offsets.Micro(), offsets.Nano())) assert (frequencies.is_subperiod(offsets.Nano(), offsets.Micro()))
def test_is_superperiod_subperiod(): # input validation assert not (frequencies.is_superperiod(offsets.YearEnd(), None)) assert not (frequencies.is_subperiod(offsets.MonthEnd(), None)) assert not (frequencies.is_superperiod(None, offsets.YearEnd())) assert not (frequencies.is_subperiod(None, offsets.MonthEnd())) assert not (frequencies.is_superperiod(None, None)) assert not (frequencies.is_subperiod(None, None)) assert frequencies.is_superperiod(offsets.YearEnd(), offsets.MonthEnd()) assert frequencies.is_subperiod(offsets.MonthEnd(), offsets.YearEnd()) assert frequencies.is_superperiod(offsets.Hour(), offsets.Minute()) assert frequencies.is_subperiod(offsets.Minute(), offsets.Hour()) assert frequencies.is_superperiod(offsets.Second(), offsets.Milli()) assert frequencies.is_subperiod(offsets.Milli(), offsets.Second()) assert frequencies.is_superperiod(offsets.Milli(), offsets.Micro()) assert frequencies.is_subperiod(offsets.Micro(), offsets.Milli()) assert frequencies.is_superperiod(offsets.Micro(), offsets.Nano()) assert frequencies.is_subperiod(offsets.Nano(), offsets.Micro())
def tsplot(series, plotf, **kwargs): """ Plots a Series on the given Matplotlib axes or the current axes Parameters ---------- axes : Axes series : Series Notes _____ Supports same kwargs as Axes.plot """ # Used inferred freq is possible, need a test case for inferred if 'ax' in kwargs: ax = kwargs.pop('ax') else: import matplotlib.pyplot as plt ax = plt.gca() freq = _get_freq(ax, series) # resample against axes freq if necessary if freq is None: # pragma: no cover raise ValueError('Cannot use dynamic axis without frequency info') else: ax_freq = getattr(ax, 'freq', None) if (ax_freq is not None) and (freq != ax_freq): if frequencies.is_subperiod(freq, ax_freq): # downsample how = kwargs.pop('how', 'last') series = series.resample(ax_freq, how=how) elif frequencies.is_superperiod(freq, ax_freq): series = series.resample(ax_freq) else: # one freq is weekly how = kwargs.pop('how', 'last') series = series.resample('D', how=how, fill_method='pad') series = series.resample(ax_freq, how=how, fill_method='pad') freq = ax_freq # Convert DatetimeIndex to PeriodIndex if isinstance(series.index, DatetimeIndex): series = series.to_period(freq=freq) style = kwargs.pop('style', None) # Specialized ts plotting attributes for Axes ax.freq = freq xaxis = ax.get_xaxis() xaxis.freq = freq ax.legendlabels = [kwargs.get('label', None)] ax.view_interval = None ax.date_axis_info = None # format args and lot args = _maybe_mask(series) if style is not None: args.append(style) plotf(ax, *args, **kwargs) format_dateaxis(ax, ax.freq) left, right = _get_xlim(ax.get_lines()) ax.set_xlim(left, right) return ax
def _is_sup(f1: str, f2: str) -> bool: return (f1.startswith("W") and is_superperiod("D", f2)) or ( f2.startswith("W") and is_superperiod(f1, "D") )
def test_super_sub_symmetry(p1, p2, expected): assert is_superperiod(p1, p2) is expected assert is_subperiod(p2, p1) is expected
def test_is_superperiod_subperiod(): assert (fmod.is_superperiod(offsets.YearEnd(), offsets.MonthEnd())) assert (fmod.is_subperiod(offsets.MonthEnd(), offsets.YearEnd()))
def _is_sup(f1, f2): return (f1.startswith("W") and is_superperiod("D", f2)) or (f2.startswith("W") and is_superperiod(f1, "D"))
def test_is_superperiod_subperiod(): assert(fmod.is_superperiod(offsets.YearEnd(), offsets.MonthEnd())) assert(fmod.is_subperiod(offsets.MonthEnd(), offsets.YearEnd())) assert(fmod.is_superperiod(offsets.Hour(), offsets.Minute())) assert(fmod.is_subperiod(offsets.Minute(), offsets.Hour()))
def _is_sup(f1, f2): return ((f1.startswith('W') and frequencies.is_superperiod('D', f2)) or (f2.startswith('W') and frequencies.is_superperiod(f1, 'D')))