Repository: modin-project/modin

Issue:
BUG: series groupby list of numpy methods gives wrong column names
This is upstreaming https://github.com/ponder-org/modin-public/commit/c3013cdc8fa97d7fb5dcc7c99cb5a9d8e67d55a7

I don't have the error on hand right now.


Discussion:
```python
import modin.pandas as pd
import numpy as np

df = pd.DataFrame([[1, 2]])
df.groupby(0)[1].agg([np.mean, np.sum, np.min])
```

output looks like

```
   <function mean at 0x7f9dc63f7280>  <function sum at 0x7f9dc63efdc0>  <function amin at 0x7f9dc63f3820>
0
1                                2.0                                 2                                  2
```

but should look like

```python
   mean  sum  amin
0
1   2.0    2     2
```

I'm on pandas 1.5.3, modin 0.20.0+47.g632d724ad

Resolving patch:
diff --git a/modin/pandas/groupby.py b/modin/pandas/groupby.py
--- a/modin/pandas/groupby.py
+++ b/modin/pandas/groupby.py
@@ -678,12 +678,6 @@ def aggregate(self, func=None, *args, **kwargs):
 
         do_relabel = None
         if isinstance(func, dict) or func is None:
-
-            def try_get_str_func(fn):
-                if not isinstance(fn, str) and isinstance(fn, Iterable):
-                    return [try_get_str_func(f) for f in fn]
-                return fn.__name__ if callable(fn) and fn.__name__ in dir(self) else fn
-
             relabeling_required, func_dict, new_columns, order = reconstruct_func(
                 func, **kwargs
             )
@@ -711,7 +705,6 @@ def do_relabel(obj_to_relabel):
                     result.columns = new_columns_idx
                     return result
 
-            func_dict = {col: try_get_str_func(fn) for col, fn in func_dict.items()}
             if any(isinstance(fn, list) for fn in func_dict.values()):
                 # multicolumn case
                 # putting functions in a `list` allows to achieve multicolumn in each partition
@@ -1496,6 +1489,32 @@ def _iter(self):
                 for k in (sorted(group_ids) if self._sort else group_ids)
             )
 
+    def _try_get_str_func(self, fn):
+        """
+        Try to convert a groupby aggregation function to a string or list of such.
+
+        Parameters
+        ----------
+        fn : callable, str, or Iterable
+
+        Returns
+        -------
+        str, list
+            If `fn` is a callable, return its name if it's a method of the groupby
+            object, otherwise return `fn` itself. If `fn` is a string, return it.
+            If `fn` is an Iterable, return a list of _try_get_str_func applied to
+            each element of `fn`.
+        """
+        if not isinstance(fn, str) and isinstance(fn, Iterable):
+            return [self._try_get_str_func(f) for f in fn]
+        if fn is np.max:
+            # np.max is called "amax", so it's not a method of the groupby object.
+            return "amax"
+        elif fn is np.min:
+            # np.min is called "amin", so it's not a method of the groupby object.
+            return "amin"
+        return fn.__name__ if callable(fn) and fn.__name__ in dir(self) else fn
+
     def value_counts(
         self,
         normalize: bool = False,
@@ -1574,7 +1593,7 @@ def aggregate(self, func=None, *args, **kwargs):
             # the new column represents. alternatively we could give the query compiler
             # a hint that it's for a series, not a dataframe.
             maybe_squeezed = result.squeeze() if self._squeeze else result
-            return maybe_squeezed.set_axis(labels=func, axis=1)
+            return maybe_squeezed.set_axis(labels=self._try_get_str_func(func), axis=1)
         else:
             return super().aggregate(func, *args, **kwargs)
 


Test patch:
diff --git a/modin/pandas/test/test_groupby.py b/modin/pandas/test/test_groupby.py
--- a/modin/pandas/test/test_groupby.py
+++ b/modin/pandas/test/test_groupby.py
@@ -1023,7 +1023,16 @@ def test_series_groupby(by, as_index_series_or_dataframe):
             eval_var(modin_groupby, pandas_groupby)
             eval_skew(modin_groupby, pandas_groupby)
 
-        agg_functions = [lambda df: df.sum(), "min", "max", max, sum]
+        agg_functions = [
+            lambda df: df.sum(),
+            "min",
+            "max",
+            max,
+            sum,
+            np.mean,
+            ["min", "max"],
+            [np.mean, np.std, np.var, np.max, np.min],
+        ]
         for func in agg_functions:
             eval_agg(modin_groupby, pandas_groupby, func)
             eval_aggregate(modin_groupby, pandas_groupby, func)