Skip to content

Commit 08ecba8

Browse files
jbrockmendeljreback
authored andcommitted
BUG: fix DataFrame+DataFrame op with timedelta64 dtype (pandas-dev#22696)
1 parent c44bad2 commit 08ecba8

File tree

4 files changed

+57
-4
lines changed

4 files changed

+57
-4
lines changed

doc/source/whatsnew/v0.24.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ Timedelta
666666
- Bug in :class:`Index` with numeric dtype when multiplying or dividing an array with dtype ``timedelta64`` (:issue:`22390`)
667667
- Bug in :class:`TimedeltaIndex` incorrectly allowing indexing with ``Timestamp`` object (:issue:`20464`)
668668
- Fixed bug where subtracting :class:`Timedelta` from an object-dtyped array would raise ``TypeError`` (:issue:`21980`)
669-
-
669+
- Fixed bug in adding a :class:`DataFrame` with all-`timedelta64[ns]` dtypes to a :class:`DataFrame` with all-integer dtypes returning incorrect results instead of raising ``TypeError`` (:issue:`22696`)
670670
-
671671

672672
Timezones

pandas/core/frame.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4889,7 +4889,7 @@ def _arith_op(left, right):
48894889
left, right = ops.fill_binop(left, right, fill_value)
48904890
return func(left, right)
48914891

4892-
if this._is_mixed_type or other._is_mixed_type:
4892+
if ops.should_series_dispatch(this, other, func):
48934893
# iterate over columns
48944894
return ops.dispatch_to_series(this, other, _arith_op)
48954895
else:

pandas/core/ops.py

+40-2
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,42 @@ def invalid_comparison(left, right, op):
900900
return res_values
901901

902902

903+
# -----------------------------------------------------------------------------
904+
# Dispatch logic
905+
906+
def should_series_dispatch(left, right, op):
907+
"""
908+
Identify cases where a DataFrame operation should dispatch to its
909+
Series counterpart.
910+
911+
Parameters
912+
----------
913+
left : DataFrame
914+
right : DataFrame
915+
op : binary operator
916+
917+
Returns
918+
-------
919+
override : bool
920+
"""
921+
if left._is_mixed_type or right._is_mixed_type:
922+
return True
923+
924+
if not len(left.columns) or not len(right.columns):
925+
# ensure obj.dtypes[0] exists for each obj
926+
return False
927+
928+
ldtype = left.dtypes.iloc[0]
929+
rdtype = right.dtypes.iloc[0]
930+
931+
if ((is_timedelta64_dtype(ldtype) and is_integer_dtype(rdtype)) or
932+
(is_timedelta64_dtype(rdtype) and is_integer_dtype(ldtype))):
933+
# numpy integer dtypes as timedelta64 dtypes in this scenario
934+
return True
935+
936+
return False
937+
938+
903939
# -----------------------------------------------------------------------------
904940
# Functions that add arithmetic methods to objects, given arithmetic factory
905941
# methods
@@ -1803,8 +1839,10 @@ def f(self, other, axis=default_axis, level=None, fill_value=None):
18031839

18041840
other = _align_method_FRAME(self, other, axis)
18051841

1806-
if isinstance(other, ABCDataFrame): # Another DataFrame
1807-
return self._combine_frame(other, na_op, fill_value, level)
1842+
if isinstance(other, ABCDataFrame):
1843+
# Another DataFrame
1844+
pass_op = op if should_series_dispatch(self, other, op) else na_op
1845+
return self._combine_frame(other, pass_op, fill_value, level)
18081846
elif isinstance(other, ABCSeries):
18091847
return _combine_series_frame(self, other, na_op,
18101848
fill_value=fill_value, axis=axis,

pandas/tests/frame/test_arithmetic.py

+15
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,18 @@ def test_df_bool_mul_int(self):
266266
result = 1 * df
267267
kinds = result.dtypes.apply(lambda x: x.kind)
268268
assert (kinds == 'i').all()
269+
270+
def test_td64_df_add_int_frame(self):
271+
# GH#22696 Check that we don't dispatch to numpy implementation,
272+
# which treats int64 as m8[ns]
273+
tdi = pd.timedelta_range('1', periods=3)
274+
df = tdi.to_frame()
275+
other = pd.DataFrame([1, 2, 3], index=tdi) # indexed like `df`
276+
with pytest.raises(TypeError):
277+
df + other
278+
with pytest.raises(TypeError):
279+
other + df
280+
with pytest.raises(TypeError):
281+
df - other
282+
with pytest.raises(TypeError):
283+
other - df

0 commit comments

Comments
 (0)