Skip to content

BUG: Fix agg ingore arg/kwargs when given list like func #50863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 63 additions & 2 deletions pandas/core/apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from contextlib import nullcontext
from functools import partial
import inspect
from types import FunctionType
from typing import (
TYPE_CHECKING,
Any,
Expand Down Expand Up @@ -330,9 +331,18 @@ def agg_list_like(self) -> DataFrame | Series:
# degenerate case
if selected_obj.ndim == 1:

args_remain, kwargs_remain = self.args, self.kwargs
for a in arg:
colg = obj._gotitem(selected_obj.name, ndim=1, subset=selected_obj)
new_res = colg.aggregate(a)
if not isinstance(a, (np.ufunc, str)) and isinstance(
a, FunctionType
):
args_pass, kwargs_pass, args_remain, kwargs_remain = _map_args(
a, args_remain, kwargs_remain
)
new_res = colg.aggregate(a, *args_pass, **kwargs_pass)
else:
new_res = colg.aggregate(a)
results.append(new_res)

# make sure we find a good name
Expand All @@ -344,7 +354,7 @@ def agg_list_like(self) -> DataFrame | Series:
indices = []
for index, col in enumerate(selected_obj):
colg = obj._gotitem(col, ndim=1, subset=selected_obj.iloc[:, index])
new_res = colg.aggregate(arg)
new_res = colg.aggregate(arg, *self.args, **self.kwargs)
results.append(new_res)
indices.append(index)
keys = selected_obj.columns.take(indices)
Expand Down Expand Up @@ -1506,3 +1516,54 @@ def validate_func_kwargs(
no_arg_message = "Must provide 'func' or named aggregation **kwargs."
raise TypeError(no_arg_message)
return columns, func


def _map_args(
func: AggFuncType, args: tuple, kwargs: dict
) -> tuple[tuple, dict, tuple, dict]:
# GH 50624
"""
Map arguments to function.
But for some cases with unnamed arguments, it will cause error.

Parameters
----------
func : function
args : tuple
kwargs : dict

Returns
-------
args_pass : tuple
Args should be passed to func
kwargs_pass : dict
Kwargs should be passed to func
args_remain : tuple
Args should be passed to other functions
kwargs_remain : dict
Kwargs should be passed to other functions

Examples
--------
>>> def f(a=1, b=2):
... return a, b
>>> _map_args(f, (1,), {'b': 2, 'c': 3})
((1,), {'b': 2}, (), {'c': 3})
>>> _map_args(f, (1, 2, 3), {'b': 4}) # maybe some unexpected results
((1, 2), {}, (3,), {'b':4})
"""
argspec = inspect.getfullargspec(func)
args_names = argspec.args + argspec.kwonlyargs

if len(args) >= len(args_names):
args_pass = args[: len(args_names)]
args_remain = args[len(args_names) :]
kwargs_pass = {}
kwargs_remain = kwargs
else:
args_pass = args
args_remain = ()
kwargs_pass = {k: v for k, v in kwargs.items() if k in args_names}
kwargs_remain = {k: v for k, v in kwargs.items() if k not in args_names}

return args_pass, kwargs_pass, args_remain, kwargs_remain
19 changes: 19 additions & 0 deletions pandas/tests/apply/test_frame_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -1623,3 +1623,22 @@ def test_any_apply_keyword_non_zero_axis_regression():

result = df.apply("any", 1)
tm.assert_series_equal(result, expected)


def test_agg_list_like_arg():
# GH 50624
df = DataFrame({"x": [1, 2, 3]})

def foo1(x, a=1, b=2):
return x + a + b

def foo2(x, c=3, d=4):
return x + c + d

result = df.agg([foo1, foo2], 0, 5, b=6, c=7, d=8)
expected = DataFrame(
[[12, 16], [13, 17], [14, 18]],
columns=MultiIndex.from_tuples([("x", "foo1"), ("x", "foo2")]),
index=[0, 1, 2],
)
tm.assert_frame_equal(result, expected)