Skip to content

Commit 3577746

Browse files
jbrockmendelWillAyd
authored andcommitted
CLN: small ops optimizations (#28036)
1 parent ddfc9a2 commit 3577746

File tree

5 files changed

+32
-26
lines changed

5 files changed

+32
-26
lines changed

pandas/core/frame.py

+17-11
Original file line numberDiff line numberDiff line change
@@ -5298,12 +5298,19 @@ def _combine_frame(self, other, func, fill_value=None, level=None):
52985298
this, other = self.align(other, join="outer", level=level, copy=False)
52995299
new_index, new_columns = this.index, this.columns
53005300

5301-
def _arith_op(left, right):
5302-
# for the mixed_type case where we iterate over columns,
5303-
# _arith_op(left, right) is equivalent to
5304-
# left._binop(right, func, fill_value=fill_value)
5305-
left, right = ops.fill_binop(left, right, fill_value)
5306-
return func(left, right)
5301+
if fill_value is None:
5302+
# since _arith_op may be called in a loop, avoid function call
5303+
# overhead if possible by doing this check once
5304+
_arith_op = func
5305+
5306+
else:
5307+
5308+
def _arith_op(left, right):
5309+
# for the mixed_type case where we iterate over columns,
5310+
# _arith_op(left, right) is equivalent to
5311+
# left._binop(right, func, fill_value=fill_value)
5312+
left, right = ops.fill_binop(left, right, fill_value)
5313+
return func(left, right)
53075314

53085315
if ops.should_series_dispatch(this, other, func):
53095316
# iterate over columns
@@ -5318,7 +5325,7 @@ def _arith_op(left, right):
53185325

53195326
def _combine_match_index(self, other, func, level=None):
53205327
left, right = self.align(other, join="outer", axis=0, level=level, copy=False)
5321-
assert left.index.equals(right.index)
5328+
# at this point we have `left.index.equals(right.index)`
53225329

53235330
if left._is_mixed_type or right._is_mixed_type:
53245331
# operate column-wise; avoid costly object-casting in `.values`
@@ -5331,14 +5338,13 @@ def _combine_match_index(self, other, func, level=None):
53315338
new_data, index=left.index, columns=self.columns, copy=False
53325339
)
53335340

5334-
def _combine_match_columns(self, other, func, level=None):
5335-
assert isinstance(other, Series)
5341+
def _combine_match_columns(self, other: Series, func, level=None):
53365342
left, right = self.align(other, join="outer", axis=1, level=level, copy=False)
5337-
assert left.columns.equals(right.index)
5343+
# at this point we have `left.columns.equals(right.index)`
53385344
return ops.dispatch_to_series(left, right, func, axis="columns")
53395345

53405346
def _combine_const(self, other, func):
5341-
assert lib.is_scalar(other) or np.ndim(other) == 0
5347+
# scalar other or np.ndim(other) == 0
53425348
return ops.dispatch_to_series(self, other, func)
53435349

53445350
def combine(self, other, func, fill_value=None, overwrite=True):

pandas/core/ops/__init__.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def maybe_upcast_for_op(obj, shape: Tuple[int, ...]):
169169
# np.timedelta64(3, 'D') / 2 == np.timedelta64(1, 'D')
170170
return Timedelta(obj)
171171

172-
elif isinstance(obj, np.ndarray) and is_timedelta64_dtype(obj):
172+
elif isinstance(obj, np.ndarray) and is_timedelta64_dtype(obj.dtype):
173173
# GH#22390 Unfortunately we need to special-case right-hand
174174
# timedelta64 dtypes because numpy casts integer dtypes to
175175
# timedelta64 when operating with timedelta64
@@ -415,7 +415,7 @@ def should_extension_dispatch(left: ABCSeries, right: Any) -> bool:
415415
):
416416
return True
417417

418-
if is_extension_array_dtype(right) and not is_scalar(right):
418+
if not is_scalar(right) and is_extension_array_dtype(right):
419419
# GH#22378 disallow scalar to exclude e.g. "category", "Int64"
420420
return True
421421

@@ -755,7 +755,7 @@ def na_op(x, y):
755755
assert not isinstance(y, (list, ABCSeries, ABCIndexClass))
756756
if isinstance(y, np.ndarray):
757757
# bool-bool dtype operations should be OK, should not get here
758-
assert not (is_bool_dtype(x) and is_bool_dtype(y))
758+
assert not (is_bool_dtype(x.dtype) and is_bool_dtype(y.dtype))
759759
x = ensure_object(x)
760760
y = ensure_object(y)
761761
result = libops.vec_binop(x, y, op)
@@ -804,7 +804,7 @@ def wrapper(self, other):
804804

