Skip to content

Commit f263ef9

Browse files
committed
* Removing struct pairs from algos as it's no longer being
used * Since rolling min/max used to implicitly convert the return type to float, but now supports returning the same type as the original value, added an as_float argument to the min/max functions so that users of the API can obtain the original return type by passing as_float=False * Enhanced the unit test for the new as_float parameter * Changed the private _roll_min_max function to be declared as cdef instead of def
1 parent 2396314 commit f263ef9

File tree

3 files changed

+33
-19
lines changed

3 files changed

+33
-19
lines changed

pandas/algos.pyx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,10 +1625,6 @@ def roll_median_c(ndarray[float64_t] arg, int win, int minp):
16251625
# of its Simplified BSD license
16261626
# https://github.com/kwgoodman/bottleneck
16271627

1628-
cdef struct pairs:
1629-
double value
1630-
int death
1631-
16321628
from libc cimport stdlib
16331629

16341630
@cython.boundscheck(False)
@@ -1645,7 +1641,7 @@ def roll_min(ndarray[numeric] a, int window, int minp):
16451641

16461642
@cython.boundscheck(False)
16471643
@cython.wraparound(False)
1648-
def _roll_min_max(ndarray[numeric] a, int window, int minp, bint is_max):
1644+
cdef _roll_min_max(ndarray[numeric] a, int window, int minp, bint is_max):
16491645
"Moving min/max of 1d array of any numeric type along axis=0 ignoring NaNs."
16501646
cdef numeric ai, aold
16511647
cdef Py_ssize_t count

pandas/core/window.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,15 @@ def _shallow_copy(self, obj=None, **kwargs):
144144
kwargs[attr] = getattr(self, attr)
145145
return self._constructor(obj, **kwargs)
146146

147-
def _prep_values(self, values=None, kill_inf=True, how=None):
147+
def _prep_values(self, values=None, kill_inf=True, how=None, as_float=True):
148148

149149
if values is None:
150150
values = getattr(self._selected_obj, 'values', self._selected_obj)
151151

152152
# coerce dtypes as appropriate
153153
if com.is_float_dtype(values.dtype):
154154
pass
155-
elif com.is_integer_dtype(values.dtype):
155+
elif com.is_integer_dtype(values.dtype) and as_float:
156156
values = values.astype(float)
157157
elif com.is_timedelta64_dtype(values.dtype):
158158
values = values.view('i8').astype(float)
@@ -198,6 +198,7 @@ def _wrap_results(self, results, blocks, obj):
198198
results : list of ndarrays
199199
blocks : list of blocks
200200
obj : conformed data (may be resampled)
201+
as_float: bool, cast results to float
201202
"""
202203

203204
final = []
@@ -408,7 +409,7 @@ def _constructor(self):
408409
return Rolling
409410

410411
def _apply(self, func, window=None, center=None, check_minp=None, how=None,
411-
**kwargs):
412+
as_float=True, **kwargs):
412413
"""
413414
Rolling statistical measure using supplied function. Designed to be
414415
used with passed-in Cython array-based functions.
@@ -421,6 +422,8 @@ def _apply(self, func, window=None, center=None, check_minp=None, how=None,
421422
check_minp : function, default to _use_window
422423
how : string, default to None (DEPRECATED)
423424
how to resample
425+
as_float: bool, default to True
426+
Cast result to float, otherwise return as original type
424427
425428
Returns
426429
-------
@@ -438,7 +441,7 @@ def _apply(self, func, window=None, center=None, check_minp=None, how=None,
438441
results = []
439442
for b in blocks:
440443
try:
441-
values = self._prep_values(b.values)
444+
values = self._prep_values(b.values, as_float=as_float)
442445
except TypeError:
443446
results.append(b.values.copy())
444447
continue
@@ -535,25 +538,29 @@ def sum(self, **kwargs):
535538
Parameters
536539
----------
537540
how : string, default 'max' (DEPRECATED)
538-
Method for down- or re-sampling""")
541+
Method for down- or re-sampling
542+
as_float : bool, default True
543+
Cast to float, otherwise return as original type""")
539544

540-
def max(self, how=None, **kwargs):
545+
def max(self, how=None, as_float=True, **kwargs):
541546
if self.freq is not None and how is None:
542547
how = 'max'
543-
return self._apply('roll_max', how=how, **kwargs)
548+
return self._apply('roll_max', how=how, as_float=as_float, **kwargs)
544549

545550
_shared_docs['min'] = dedent("""
546551
%(name)s minimum
547552
548553
Parameters
549554
----------
550555
how : string, default 'min' (DEPRECATED)
551-
Method for down- or re-sampling""")
556+
Method for down- or re-sampling
557+
as_float : bool, default True
558+
Cast to float, otherwise return as original type""")
552559

553-
def min(self, how=None, **kwargs):
560+
def min(self, how=None, as_float=True, **kwargs):
554561
if self.freq is not None and how is None:
555562
how = 'min'
556-
return self._apply('roll_min', how=how, **kwargs)
563+
return self._apply('roll_min', how=how, as_float=as_float, **kwargs)
557564

558565
def mean(self, **kwargs):
559566
return self._apply('roll_mean', **kwargs)

pandas/tests/test_window.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,7 +2439,18 @@ def test_rolling_min_max_numeric_types(self):
24392439
types_test.extend([np.dtype("{}{}".format(sign, width))
24402440
for width in [1, 2, 4, 8] for sign in "ui"])
24412441
for data_type in types_test:
2442-
# Just testing that these don't throw exceptions. Other tests will
2443-
# cover quantitative correctness
2444-
DataFrame(np.arange(20, dtype=data_type)).rolling(window=5).max()
2445-
DataFrame(np.arange(20, dtype=data_type)).rolling(window=5).min()
2442+
# Just testing that these don't throw exceptions and that the types match.
2443+
# Other tests will cover quantitative correctness
2444+
for convert_to_float in [True]:
2445+
if data_type.kind == 'f' or not convert_to_float:
2446+
# Floating point values are left as-is when convert_to_float is True.
2447+
# We compare to the original floating point type instead
2448+
expected_type = data_type
2449+
else:
2450+
expected_type = np.dtype(float)
2451+
result = DataFrame(np.arange(20, dtype=data_type)).rolling(window=5).max(as_float=convert_to_float)
2452+
self.assertEqual(result.dtypes[0], expected_type)
2453+
result = DataFrame(np.arange(20, dtype=data_type)).rolling(window=5).min(as_float=convert_to_float)
2454+
self.assertEqual(result.dtypes[0], expected_type)
2455+
2456+

0 commit comments

Comments
 (0)