Repository: modin-project/modin

Issue:
Multi-column named groupby aggregation is broken
### Reproducer:
```python
import modin.pandas as pd
import numpy as np

nrows = 256
ncols = 128
data = {
    f"col{i}": np.random.randint(0, 100, nrows)
    for i in np.arange(ncols)
}

agg_fn = {"max": ("col1", np.max), "min": ("col127", np.min)}

df = pd.DataFrame(data)
res = df.groupby("col0").agg(**agg_fn) # KeyError: 'col127' does not exist
print(res)
```
<!--
You can obtain the Modin version with

python -c "import modin; print(modin.__version__)"
-->

### Describe the problem
That happens because In the current implementation we assume, that every column from dict function exists in every partition, however that's not true. We probably should check that partition on what we're applying on, contains all columns from dict, otherwise drop them from dict



Discussion:

Resolving patch:
diff --git a/modin/backends/pandas/query_compiler.py b/modin/backends/pandas/query_compiler.py
--- a/modin/backends/pandas/query_compiler.py
+++ b/modin/backends/pandas/query_compiler.py
@@ -2606,11 +2606,15 @@ def groupby_agg_builder(df):
             def compute_groupby(df):
                 grouped_df = df.groupby(by=by, axis=axis, **groupby_kwargs)
                 try:
-                    result = (
-                        grouped_df.agg(agg_func)
-                        if isinstance(agg_func, dict)
-                        else agg_func(grouped_df, **agg_kwargs)
-                    )
+                    if isinstance(agg_func, dict):
+                        # Filter our keys that don't exist in this partition. This happens when some columns
+                        # from this original dataframe didn't end up in every partition.
+                        partition_dict = {
+                            k: v for k, v in agg_func.items() if k in df.columns
+                        }
+                        result = grouped_df.agg(partition_dict)
+                    else:
+                        result = agg_func(grouped_df, **agg_kwargs)
                 # This happens when the partition is filled with non-numeric data and a
                 # numeric operation is done. We need to build the index here to avoid
                 # issues with extracting the index.


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
@@ -22,6 +22,7 @@
     check_df_columns_have_nans,
     create_test_dfs,
     eval_general,
+    test_data,
     test_data_values,
     modin_df_almost_equals_pandas,
 )
@@ -1189,23 +1190,36 @@ def test_shift_freq(groupby_axis, shift_axis):
         )
 
 
-def test_agg_func_None_rename():
-    pandas_df = pandas.DataFrame(
+@pytest.mark.parametrize(
+    "by_and_agg_dict",
+    [
         {
-            "col1": np.random.randint(0, 100, size=1000),
-            "col2": np.random.randint(0, 100, size=1000),
-            "col3": np.random.randint(0, 100, size=1000),
-            "col4": np.random.randint(0, 100, size=1000),
+            "by": [
+                list(test_data["int_data"].keys())[0],
+                list(test_data["int_data"].keys())[1],
+            ],
+            "agg_dict": {
+                "max": (list(test_data["int_data"].keys())[2], np.max),
+                "min": (list(test_data["int_data"].keys())[2], np.min),
+            },
         },
-        index=["row{}".format(i) for i in range(1000)],
-    )
-    modin_df = from_pandas(pandas_df)
+        {
+            "by": ["col1"],
+            "agg_dict": {
+                "max": (list(test_data["int_data"].keys())[0], np.max),
+                "min": (list(test_data["int_data"].keys())[-1], np.min),
+            },
+        },
+    ],
+)
+def test_agg_func_None_rename(by_and_agg_dict):
+    modin_df, pandas_df = create_test_dfs(test_data["int_data"])
 
-    modin_result = modin_df.groupby(["col1", "col2"]).agg(
-        max=("col3", np.max), min=("col3", np.min)
+    modin_result = modin_df.groupby(by_and_agg_dict["by"]).agg(
+        **by_and_agg_dict["agg_dict"]
     )
-    pandas_result = pandas_df.groupby(["col1", "col2"]).agg(
-        max=("col3", np.max), min=("col3", np.min)
+    pandas_result = pandas_df.groupby(by_and_agg_dict["by"]).agg(
+        **by_and_agg_dict["agg_dict"]
     )
     df_equals(modin_result, pandas_result)