Skip to content

Commit dbb054f

Browse files
committed
BUG: loffset not applied when using resample with agg() (GH13218)
1 parent 4df08a9 commit dbb054f

File tree

3 files changed

+111
-20
lines changed

3 files changed

+111
-20
lines changed

doc/source/whatsnew/v0.19.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -975,3 +975,4 @@ Bug Fixes
975975
- Bug in ``Index`` raises ``KeyError`` displaying incorrect column when column is not in the df and columns contains duplicate values (:issue:`13822`)
976976
- Bug in ``Period`` and ``PeriodIndex`` creating wrong dates when frequency has combined offset aliases (:issue:`13874`)
977977
- Bug in ``pd.to_datetime()`` did not cast floats correctly when ``unit`` was specified, resulting in truncated datetime (:issue:`13845`)
978+
- Bug in ``resample`` where ``loffset`` was not applied when calling ``resample.agg()`` on a timeseries (:issue:`13218`)

pandas/tseries/resample.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ def aggregate(self, arg, *args, **kwargs):
309309
return self._groupby_and_aggregate(arg,
310310
*args,
311311
**kwargs)
312+
# GH 13218
313+
if isinstance(arg, (dict, list)):
314+
result = self._apply_loffset(result)
312315

313316
return result
314317

@@ -368,7 +371,7 @@ def _gotitem(self, key, ndim, subset=None):
368371
return grouped
369372

370373
def _groupby_and_aggregate(self, how, grouper=None, *args, **kwargs):
371-
""" revaluate the obj with a groupby aggregation """
374+
""" re-evaluate the obj with a groupby aggregation """
372375

373376
if grouper is None:
374377
self._set_binner()
@@ -396,7 +399,14 @@ def _groupby_and_aggregate(self, how, grouper=None, *args, **kwargs):
396399
return self._wrap_result(result)
397400

398401
def _apply_loffset(self, result):
399-
"""if loffset if set, offset the result index"""
402+
"""
403+
if loffset is set, offset the result index
404+
405+
Parameters
406+
----------
407+
result : Series or DataFrame
408+
the result of resample
409+
"""
400410
loffset = self.loffset
401411
if isinstance(loffset, compat.string_types):
402412
loffset = to_offset(self.loffset)
@@ -406,6 +416,7 @@ def _apply_loffset(self, result):
406416
isinstance(result.index, DatetimeIndex) and
407417
len(result.index) > 0
408418
)
419+
409420
if needs_offset:
410421
result.index = result.index + loffset
411422

@@ -771,6 +782,10 @@ def aggregate(self, arg, *args, **kwargs):
771782
if result is None:
772783
result = self._downsample(arg, *args, **kwargs)
773784

785+
# GH 13218
786+
if isinstance(arg, (dict, list)):
787+
result = self._apply_loffset(result)
788+
774789
return result
775790

776791
agg = aggregate

pandas/tseries/tests/test_resample.py

+93-18
Original file line numberDiff line numberDiff line change
@@ -1098,25 +1098,35 @@ def test_resample_loffset(self):
10981098

10991099
def test_resample_loffset_count(self):
11001100
# GH 12725
1101-
start_time = '1/1/2000 00:00:00'
1102-
rng = date_range(start_time, periods=100, freq='S')
1103-
ts = Series(np.random.randn(len(rng)), index=rng)
1104-
1105-
result = ts.resample('10S', loffset='1s').count()
1106-
1107-
expected_index = (
1108-
date_range(start_time, periods=10, freq='10S') +
1109-
timedelta(seconds=1)
1110-
)
1111-
expected = pd.Series(10, index=expected_index)
1112-
1113-
assert_series_equal(result, expected)
1114-
1115-
# Same issue should apply to .size() since it goes through
1116-
# same code path
1117-
result = ts.resample('10S', loffset='1s').size()
1101+
s = self.create_series()
1102+
df = s.to_frame('value')
1103+
result = df.resample('2D', loffset='2H').count()
1104+
expected_index = DatetimeIndex(start=df.index[0],
1105+
freq='2D',
1106+
periods=len(df.index) / 2)
1107+
expected_index = expected_index + timedelta(hours=2)
1108+
expected = DataFrame({'value': 2},
1109+
index=expected_index)
1110+
assert_frame_equal(result, expected)
11181111

