@@ -220,14 +220,12 @@ def apply_empty_result(self):
220
220
221
221
def apply_raw (self ):
222
222
""" apply to the values as a numpy array """
223
- try :
224
- result = libreduction .compute_reduction (self .values , self .f , axis = self .axis )
225
- except ValueError as err :
226
- if "Function does not reduce" not in str (err ):
227
- # catch only ValueError raised intentionally in libreduction
228
- raise
229
- # We expect np.apply_along_axis to give a two-dimensional result, or
230
- # also raise.
223
+ result , reduction_success = libreduction .compute_reduction (
224
+ self .values , self .f , axis = self .axis
225
+ )
226
+
227
+ # We expect np.apply_along_axis to give a two-dimensional result, or raise.
228
+ if not reduction_success :
231
229
result = np .apply_along_axis (self .f , self .axis , self .values )
232
230
233
231
# TODO: mixed type case
@@ -265,6 +263,9 @@ def apply_broadcast(self, target: "DataFrame") -> "DataFrame":
265
263
266
264
def apply_standard (self ):
267
265
266
+ # partial result that may be returned from reduction
267
+ partial_result = None
268
+
268
269
# try to reduce first (by default)
269
270
# this only matters if the reduction in values is of different dtype
270
271
# e.g. if we want to apply to a SparseFrame, then can't directly reduce
@@ -292,13 +293,9 @@ def apply_standard(self):
292
293
)
293
294
294
295
try :
295
- result = libreduction .compute_reduction (
296
+ result , reduction_success = libreduction .compute_reduction (
296
297
values , self .f , axis = self .axis , dummy = dummy , labels = labels
297
298
)
298
- except ValueError as err :
299
- if "Function does not reduce" not in str (err ):
300
- # catch only ValueError raised intentionally in libreduction
301
- raise
302
299
except TypeError :
303
300
# e.g. test_apply_ignore_failures we just ignore
304
301
if not self .ignore_failures :
@@ -307,39 +304,53 @@ def apply_standard(self):
307
304
# reached via numexpr; fall back to python implementation
308
305
pass
309
306
else :
310
- return self .obj ._constructor_sliced (result , index = labels )
307
+ if reduction_success :
308
+ return self .obj ._constructor_sliced (result , index = labels )
311
309
312
- # compute the result using the series generator
313
- results , res_index = self .apply_series_generator ()
310
+ # no exceptions - however reduction was unsuccessful,
311
+ # use the computed function result for first element
312
+ partial_result = result [0 ]
313
+ if isinstance (partial_result , ABCSeries ):
314
+ partial_result = partial_result .infer_objects ()
315
+
316
+ # compute the result using the series generator,
317
+ # use the result computed while trying to reduce if available.
318
+ results , res_index = self .apply_series_generator (partial_result )
314
319
315
320
# wrap results
316
321
return self .wrap_results (results , res_index )
317
322
318
- def apply_series_generator (self ) -> Tuple [ResType , "Index" ]:
323
+ def apply_series_generator (self , partial_result = None ) -> Tuple [ResType , "Index" ]:
319
324
series_gen = self .series_generator
320
325
res_index = self .result_index
321
326
322
- keys = []
323
327
results = {}
328
+
329
+ # If a partial result was already computed,
330
+ # use it instead of running on the first element again
331
+ series_gen_enumeration = enumerate (series_gen )
332
+ if partial_result is not None :
333
+ i , v = next (series_gen_enumeration )
334
+ results [i ] = partial_result
335
+
324
336
if self .ignore_failures :
325
337
successes = []
326
- for i , v in enumerate ( series_gen ) :
338
+ for i , v in series_gen_enumeration :
327
339
try :
328
340
results [i ] = self .f (v )
329
341
except Exception :
330
342
pass
331
343
else :
332
- keys .append (v .name )
333
344
successes .append (i )
334
345
335
346
# so will work with MultiIndex
336
347
if len (successes ) < len (res_index ):
337
348
res_index = res_index .take (successes )
338
349
339
350
else :
340
- for i , v in enumerate (series_gen ):
351
+ for i , v in series_gen_enumeration :
352
+
341
353
results [i ] = self .f (v )
342
- keys .append (v .name )
343
354
344
355
return results , res_index
345
356
0 commit comments