Repository: modin-project/modin

Issue:
unique function implementation



Discussion:

Resolving patch:
diff --git a/modin/backends/base/query_compiler.py b/modin/backends/base/query_compiler.py
--- a/modin/backends/base/query_compiler.py
+++ b/modin/backends/base/query_compiler.py
@@ -382,6 +382,10 @@ def notna(self):
     def round(self, **kwargs):
         pass
 
+    @abc.abstractmethod
+    def unique(self, **kwargs):
+        pass
+
     # END Abstract map partitions operations
 
     # Abstract map partitions across select indices
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
@@ -430,6 +430,19 @@ def transpose(self, *args, **kwargs):
 
     # END String map partitions operations
 
+    def unique(self):
+        """Return unique values of Series object.
+
+        Returns
+        -------
+        ndarray
+            The unique values returned as a NumPy array.
+        """
+        new_modin_frame = self._modin_frame._apply_full_axis(
+            0, lambda x: x.squeeze().unique(), new_columns=self.columns,
+        )
+        return self.__constructor__(new_modin_frame)
+
     def astype(self, col_dtypes, **kwargs):
         """Converts columns dtypes to given dtypes.
 
diff --git a/modin/pandas/series.py b/modin/pandas/series.py
--- a/modin/pandas/series.py
+++ b/modin/pandas/series.py
@@ -1224,7 +1224,18 @@ def truncate(self, before=None, after=None, axis=None, copy=True):
         )
 
     def unique(self):
-        return self._default_to_pandas(pandas.Series.unique)
+        """
+        Return unique values of Series object.
+
+        Uniques are returned in order of appearance. Hash table-based unique,
+        therefore does NOT sort.
+
+        Returns
+        -------
+        ndarray
+            The unique values returned as a NumPy array.
+        """
+        return self._query_compiler.unique().to_numpy().squeeze()
 
     def update(self, other):
         return self._default_to_pandas(pandas.Series.update, other)


Test patch:
diff --git a/modin/pandas/test/test_series.py b/modin/pandas/test/test_series.py
--- a/modin/pandas/test/test_series.py
+++ b/modin/pandas/test/test_series.py
@@ -2688,9 +2688,40 @@ def test_tz_localize():
 
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
 def test_unique(data):
-    modin_series, _ = create_test_series(data)  # noqa: F841
-    with pytest.warns(UserWarning):
-        modin_series.unique()
+    modin_series, pandas_series = create_test_series(data)
+    modin_result = modin_series.unique()
+    pandas_result = pandas_series.unique()
+    assert_array_equal(modin_result, pandas_result)
+
+    modin_result = pd.Series([2, 1, 3, 3], name="A").unique()
+    pandas_result = pandas.Series([2, 1, 3, 3], name="A").unique()
+    assert_array_equal(modin_result, pandas_result)
+
+    modin_result = pd.Series([pd.Timestamp("2016-01-01") for _ in range(3)]).unique()
+    pandas_result = pandas.Series(
+        [pd.Timestamp("2016-01-01") for _ in range(3)]
+    ).unique()
+    assert_array_equal(modin_result, pandas_result)
+
+    modin_result = pd.Series(
+        [pd.Timestamp("2016-01-01", tz="US/Eastern") for _ in range(3)]
+    ).unique()
+    pandas_result = pandas.Series(
+        [pd.Timestamp("2016-01-01", tz="US/Eastern") for _ in range(3)]
+    ).unique()
+    assert_array_equal(modin_result, pandas_result)
+
+    modin_result = pandas.Series(pd.Categorical(list("baabc"))).unique()
+    pandas_result = pd.Series(pd.Categorical(list("baabc"))).unique()
+    assert_array_equal(modin_result, pandas_result)
+
+    modin_result = pd.Series(
+        pd.Categorical(list("baabc"), categories=list("abc"), ordered=True)
+    ).unique()
+    pandas_result = pandas.Series(
+        pd.Categorical(list("baabc"), categories=list("abc"), ordered=True)
+    ).unique()
+    assert_array_equal(modin_result, pandas_result)
 
 
 def test_unstack():