Repository: modin-project/modin

Issue:
KeyError from groupby over a DF with FrozenList multi-index as groupby key 
### System information
OS X 11.6.4
Modin version '0.15.2'
Python 3.9.12*:

### Describe the problem
<!-- Describe the problem clearly here. -->
KeyError occurs in modin query_compiler when using a FrozenList with more than one element as groupby key.

### Source code / logs
Notes:
1. Replace line 3 to `x = x.set_index('a')` and it will run, no problems.
2. Use `x.groupby(list(x.index.names))` and it will run, no problems.

```
import modin.pandas as pd
x = pd.DataFrame(data={"a":[1,2,3], "b":[1,2,3], "c":[1,2,3]})
x = x.set_index(['a','b'])
print(x.index.names) # FrozenList(['a', 'b'])
count = x.groupby(x.index.names) \
        .count()
```

Stack Trace:

```
<class 'modin.core.storage_formats.pandas.query_compiler.PandasQueryCompiler'>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Caskroom/miniforge/base/envs/enobase3/lib/python3.9/site-packages/modin/logging/logger_metaclass.py", line 68, in log_wrap
    return method(*args, **kwargs)
  File "/usr/local/Caskroom/miniforge/base/envs/enobase3/lib/python3.9/site-packages/modin/pandas/dataframe.py", line 445, in groupby
    by = self.__getitem__(by)._query_compiler
  File "/usr/local/Caskroom/miniforge/base/envs/enobase3/lib/python3.9/site-packages/modin/logging/logger_metaclass.py", line 68, in log_wrap
    return method(*args, **kwargs)
  File "/usr/local/Caskroom/miniforge/base/envs/enobase3/lib/python3.9/site-packages/modin/pandas/base.py", line 3650, in __getitem__
    return self._getitem(key)
  File "/usr/local/Caskroom/miniforge/base/envs/enobase3/lib/python3.9/site-packages/modin/logging/logger_metaclass.py", line 68, in log_wrap
    return method(*args, **kwargs)
  File "/usr/local/Caskroom/miniforge/base/envs/enobase3/lib/python3.9/site-packages/modin/pandas/dataframe.py", line 2994, in _getitem
    return DataFrame(query_compiler=self._query_compiler.getitem_array(key))
  File "/usr/local/Caskroom/miniforge/base/envs/enobase3/lib/python3.9/site-packages/modin/logging/logger_metaclass.py", line 68, in log_wrap
    return method(*args, **kwargs)
  File "/usr/local/Caskroom/miniforge/base/envs/enobase3/lib/python3.9/site-packages/modin/core/storage_formats/pandas/query_compiler.py", line 2167, in getitem_array
    "{} not index".format(
KeyError: "['a' 'b'] not index"
```



Discussion:
@meijiu thanks for posting this issue! Looks like the `FrozenList` is not getting treated as a "list-like" object. I've identified the issue to the `groupby` call in `modin/pandas/dataframe.py` where we check if `by` is hashable. While lists are normally not hashable, it seems that `FrozenLists` are. We should check that `by` is not a `FrozenList` and treat it like a list if it is since it does return True for `is_list_like()`. This bug was quite subtle - thanks for the good find! 

Resolving patch:
diff --git a/modin/pandas/dataframe.py b/modin/pandas/dataframe.py
--- a/modin/pandas/dataframe.py
+++ b/modin/pandas/dataframe.py
@@ -21,6 +21,7 @@
     is_list_like,
     is_numeric_dtype,
 )
+from pandas.core.indexes.frozen import FrozenList
 from pandas.util._validators import validate_bool_kwarg
 from pandas.io.formats.printing import pprint_thing
 from pandas._libs.lib import no_default
@@ -434,7 +435,7 @@ def groupby(
 
         if callable(by):
             by = self.index.map(by)
-        elif hashable(by) and not isinstance(by, pandas.Grouper):
+        elif hashable(by) and not isinstance(by, (pandas.Grouper, FrozenList)):
             drop = by in self.columns
             idx_name = by
             if by is not None and by in self._query_compiler.get_index_names(axis):


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
@@ -2063,3 +2063,10 @@ def test_sum_with_level():
     }
     modin_df, pandas_df = pd.DataFrame(data), pandas.DataFrame(data)
     eval_general(modin_df, pandas_df, lambda df: df.set_index("C").groupby("C").sum())
+
+
+def test_groupby_with_frozenlist():
+    pandas_df = pandas.DataFrame(data={"a": [1, 2, 3], "b": [1, 2, 3], "c": [1, 2, 3]})
+    pandas_df = pandas_df.set_index(["a", "b"])
+    modin_df = from_pandas(pandas_df)
+    eval_general(modin_df, pandas_df, lambda df: df.groupby(df.index.names).count())