Skip to content

Commit 4e790f6

Browse files
committed
BUG: GH15429 transform result of timedelta from datetime
The transform() operation needs to return a like-indexed. To facilitate this, transform starts with a copy of the original series. Then, after the computation for each group, sets the appropriate elements of the copied series equal to the result. At that point is does a type comparison, and discovers that the timedelta is not cast-able to a datetime.
1 parent 5a8883b commit 4e790f6

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

doc/source/whatsnew/v0.20.0.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,8 @@ Bug Fixes
579579

580580

581581

582+
- Bug in ``groupby.transform`` where calculating a ``timedelta`` from a ``datetime`` caused a ``ValueError`` (:issue:`15429`)
583+
582584

583585

584586

pandas/core/groupby.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2926,7 +2926,15 @@ def transform(self, func, *args, **kwargs):
29262926
pass
29272927

29282928
indexer = self._get_index(name)
2929-
result[indexer] = res
2929+
try:
2930+
result[indexer] = res
2931+
except ValueError:
2932+
# date math can cause type of result to change
2933+
if i != 0 or not isinstance(
2934+
res, (datetime.datetime, datetime.timedelta)):
2935+
raise
2936+
result = np.empty_like(result, type(res))
2937+
result[indexer] = res
29302938

29312939
result = _possibly_downcast_to_dtype(result, dtype)
29322940
return self._selected_obj.__class__(result,

pandas/tests/groupby/test_transform.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,22 @@ def test_transform_bug(self):
190190
expected = Series(np.arange(5, 0, step=-1), name='B')
191191
assert_series_equal(result, expected)
192192

193+
def test_transform_datetime_to_timedelta(self):
194+
# transforming a datetime to timedelta
195+
df = DataFrame(dict(A=Timestamp('20130101'), B=np.arange(5)))
196+
expected = pd.Series([
197+
Timestamp('20130101') - Timestamp('20130101')] * 5, name='A')
198+
199+
# this does date math without changing result type in transform
200+
base_time = df['A'][0]
201+
result = df.groupby('A')['A'].transform(
202+
lambda x: x.max() - x.min() + base_time) - base_time
203+
assert_series_equal(result, expected)
204+
205+
# this does date math and causes the transform to return timedelta
206+
result = df.groupby('A')['A'].transform(lambda x: x.max() - x.min())
207+
assert_series_equal(result, expected)
208+
193209
def test_transform_multiple(self):
194210
grouped = self.ts.groupby([lambda x: x.year, lambda x: x.month])
195211

0 commit comments

Comments
 (0)