16
16
Iterable,
17
17
Iterator,
18
18
List,
19
+ Literal,
19
20
Sequence,
20
21
cast,
21
22
)
@@ -288,6 +289,11 @@ def agg_list_like(self) -> DataFrame | Series:
288
289
-------
289
290
Result of aggregation.
290
291
"""
292
+ return self.agg_or_apply_list_like(op_name="agg")
293
+
294
+ def agg_or_apply_list_like(
295
+ self, op_name: Literal["agg", "apply"]
296
+ ) -> DataFrame | Series:
291
297
from pandas.core.groupby.generic import (
292
298
DataFrameGroupBy,
293
299
SeriesGroupBy,
@@ -296,6 +302,9 @@ def agg_list_like(self) -> DataFrame | Series:
296
302
297
303
obj = self.obj
298
304
func = cast(List[AggFuncTypeBase], self.func)
305
+ kwargs = self.kwargs
306
+ if op_name == "apply":
307
+ kwargs = {**kwargs, "by_row": False}
299
308
300
309
if getattr(obj, "axis", 0) == 1:
301
310
raise NotImplementedError("axis other than 0 is not supported")
@@ -313,8 +322,6 @@ def agg_list_like(self) -> DataFrame | Series:
313
322
keys = []
314
323
315
324
is_groupby = isinstance(obj, (DataFrameGroupBy, SeriesGroupBy))
316
- is_ser_or_df = isinstance(obj, (ABCDataFrame, ABCSeries))
317
- this_args = [self.axis, *self.args] if is_ser_or_df else self.args
318
325
319
326
context_manager: ContextManager
320
327
if is_groupby:
@@ -323,12 +330,19 @@ def agg_list_like(self) -> DataFrame | Series:
323
330
context_manager = com.temp_setattr(obj, "as_index", True)
324
331
else:
325
332
context_manager = nullcontext()
333
+
334
+ def include_axis(colg) -> bool:
335
+ return isinstance(colg, ABCDataFrame) or (
336
+ isinstance(colg, ABCSeries) and op_name == "agg"
337
+ )
338
+
326
339
with context_manager:
327
340
# degenerate case
328
341
if selected_obj.ndim == 1:
329
342
for a in func:
330
343
colg = obj._gotitem(selected_obj.name, ndim=1, subset=selected_obj)
331
- new_res = colg.aggregate(a, *this_args, **self.kwargs)
344
+ args = [self.axis, *self.args] if include_axis(colg) else self.args
345
+ new_res = getattr(colg, op_name)(a, *args, **kwargs)
332
346
results.append(new_res)
333
347
334
348
# make sure we find a good name
@@ -339,7 +353,8 @@ def agg_list_like(self) -> DataFrame | Series:
339
353
indices = []
340
354
for index, col in enumerate(selected_obj):
341
355
colg = obj._gotitem(col, ndim=1, subset=selected_obj.iloc[:, index])
342
- new_res = colg.aggregate(func, *this_args, **self.kwargs)
356
+ args = [self.axis, *self.args] if include_axis(colg) else self.args
357
+ new_res = getattr(colg, op_name)(func, *args, **kwargs)
343
358
results.append(new_res)
344
359
indices.append(index)
345
360
keys = selected_obj.columns.take(indices)
@@ -366,15 +381,23 @@ def agg_dict_like(self) -> DataFrame | Series:
366
381
-------
367
382
Result of aggregation.
368
383
"""
384
+ return self.agg_or_apply_dict_like(op_name="agg")
385
+
386
+ def agg_or_apply_dict_like(
387
+ self, op_name: Literal["agg", "apply"]
388
+ ) -> DataFrame | Series:
369
389
from pandas import Index
370
390
from pandas.core.groupby.generic import (
371
391
DataFrameGroupBy,
372
392
SeriesGroupBy,
373
393
)
374
394
from pandas.core.reshape.concat import concat
375
395
396
+ assert op_name in ["agg", "apply"]
397
+
376
398
obj = self.obj
377
399
func = cast(AggFuncTypeDict, self.func)
400
+ kwargs = {"by_row": False} if op_name == "apply" else {}
378
401
379
402
if getattr(obj, "axis", 0) == 1:
380
403
raise NotImplementedError("axis other than 0 is not supported")
@@ -387,7 +410,7 @@ def agg_dict_like(self) -> DataFrame | Series:
387
410
selected_obj = obj._selected_obj
388
411
selection = obj._selection
389
412
390
- func = self.normalize_dictlike_arg("agg" , selected_obj, func)
413
+ func = self.normalize_dictlike_arg(op_name , selected_obj, func)
391
414
392
415
is_groupby = isinstance(obj, (DataFrameGroupBy, SeriesGroupBy))
393
416
context_manager: ContextManager
@@ -404,17 +427,18 @@ def agg_dict_like(self) -> DataFrame | Series:
404
427
)
405
428
406
429
# Numba Groupby engine/engine-kwargs passthrough
407
- kwargs = {}
408
430
if is_groupby:
409
431
engine = self.kwargs.get("engine", None)
410
432
engine_kwargs = self.kwargs.get("engine_kwargs", None)
411
- kwargs = {"engine": engine, "engine_kwargs": engine_kwargs}
433
+ kwargs.update( {"engine": engine, "engine_kwargs": engine_kwargs})
412
434
413
435
with context_manager:
414
436
if selected_obj.ndim == 1:
415
437
# key only used for output
416
438
colg = obj._gotitem(selection, ndim=1)
417
- result_data = [colg.agg(how, **kwargs) for _, how in func.items()]
439
+ result_data = [
440
+ getattr(colg, op_name)(how, **kwargs) for _, how in func.items()
441
+ ]
418
442
result_index = list(func.keys())
419
443
elif is_non_unique_col:
420
444
# key used for column selection and output
@@ -429,7 +453,9 @@ def agg_dict_like(self) -> DataFrame | Series:
429
453
label_to_indices[label].append(index)
430
454
431
455
key_data = [
432
- selected_obj._ixs(indice, axis=1).agg(how, **kwargs)
456
+ getattr(selected_obj._ixs(indice, axis=1), op_name)(
457
+ how, **kwargs
458
+ )
433
459
for label, indices in label_to_indices.items()
434
460
for indice in indices
435
461
]
@@ -439,7 +465,7 @@ def agg_dict_like(self) -> DataFrame | Series:
439
465
else:
440
466
# key used for column selection and output
441
467
result_data = [
442
- obj._gotitem(key, ndim=1).agg (how, **kwargs)
468
+ getattr( obj._gotitem(key, ndim=1), op_name) (how, **kwargs)
443
469
for key, how in func.items()
444
470
]
445
471
result_index = list(func.keys())
@@ -535,7 +561,7 @@ def apply_str(self) -> DataFrame | Series:
535
561
self.kwargs["axis"] = self.axis
536
562
return self._apply_str(obj, func, *self.args, **self.kwargs)
537
563
538
- def apply_multiple (self) -> DataFrame | Series:
564
+ def apply_list_or_dict_like (self) -> DataFrame | Series:
539
565
"""
540
566
Compute apply in case of a list-like or dict-like.
541
567
@@ -551,9 +577,9 @@ def apply_multiple(self) -> DataFrame | Series:
551
577
kwargs = self.kwargs
552
578
553
579
if is_dict_like(func):
554
- result = self.agg_dict_like( )
580
+ result = self.agg_or_apply_dict_like(op_name="apply" )
555
581
else:
556
- result = self.agg_list_like( )
582
+ result = self.agg_or_apply_list_like(op_name="apply" )
557
583
558
584
result = reconstruct_and_relabel_result(result, func, **kwargs)
559
585
@@ -692,9 +718,9 @@ def values(self):
692
718
693
719
def apply(self) -> DataFrame | Series:
694
720
"""compute the results"""
695
- # dispatch to agg
721
+ # dispatch to handle list-like or dict-like
696
722
if is_list_like(self.func):
697
- return self.apply_multiple ()
723
+ return self.apply_list_or_dict_like ()
698
724
699
725
# all empty
700
726
if len(self.columns) == 0 and len(self.index) == 0:
@@ -1041,13 +1067,15 @@ def infer_to_same_shape(self, results: ResType, res_index: Index) -> DataFrame:
1041
1067
class SeriesApply(NDFrameApply):
1042
1068
obj: Series
1043
1069
axis: AxisInt = 0
1070
+ by_row: bool # only relevant for apply()
1044
1071
1045
1072
def __init__(
1046
1073
self,
1047
1074
obj: Series,
1048
1075
func: AggFuncType,
1049
1076
*,
1050
1077
convert_dtype: bool | lib.NoDefault = lib.no_default,
1078
+ by_row: bool = True,
1051
1079
args,
1052
1080
kwargs,
1053
1081
) -> None:
@@ -1062,6 +1090,7 @@ def __init__(
1062
1090
stacklevel=find_stack_level(),
1063
1091
)
1064
1092
self.convert_dtype = convert_dtype
1093
+ self.by_row = by_row
1065
1094
1066
1095
super().__init__(
1067
1096
obj,
@@ -1078,9 +1107,9 @@ def apply(self) -> DataFrame | Series:
1078
1107
if len(obj) == 0:
1079
1108
return self.apply_empty_result()
1080
1109
1081
- # dispatch to agg
1110
+ # dispatch to handle list-like or dict-like
1082
1111
if is_list_like(self.func):
1083
- return self.apply_multiple ()
1112
+ return self.apply_list_or_dict_like ()
1084
1113
1085
1114
if isinstance(self.func, str):
1086
1115
# if we are a string, try to dispatch
@@ -1126,6 +1155,8 @@ def apply_standard(self) -> DataFrame | Series:
1126
1155
if isinstance(func, np.ufunc):
1127
1156
with np.errstate(all="ignore"):
1128
1157
return func(obj, *self.args, **self.kwargs)
1158
+ elif not self.by_row:
1159
+ return func(obj, *self.args, **self.kwargs)
1129
1160
1130
1161
if self.args or self.kwargs:
1131
1162
# _map_values does not support args/kwargs
0 commit comments