Repository: databricks/koalas

Issue:
Series.is_unique
Although an expensive function, this should be pretty easy to add. We can do a count distinct and compare it with the total cardinality.

pandas doc: http://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.is_unique.html


Discussion:

Resolving patch:
diff --git a/databricks/koalas/missing/series.py b/databricks/koalas/missing/series.py
--- a/databricks/koalas/missing/series.py
+++ b/databricks/koalas/missing/series.py
@@ -49,7 +49,6 @@ class _MissingPandasLikeSeries(object):
     is_monotonic = unsupported_property('is_monotonic')
     is_monotonic_decreasing = unsupported_property('is_monotonic_decreasing')
     is_monotonic_increasing = unsupported_property('is_monotonic_increasing')
-    is_unique = unsupported_property('is_unique')
     itemsize = unsupported_property('itemsize')
     ix = unsupported_property('ix')
     nbytes = unsupported_property('nbytes')
diff --git a/databricks/koalas/series.py b/databricks/koalas/series.py
--- a/databricks/koalas/series.py
+++ b/databricks/koalas/series.py
@@ -355,6 +355,36 @@ def index(self):
             raise KeyError('Currently supported only when the Column has a single index.')
         return self._kdf.index
 
+    @property
+    def is_unique(self):
+        """
+        Return boolean if values in the object are unique
+
+        Returns
+        -------
+        is_unique : boolean
+
+        >>> ks.Series([1, 2, 3]).is_unique
+        True
+        >>> ks.Series([1, 2, 2]).is_unique
+        False
+        >>> ks.Series([1, 2, 3, None]).is_unique
+        True
+        """
+        sdf = self._kdf._sdf.select(self._scol)
+        col = self._scol
+
+        # Here we check:
+        #   1. the distinct count without nulls and count without nulls for non-null values
+        #   2. count null values and see if null is a distinct value.
+        #
+        # This workaround is in order to calculate the distinct count including nulls in
+        # single pass. Note that COUNT(DISTINCT expr) in Spark is designed to ignore nulls.
+        return sdf.select(
+            (F.count(col) == F.countDistinct(col)) &
+            (F.count(F.when(col.isNull(), 1).otherwise(None)) <= 1)
+        ).collect()[0][0]
+
     def reset_index(self, level=None, drop=False, name=None, inplace=False):
         """
         Generate a new DataFrame or Series with the index reset.
@@ -758,12 +788,12 @@ def dropna(self, axis=0, inplace=False, **kwargs):
         Name: 0, dtype: float64
         """
         # TODO: last two examples from Pandas produce different results.
-        ks = _col(self.to_dataframe().dropna(axis=axis, inplace=False))
+        kser = _col(self.to_dataframe().dropna(axis=axis, inplace=False))
         if inplace:
-            self._kdf = ks._kdf
-            self._scol = ks._scol
+            self._kdf = kser._kdf
+            self._scol = kser._scol
         else:
-            return ks
+            return kser
 
     def clip(self, lower: Union[float, int] = None, upper: Union[float, int] = None) -> 'Series':
         """


Test patch:
diff --git a/databricks/koalas/tests/test_series.py b/databricks/koalas/tests/test_series.py
--- a/databricks/koalas/tests/test_series.py
+++ b/databricks/koalas/tests/test_series.py
@@ -255,3 +255,21 @@ def test_clip(self):
         # Assert behavior on string values
         str_ks = koalas.Series(['a', 'b', 'c'])
         self.assert_eq(str_ks.clip(1, 3), str_ks)
+
+    def test_is_unique(self):
+        # We can't use pandas' is_unique for comparison. pandas 0.23 ignores None
+        pser = pd.Series([1, 2, 2, None, None])
+        kser = koalas.from_pandas(pser)
+        self.assertEqual(False, kser.is_unique)
+
+        pser = pd.Series([1, None, None])
+        kser = koalas.from_pandas(pser)
+        self.assertEqual(False, kser.is_unique)
+
+        pser = pd.Series([1])
+        kser = koalas.from_pandas(pser)
+        self.assertEqual(pser.is_unique, kser.is_unique)
+
+        pser = pd.Series([1, 1, 1])
+        kser = koalas.from_pandas(pser)
+        self.assertEqual(pser.is_unique, kser.is_unique)