805805
else:
806806
# scalars, list, tuple, np.array
807-
is_other_int_dtype = is_integer_dtype(np.asarray(other))
807+
is_other_int_dtype = is_integer_dtype(np.asarray(other).dtype)
808808
if is_list_like(other) and not isinstance(other, np.ndarray):
809809
# TODO: Can we do this before the is_integer_dtype check?
810810
# could the is_integer_dtype check be checking the wrong
@@ -988,10 +988,10 @@ def f(self, other, axis=default_axis, level=None, fill_value=None):
988988
self, other, pass_op, fill_value=fill_value, axis=axis, level=level
989989
)
990990
else:
991+
# in this case we always have `np.ndim(other) == 0`
991992
if fill_value is not None:
992993
self = self.fillna(fill_value)
993994

994-
assert np.ndim(other) == 0
995995
return self._combine_const(other, op)
996996

997997
f.__name__ = op_name
@@ -1032,7 +1032,7 @@ def f(self, other, axis=default_axis, level=None):
10321032
self, other, na_op, fill_value=None, axis=axis, level=level
10331033
)
10341034
else:
1035-
assert np.ndim(other) == 0, other
1035+
# in this case we always have `np.ndim(other) == 0`
10361036
return self._combine_const(other, na_op)
10371037

10381038
f.__name__ = op_name

pandas/core/ops/array_ops.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
find_common_type,
1212
maybe_upcast_putmask,
1313
)
14-
from pandas.core.dtypes.common import is_object_dtype, is_period_dtype, is_scalar
14+
from pandas.core.dtypes.common import is_object_dtype, is_scalar
1515
from pandas.core.dtypes.generic import ABCIndex, ABCSeries
1616
from pandas.core.dtypes.missing import notna
1717

@@ -57,9 +57,9 @@ def masked_arith_op(x, y, op):
5757
dtype = find_common_type([x.dtype, y.dtype])
5858
result = np.empty(x.size, dtype=dtype)
5959

60-
# PeriodIndex.ravel() returns int64 dtype, so we have
61-
# to work around that case. See GH#19956
62-
yrav = y if is_period_dtype(y) else y.ravel()
60+
# NB: ravel() is only safe since y is ndarray; for e.g. PeriodIndex
61+
# we would get int64 dtype, see GH#19956
62+
yrav = y.ravel()
6363
mask = notna(xrav) & notna(yrav)
6464

6565
if yrav.shape != mask.shape:
@@ -82,9 +82,9 @@ def masked_arith_op(x, y, op):
8282
mask = notna(xrav)
8383

8484
# 1 ** np.nan is 1. So we have to unmask those.
85-
if op == pow:
85+
if op is pow:
8686
mask = np.where(x == 1, False, mask)
87-
elif op == rpow:
87+
elif op is rpow:
8888
mask = np.where(y == 1, False, mask)
8989

9090
if mask.any():

pandas/core/ops/missing.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def fill_zeros(result, x, y, name, fill):
4040
4141
Mask the nan's from x.
4242
"""
43-
if fill is None or is_float_dtype(result):
43+
if fill is None or is_float_dtype(result.dtype):
4444
return result
4545

4646
if name.startswith(("r", "__r")):
@@ -55,7 +55,7 @@ def fill_zeros(result, x, y, name, fill):
5555
if is_scalar_type:
5656
y = np.array(y)
5757

58-
if is_integer_dtype(y):
58+
if is_integer_dtype(y.dtype):
5959

6060
if (y == 0).any():
6161

pandas/core/sparse/frame.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -569,13 +569,13 @@ def _combine_frame(self, other, func, fill_value=None, level=None):
569569
).__finalize__(self)
570570

571571
def _combine_match_index(self, other, func, level=None):
572-
new_data = {}
573572

574573
if level is not None:
575574
raise NotImplementedError("'level' argument is not supported")
576575

577576
this, other = self.align(other, join="outer", axis=0, level=level, copy=False)
578577

578+
new_data = {}
579579
for col, series in this.items():
580580
new_data[col] = func(series.values, other.values)
581581

0 commit comments

Comments
 (0)