1119-
assert_series_equal(result, expected)
1112+
def test_resample_loffset_agg(self):
1113+
# GH 13218
1114+
s = self.create_series()
1115+
expected_means = [s.values[i:i + 2].mean()
1116+
for i in range(0, len(s.values), 2)]
1117+
df = s.to_frame('value')
1118+
for arg in ['mean', {'value': 'mean'}, ['mean']]:
1119+
result = df.resample('2D', loffset='2H').agg(arg)
1120+
expected_index = DatetimeIndex(start=df.index[0],
1121+
freq='2D',
1122+
periods=len(df.index) / 2)
1123+
expected_index = expected_index + timedelta(hours=2)
1124+
expected = DataFrame({'value': expected_means},
1125+
index=expected_index)
1126+
if isinstance(arg, list):
1127+
expected.columns = pd.MultiIndex.from_tuples([('value',
1128+
'mean')])
1129+
assert_frame_equal(result, expected)
11201130

11211131
def test_resample_upsample(self):
11221132
# from daily
@@ -2509,6 +2519,36 @@ def test_evenly_divisible_with_no_extra_bins(self):
25092519
result = df.resample('7D').sum()
25102520
assert_frame_equal(result, expected)
25112521

2522+
def test_resample_loffset_count(self):
2523+
# GH 12725
2524+
s = self.create_series()
2525+
df = s.to_frame('value')
2526+
result = df.resample('2D', loffset='2H').count()
2527+
expected_index = df.index.take(
2528+
np.arange(0, len(df.index), 2)).to_datetime()
2529+
expected_index = expected_index + timedelta(hours=2)
2530+
expected = DataFrame({'value': 2},
2531+
index=expected_index)
2532+
assert_frame_equal(result, expected)
2533+
2534+
def test_resample_loffset_agg(self):
2535+
# GH 13218
2536+
s = self.create_series()
2537+
expected_means = [s.values[i:i + 2].mean()
2538+
for i in range(0, len(s.values), 2)]
2539+
df = s.to_frame('value')
2540+
for arg in ['mean', {'value': 'mean'}, ['mean']]:
2541+
result = df.resample('2D', loffset='2H').agg(arg)
2542+
expected_index = df.index.take(
2543+
np.arange(0, len(df.index), 2)).to_datetime()
2544+
expected_index = expected_index + timedelta(hours=2)
2545+
expected = DataFrame({'value': expected_means},
2546+
index=expected_index)
2547+
if isinstance(arg, list):
2548+
expected.columns = pd.MultiIndex.from_tuples([('value',
2549+
'mean')])
2550+
assert_frame_equal(result, expected)
2551+
25122552

25132553
class TestTimedeltaIndex(Base, tm.TestCase):
25142554
_multiprocess_can_split_ = True
@@ -2531,6 +2571,41 @@ def test_asfreq_bug(self):
25312571
freq='1T'))
25322572
assert_frame_equal(result, expected)
25332573

2574+
def test_resample_loffset_count(self):
2575+
# GH 12725
2576+
s = self.create_series()
2577+
df = s.to_frame('value')
2578+
result = df.resample('2D', loffset='2H').count()
2579+
2580+
# GH 13022, 7687 resample w/ TimedeltaIndex results in incorrect index
2581+
expected_index = timedelta_range(start=df.index[0],
2582+
freq='2D',
2583+
periods=len(df.index) / 2)
2584+
expected = DataFrame({'value': 2},
2585+
index=expected_index)
2586+
with tm.assertRaises(AssertionError):
2587+
assert_frame_equal(result, expected)
2588+
2589+
def test_resample_loffset_agg(self):
2590+
# GH 13218
2591+
s = self.create_series()
2592+
expected_means = [s.values[i:i + 2].mean()
2593+
for i in range(0, len(s.values), 2)]
2594+
df = s.to_frame('value')
2595+
for arg in ['mean', {'value': 'mean'}, ['mean']]:
2596+
result = df.resample('2D', loffset='2H').agg(arg)
2597+
expected_index = timedelta_range(start=df.index[0],
2598+
freq='2D',
2599+
periods=len(df.index) / 2)
2600+
expected = DataFrame({'value': expected_means},
2601+
index=expected_index)
2602+
if isinstance(arg, list):
2603+
expected.columns = pd.MultiIndex.from_tuples([('value',
2604+
'mean')])
2605+
# GH 13022, 7687 - TODO: fix resample w/ TimedeltaIndex
2606+
with tm.assertRaises(AssertionError):
2607+
assert_frame_equal(result, expected)
2608+
25342609

25352610
class TestResamplerGrouper(tm.TestCase):
25362611
def setUp(self):

0 commit comments

Comments
 (0)