Skip to content

Commit 405730f

Browse files
committed
deprecate reduce
1 parent 1a7d7c8 commit 405730f

File tree

5 files changed

+63
-21
lines changed

5 files changed

+63
-21
lines changed

doc/source/whatsnew/v0.23.0.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ Deprecations
524524
- ``IntervalIndex.from_intervals`` is deprecated in favor of the :class:`IntervalIndex` constructor (:issue:`19263`)
525525
- :func:``DataFrame.from_items`` is deprecated. Use :func:``DataFrame.from_dict()`` instead, or :func:``DataFrame.from_dict(OrderedDict())`` if you wish to preserve the key order (:issue:`17320`)
526526
- The ``broadcast`` parameter of ``.apply()`` is removed in favor of ``result_type='broadcast'`` (:issue:`18577`)
527+
- The ``reduce`` parameter of ``.apply()`` is removed in favor of ``result_type='reduce'`` (:issue:`18577`)
527528

528529
.. _whatsnew_0230.prior_deprecations:
529530

pandas/core/apply.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ def __init__(self, obj, func, broadcast, raw, reduce, result_type,
3535
ignore_failures, args, kwds):
3636
self.obj = obj
3737
self.raw = raw
38-
self.reduce = reduce
3938
self.ignore_failures = ignore_failures
4039
self.args = args or ()
4140
self.kwds = kwds or {}
@@ -49,6 +48,20 @@ def __init__(self, obj, func, broadcast, raw, reduce, result_type,
4948
if broadcast:
5049
result_type = 'broadcast'
5150

51+
if reduce is not None:
52+
warnings.warn("The reduce argument is deprecated and will "
53+
"be removed in a future version. You can specify "
54+
"result_type='reduce' to try to reduce the result "
55+
"to the original dimensions",
56+
FutureWarning, stacklevel=4)
57+
if reduce:
58+
59+
if result_type is not None:
60+
raise ValueError(
61+
"cannot pass both reduce=True and result_type")
62+
63+
result_type = 'reduce'
64+
5265
self.result_type = result_type
5366

5467
# curry if needed
@@ -126,11 +139,16 @@ def apply_empty_result(self):
126139
series in order to see if this is a reduction function
127140
"""
128141

129-
from pandas import Series
130-
reduce = self.reduce
142+
# we are not asked to reduce or infer reduction
143+
# so just return a copy of the existing object
144+
if self.result_type not in ['reduce', None]:
145+
return self.obj.copy()
131146

132-
if reduce is None:
133-
reduce = False
147+
# we may need to infer
148+
reduce = self.result_type == 'reduce'
149+
150+
from pandas import Series
151+
if not reduce:
134152

135153
EMPTY_SERIES = Series([])
136154
try:
@@ -191,18 +209,14 @@ def apply_broadcast(self, target):
191209
return result
192210

193211
def apply_standard(self):
194-
reduce = self.reduce
195-
if reduce is None:
196-
reduce = True
197212

198213
# try to reduce first (by default)
199214
# this only matters if the reduction in values is of different dtype
200215
# e.g. if we want to apply to a SparseFrame, then can't directly reduce
201216

202217
# we cannot reduce using non-numpy dtypes,
203218
# as demonstrated in gh-12244
204-
if (reduce and
205-
self.result_type is None and
219+
if (self.result_type in ['reduce', None] and
206220
not self.dtypes.apply(is_extension_type).any()):
207221

208222
# Create a dummy Series from an empty array

pandas/core/frame.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4871,9 +4871,15 @@ def apply(self, func, axis=0, broadcast=None, raw=False, reduce=None,
48714871
reduce is True a Series will always be returned, and if False a
48724872
DataFrame will always be returned.
48734873
4874-
result_type : {'expand', 'broadcast, None}
4874+
.. deprecated:: 0.23.0
4875+
This argument will be removed in a future version, replaced
4876+
by result_type='reduce'.
4877+
4878+
result_type : {'expand', 'reduce', 'broadcast, None}
48754879
These only act when axis=1 {columns}
48764880
* 'expand' : list-like results will be turned into columns
4881+
* 'reduce' : return a Series if possible rather than expanding
4882+
list-like results. This is the opposite to 'expand'
48774883
* 'broadcast' : scalar results will be broadcast to all columns
48784884
* None : list-like results will be returned as a list
48794885
in a single column. However if the apply function
@@ -5686,7 +5692,7 @@ def f(x):
56865692
from pandas.core.apply import frame_apply
56875693
opa = frame_apply(self,
56885694
func=f,
5689-
reduce=False,
5695+
result_type='expand',
56905696
ignore_failures=True)
56915697
result = opa.get_result()
56925698
if result.ndim == self.ndim:

pandas/core/sparse/frame.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ def notna(self):
835835
return self._apply_columns(lambda x: x.notna())
836836
notnull = notna
837837

838-
def apply(self, func, axis=0, broadcast=None, reduce=False,
838+
def apply(self, func, axis=0, broadcast=None, reduce=None,
839839
result_type=None):
840840
"""
841841
Analogous to DataFrame.apply, for SparseDataFrame
@@ -853,9 +853,24 @@ def apply(self, func, axis=0, broadcast=None, reduce=False,
853853
This argument will be removed in a future version, replaced
854854
by result_type='broadcast'.
855855
856-
result_type : {'expand', 'broadcast, None}
856+
reduce : boolean or None, default None
857+
Try to apply reduction procedures. If the DataFrame is empty,
858+
apply will use reduce to determine whether the result should be a
859+
Series or a DataFrame. If reduce is None (the default), apply's
860+
return value will be guessed by calling func an empty Series (note:
861+
while guessing, exceptions raised by func will be ignored). If
862+
reduce is True a Series will always be returned, and if False a
863+
DataFrame will always be returned.
864+
865+
.. deprecated:: 0.23.0
866+
This argument will be removed in a future version, replaced
867+
by result_type='reduce'.
868+
869+
result_type : {'expand', 'reduce', 'broadcast, None}
857870
These only act when axis=1 {columns}
858871
* 'expand' : list-like results will be turned into columns
872+
* 'reduce' : return a Series if possible rather than expanding
873+
list-like results. This is the opposite to 'expand'
859874
* 'broadcast' : scalar results will be broadcast to all columns
860875
* None : list-like results will be returned as a list
861876
in a single column. However if the apply function

pandas/tests/frame/test_apply.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,24 +82,30 @@ def test_apply_empty(self):
8282
rs = xp.apply(lambda x: x['a'], axis=1)
8383
assert_frame_equal(xp, rs)
8484

85+
def test_apply_with_reduce_empty(self):
8586
# reduce with an empty DataFrame
8687
x = []
87-
result = self.empty.apply(x.append, axis=1, reduce=False)
88+
result = self.empty.apply(x.append, axis=1, result_type='expand')
8889
assert_frame_equal(result, self.empty)
89-
result = self.empty.apply(x.append, axis=1, reduce=True)
90+
result = self.empty.apply(x.append, axis=1, result_type='reduce')
9091
assert_series_equal(result, Series(
9192
[], index=pd.Index([], dtype=object)))
9293

9394
empty_with_cols = DataFrame(columns=['a', 'b', 'c'])
94-
result = empty_with_cols.apply(x.append, axis=1, reduce=False)
95+
result = empty_with_cols.apply(x.append, axis=1, result_type='expand')
9596
assert_frame_equal(result, empty_with_cols)
96-
result = empty_with_cols.apply(x.append, axis=1, reduce=True)
97+
result = empty_with_cols.apply(x.append, axis=1, result_type='reduce')
9798
assert_series_equal(result, Series(
9899
[], index=pd.Index([], dtype=object)))
99100

100101
# Ensure that x.append hasn't been called
101102
assert x == []
102103

104+
def test_apply_deprecate_reduce(self):
105+
with warnings.catch_warnings(record=True):
106+
x = []
107+
self.empty.apply(x.append, axis=1, result_type='reduce')
108+
103109
def test_apply_standard_nonunique(self):
104110
df = DataFrame(
105111
[[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=['a', 'a', 'c'])
@@ -419,9 +425,9 @@ def test_apply_dict(self):
419425
fn = lambda x: x.to_dict()
420426

421427
for df, dicts in [(A, A_dicts), (B, B_dicts)]:
422-
reduce_true = df.apply(fn, reduce=True)
423-
reduce_false = df.apply(fn, reduce=False)
424-
reduce_none = df.apply(fn, reduce=None)
428+
reduce_true = df.apply(fn, result_type='reduce')
429+
reduce_false = df.apply(fn, result_type='expand')
430+
reduce_none = df.apply(fn)
425431

426432
assert_series_equal(reduce_true, dicts)
427433
assert_frame_equal(reduce_false, df)

0 commit comments

Comments
 (0)