Skip to content

Commit 3acc6b6

Browse files
committed
PERF: O(n) speedup in any/all by re-enabling short-circuiting for bool case
1 parent ea013a2 commit 3acc6b6

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

asv_bench/benchmarks/series_methods.py

+30
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,34 @@ def time_series_datetimeindex_repr(self):
182182
getattr(self.s, 'a', None)
183183

184184

185+
class All(object):
186+
187+
params = [[10**3, 10**6], ['fast', 'slow']]
188+
param_names = ['N', 'case']
189+
190+
def setup(self, N, case):
191+
if case == 'fast':
192+
self.s = Series([False] * N)
193+
else:
194+
self.s = Series([True] * N)
195+
196+
def time_all(self, N, case):
197+
self.s.all()
198+
199+
200+
class Any(object):
201+
202+
params = [[10**3, 10**6], ['fast', 'slow']]
203+
param_names = ['N', 'case']
204+
205+
def setup(self, N, case):
206+
if case == 'fast':
207+
self.s = Series([True] * N)
208+
else:
209+
self.s = Series([False] * N)
210+
211+
def time_any(self, N, case):
212+
self.s.any()
213+
214+
185215
from .pandas_vb_common import setup # noqa: F401

pandas/core/nanops.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,13 @@ def _get_fill_value(dtype, fill_value=None, fill_value_typ=None):
201201

202202

203203
def _get_values(values, skipna, fill_value=None, fill_value_typ=None,
204-
isfinite=False, copy=True, mask=None):
204+
isfinite=False, copy=True, mask=None, compute_mask=True):
205205
""" utility to get the values view, mask, dtype
206206
if necessary copy and mask using the specified fill_value
207207
copy = True will force the copy
208208
"""
209+
if skipna:
210+
compute_mask = True
209211

210212
if is_datetime64tz_dtype(values):
211213
# com.values_from_object returns M8[ns] dtype instead of tz-aware,
@@ -216,7 +218,7 @@ def _get_values(values, skipna, fill_value=None, fill_value_typ=None,
216218
values = com.values_from_object(values)
217219
dtype = values.dtype
218220

219-
if mask is None:
221+
if mask is None and compute_mask:
220222
if isfinite:
221223
mask = _isfinite(values)
222224
else:
@@ -362,8 +364,12 @@ def nanany(values, axis=None, skipna=True, mask=None):
362364
>>> nanops.nanany(s)
363365
False
364366
"""
365-
values, mask, dtype, _, _ = _get_values(values, skipna, False, copy=skipna,
366-
mask=mask)
367+
if (hasattr(values, 'dtype') and is_bool_dtype(values.dtype) and
368+
mask is None):
369+
# Assume np.bool cannot store NaNs
370+
skipna = False
371+
values, _, _, _, _ = _get_values(values, skipna, False, copy=skipna,
372+
mask=mask, compute_mask=False)
367373
return values.any(axis)
368374

369375

@@ -395,8 +401,12 @@ def nanall(values, axis=None, skipna=True, mask=None):
395401
>>> nanops.nanall(s)
396402
False
397403
"""
398-
values, mask, dtype, _, _ = _get_values(values, skipna, True, copy=skipna,
399-
mask=mask)
404+
if (hasattr(values, 'dtype') and is_bool_dtype(values.dtype) and
405+
mask is None):
406+
# Assume np.bool cannot store NaNs
407+
skipna = False
408+
values, _, _, _, _ = _get_values(values, skipna, True, copy=skipna,
409+
mask=mask, compute_mask=False)
400410
return values.all(axis)
401411

402412

0 commit comments

Comments
 (0)