Repository: modin-project/modin

Issue:
[OmniSci] Support 'nunique' aggregate
We need to support aggregation like `df.groupby('col1').agg('col2' : 'nunique')`


Discussion:

Resolving patch:
diff --git a/modin/experimental/backends/omnisci/query_compiler.py b/modin/experimental/backends/omnisci/query_compiler.py
--- a/modin/experimental/backends/omnisci/query_compiler.py
+++ b/modin/experimental/backends/omnisci/query_compiler.py
@@ -359,7 +359,7 @@ def nunique(self, axis=0, dropna=True):
             raise NotImplementedError(
                 f"OmniSci's nunique does not support such set of parameters: axis={axis}, dropna={dropna}."
             )
-        return self._agg("count", distinct=True)
+        return self._agg("nunique")
 
     def _agg(self, agg, axis=0, level=None, **kwargs):
         """
@@ -400,7 +400,7 @@ def _agg(self, agg, axis=0, level=None, **kwargs):
         kwargs.pop("skipna", None)
         kwargs.pop("numeric_only", None)
 
-        new_frame = self._modin_frame.agg(agg, **kwargs)
+        new_frame = self._modin_frame.agg(agg)
         new_frame = new_frame._set_index(
             pandas.Index.__new__(pandas.Index, data=["__reduced__"], dtype="O")
         )
diff --git a/modin/experimental/engines/omnisci_on_ray/frame/data.py b/modin/experimental/engines/omnisci_on_ray/frame/data.py
--- a/modin/experimental/engines/omnisci_on_ray/frame/data.py
+++ b/modin/experimental/engines/omnisci_on_ray/frame/data.py
@@ -540,7 +540,7 @@ def generate_by_name(by):
                 new_frame = new_frame.mask(col_indices=filtered_columns)
         return new_frame
 
-    def agg(self, agg, **kwargs):
+    def agg(self, agg):
         """
         Perform specified aggregation along columns.
 
@@ -548,8 +548,6 @@ def agg(self, agg, **kwargs):
         ----------
         agg : str
             Name of the aggregation function to perform.
-        **kwargs : dict
-            Additional parameters to pass to the aggregation expression.
 
         Returns
         -------
@@ -560,7 +558,7 @@ def agg(self, agg, **kwargs):
 
         agg_exprs = OrderedDict()
         for col in self.columns:
-            agg_exprs[col] = AggregateExpr(agg, self.ref(col), **kwargs)
+            agg_exprs[col] = AggregateExpr(agg, self.ref(col))
 
         return self.__constructor__(
             columns=self.columns,
diff --git a/modin/experimental/engines/omnisci_on_ray/frame/expr.py b/modin/experimental/engines/omnisci_on_ray/frame/expr.py
--- a/modin/experimental/engines/omnisci_on_ray/frame/expr.py
+++ b/modin/experimental/engines/omnisci_on_ray/frame/expr.py
@@ -743,11 +743,17 @@ class AggregateExpr(BaseExpr):
     """
 
     def __init__(self, agg, op, distinct=False, dtype=None):
-        self.agg = agg
+        if agg == "nunique":
+            self.agg = "count"
+            self.distinct = True
+        else:
+            self.agg = agg
+            self.distinct = distinct
         self.operands = [op]
-        self._dtype = dtype if dtype else _agg_dtype(agg, op._dtype if op else None)
+        self._dtype = (
+            dtype if dtype else _agg_dtype(self.agg, op._dtype if op else None)
+        )
         assert self._dtype is not None
-        self.distinct = distinct
 
     def copy(self):
         """


Test patch:
diff --git a/modin/experimental/engines/omnisci_on_ray/test/test_dataframe.py b/modin/experimental/engines/omnisci_on_ray/test/test_dataframe.py
--- a/modin/experimental/engines/omnisci_on_ray/test/test_dataframe.py
+++ b/modin/experimental/engines/omnisci_on_ray/test/test_dataframe.py
@@ -745,9 +745,9 @@ def test_concat_index_names(self):
 
 class TestGroupby:
     data = {
-        "a": [1, 1, 2, 2, 2],
-        "b": [11, 21, 12, 22, 32],
-        "c": [101, 201, 102, 202, 302],
+        "a": [1, 1, 2, 2, 2, 1],
+        "b": [11, 21, 12, 22, 32, 11],
+        "c": [101, 201, 202, 202, 302, 302],
     }
     cols_value = ["a", ["a", "b"]]
 
@@ -788,17 +788,12 @@ def groupby_sum(df, cols, as_index, **kwargs):
             groupby_sum, data=self.data, cols=cols, as_index=as_index, force_lazy=False
         )
 
-    def test_groupby_agg_count(self):
-        def groupby(df, **kwargs):
-            return df.groupby("a").agg({"b": "count"})
-
-        run_and_compare(groupby, data=self.data)
+    @pytest.mark.parametrize("agg", ["count", "size", "nunique"])
+    def test_groupby_agg(self, agg):
+        def groupby(df, agg, **kwargs):
+            return df.groupby("a").agg({"b": agg})
 
-    def test_groupby_agg_size(self):
-        def groupby(df, **kwargs):
-            return df.groupby("a").agg({"b": "size"})
-
-        run_and_compare(groupby, data=self.data)
+        run_and_compare(groupby, data=self.data, agg=agg)
 
     def test_groupby_agg_default_to_pandas(self):
         def lambda_func(df, **kwargs):