Skip to content

Commit d7782be

Browse files
committed
BUG: Non-string loffset not applied when resampling a timeseries (GH13218)
1 parent 3e3434b commit d7782be

File tree

3 files changed

+90
-2
lines changed

3 files changed

+90
-2
lines changed

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,4 @@ Bug Fixes
321321
- Require at least 0.23 version of cython to avoid problems with character encodings (:issue:`14699`)
322322
- Bug in converting object elements of array-like objects to unsigned 64-bit integers (:issue:`4471`)
323323
- Bug in ``pd.pivot_table()`` where no error was raised when values argument was not in the columns (:issue:`14938`)
324+
- Bug in ``resample``, where a non-string ```loffset`` argument would not be applied when resampling a timeseries (:issue:`13218`)

pandas/tseries/resample.py

+20-2
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,11 @@ def aggregate(self, arg, *args, **kwargs):
323323
*args,
324324
**kwargs)
325325

326+
# if arg was a string, _aggregate called resampler's _downsample or
327+
# _groupby_and_agg methods, which would've already applied the loffset
328+
if not isinstance(arg, compat.string_types):
329+
result = self._apply_loffset(result)
330+
326331
return result
327332

328333
agg = aggregate
@@ -381,7 +386,7 @@ def _gotitem(self, key, ndim, subset=None):
381386
return grouped
382387

383388
def _groupby_and_aggregate(self, how, grouper=None, *args, **kwargs):
384-
""" revaluate the obj with a groupby aggregation """
389+
""" re-evaluate the obj with a groupby aggregation """
385390

386391
if grouper is None:
387392
self._set_binner()
@@ -409,7 +414,14 @@ def _groupby_and_aggregate(self, how, grouper=None, *args, **kwargs):
409414
return self._wrap_result(result)
410415

411416
def _apply_loffset(self, result):
412-
"""if loffset if set, offset the result index"""
417+
"""
418+
if loffset is set, offset the result index
419+
420+
Parameters
421+
----------
422+
result : Series or DataFrame
423+
the result of resample
424+
"""
413425
loffset = self.loffset
414426
if isinstance(loffset, compat.string_types):
415427
loffset = to_offset(self.loffset)
@@ -419,6 +431,7 @@ def _apply_loffset(self, result):
419431
isinstance(result.index, DatetimeIndex) and
420432
len(result.index) > 0
421433
)
434+
422435
if needs_offset:
423436
result.index = result.index + loffset
424437

@@ -797,6 +810,11 @@ def aggregate(self, arg, *args, **kwargs):
797810
if result is None:
798811
result = self._downsample(arg, *args, **kwargs)
799812

813+
# if arg was a string, _aggregate called resamplers' _downsample or
814+
# _groupby_and_agg methods, which would've already applied the loffset
815+
if not isinstance(arg, compat.string_types):
816+
result = self._apply_loffset(result)
817+
800818
return result
801819

802820
agg = aggregate

pandas/tseries/tests/test_resample.py

+69
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,29 @@ def test_resample_loffset_count(self):
11881188

11891189
assert_series_equal(result, expected)
11901190

1191+
def test_resample_loffset_arg_type(self):
1192+
# GH 13218, 15002
1193+
s = self.create_series()
1194+
expected_means = [s.values[i:i + 2].mean()
1195+
for i in range(0, len(s.values), 2)]
1196+
df = s.to_frame('value')
1197+
for arg in ['mean', {'value': 'mean'}, ['mean']]:
1198+
result_agg = df.resample('2D', loffset='2H').agg(arg)
1199+
with tm.assert_produces_warning(FutureWarning,
1200+
check_stacklevel=False):
1201+
result_how = df.resample('2D', how=arg, loffset='2H')
1202+
expected_index = DatetimeIndex(start=df.index[0],
1203+
freq='2D',
1204+
periods=len(df.index) / 2)
1205+
expected_index = expected_index + timedelta(hours=2)
1206+
expected = DataFrame({'value': expected_means},
1207+
index=expected_index)
1208+
if isinstance(arg, list):
1209+
expected.columns = pd.MultiIndex.from_tuples([('value',
1210+
'mean')])
1211+
assert_frame_equal(result_agg, expected)
1212+
assert_frame_equal(result_how, expected)
1213+
11911214
def test_resample_upsample(self):
11921215
# from daily
11931216
dti = DatetimeIndex(start=datetime(2005, 1, 1),
@@ -2655,6 +2678,28 @@ def test_evenly_divisible_with_no_extra_bins(self):
26552678
result = df.resample('7D').sum()
26562679
assert_frame_equal(result, expected)
26572680

2681+
def test_resample_loffset_arg_type(self):
2682+
# GH 13218, 15002
2683+
s = self.create_series()
2684+
expected_means = [s.values[i:i + 2].mean()
2685+
for i in range(0, len(s.values), 2)]
2686+
df = s.to_frame('value')
2687+
for arg in ['mean', {'value': 'mean'}, ['mean']]:
2688+
result_agg = df.resample('2D', loffset='2H').agg(arg)
2689+
with tm.assert_produces_warning(FutureWarning,
2690+
check_stacklevel=False):
2691+
result_how = df.resample('2D', how=arg, loffset='2H')
2692+
expected_index = df.index.take(
2693+
np.arange(0, len(df.index), 2)).to_timestamp()
2694+
expected_index = expected_index + timedelta(hours=2)
2695+
expected = DataFrame({'value': expected_means},
2696+
index=expected_index)
2697+
if isinstance(arg, list):
2698+
expected.columns = pd.MultiIndex.from_tuples([('value',
2699+
'mean')])
2700+
assert_frame_equal(result_agg, expected)
2701+
assert_frame_equal(result_how, expected)
2702+
26582703

26592704
class TestTimedeltaIndex(Base, tm.TestCase):
26602705
_multiprocess_can_split_ = True
@@ -2677,6 +2722,30 @@ def test_asfreq_bug(self):
26772722
freq='1T'))
26782723
assert_frame_equal(result, expected)
26792724

2725+
def test_resample_loffset_arg_type(self):
2726+
# GH 13218, 15002
2727+
s = self.create_series()
2728+
expected_means = [s.values[i:i + 2].mean()
2729+
for i in range(0, len(s.values), 2)]
2730+
df = s.to_frame('value')
2731+
for arg in ['mean', {'value': 'mean'}, ['mean']]:
2732+
result_agg = df.resample('2D', loffset='2H').agg(arg)
2733+
with tm.assert_produces_warning(FutureWarning,
2734+
check_stacklevel=False):
2735+
result_how = df.resample('2D', how=arg, loffset='2H')
2736+
expected_index = timedelta_range(start=df.index[0],
2737+
freq='2D',
2738+
periods=len(df.index) / 2)
2739+
expected = DataFrame({'value': expected_means},
2740+
index=expected_index)
2741+
if isinstance(arg, list):
2742+
expected.columns = pd.MultiIndex.from_tuples([('value',
2743+
'mean')])
2744+
# GH 13022, 7687 - TODO: fix resample w/ TimedeltaIndex
2745+
with tm.assertRaises(AssertionError):
2746+
assert_frame_equal(result_agg, expected)
2747+
assert_frame_equal(result_how, expected)
2748+
26802749

26812750
class TestResamplerGrouper(tm.TestCase):
26822751
def setUp(self):

0 commit comments

Comments
 (0)