Skip to content

Commit 796907b

Browse files
jschendelPingviinituutti
authored andcommitted
BUG: Fix Series.is_unique with single occurrence of NaN (pandas-dev#25182)
1 parent 77704af commit 796907b

File tree

8 files changed

+51
-44
lines changed

8 files changed

+51
-44
lines changed

doc/source/whatsnew/v0.24.2.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Bug Fixes
8787

8888
**Other**
8989

90-
-
90+
- Bug in :meth:`Series.is_unique` where single occurrences of ``NaN`` were not considered unique (:issue:`25180`)
9191
-
9292
-
9393

pandas/core/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ def is_unique(self):
13651365
-------
13661366
is_unique : boolean
13671367
"""
1368-
return self.nunique() == len(self)
1368+
return self.nunique(dropna=False) == len(self)
13691369

13701370
@property
13711371
def is_monotonic(self):

pandas/tests/indexes/common.py

+21
Original file line numberDiff line numberDiff line change
@@ -913,3 +913,24 @@ def test_astype_category(self, copy, name, ordered):
913913
result = index.astype('category', copy=copy)
914914
expected = CategoricalIndex(index.values, name=name)
915915
tm.assert_index_equal(result, expected)
916+
917+
def test_is_unique(self):
918+
# initialize a unique index
919+
index = self.create_index().drop_duplicates()
920+
assert index.is_unique is True
921+
922+
# empty index should be unique
923+
index_empty = index[:0]
924+
assert index_empty.is_unique is True
925+
926+
# test basic dupes
927+
index_dup = index.insert(0, index[0])
928+
assert index_dup.is_unique is False
929+
930+
# single NA should be unique
931+
index_na = index.insert(0, np.nan)
932+
assert index_na.is_unique is True
933+
934+
# multiple NA should not be unique
935+
index_na_dup = index_na.insert(0, np.nan)
936+
assert index_na_dup.is_unique is False

pandas/tests/indexes/interval/test_interval.py

+4-15
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,10 @@ def test_take(self, closed):
242242
[0, 0, 1], [1, 1, 2], closed=closed)
243243
tm.assert_index_equal(result, expected)
244244

245-
def test_unique(self, closed):
246-
# unique non-overlapping
247-
idx = IntervalIndex.from_tuples(
248-
[(0, 1), (2, 3), (4, 5)], closed=closed)
249-
assert idx.is_unique is True
250-
245+
def test_is_unique_interval(self, closed):
246+
"""
247+
Interval specific tests for is_unique in addition to base class tests
248+
"""
251249
# unique overlapping - distinct endpoints
252250
idx = IntervalIndex.from_tuples([(0, 1), (0.5, 1.5)], closed=closed)
253251
assert idx.is_unique is True
@@ -261,15 +259,6 @@ def test_unique(self, closed):
261259
idx = IntervalIndex.from_tuples([(-1, 1), (-2, 2)], closed=closed)
262260
assert idx.is_unique is True
263261

264-
# duplicate
265-
idx = IntervalIndex.from_tuples(
266-
[(0, 1), (0, 1), (2, 3)], closed=closed)
267-
assert idx.is_unique is False
268-
269-
# empty
270-
idx = IntervalIndex([], closed=closed)
271-
assert idx.is_unique is True
272-
273262
def test_monotonic(self, closed):
274263
# increasing non-overlapping
275264
idx = IntervalIndex.from_tuples(

pandas/tests/indexes/multi/test_duplicates.py

+12
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ def test_has_duplicates(idx, idx_dup):
143143
assert mi.is_unique is False
144144
assert mi.has_duplicates is True
145145

146+
# single instance of NaN
147+
mi_nan = MultiIndex(levels=[['a', 'b'], [0, 1]],
148+
codes=[[-1, 0, 0, 1, 1], [-1, 0, 1, 0, 1]])
149+
assert mi_nan.is_unique is True
150+
assert mi_nan.has_duplicates is False
151+
152+
# multiple instances of NaN
153+
mi_nan_dup = MultiIndex(levels=[['a', 'b'], [0, 1]],
154+
codes=[[-1, -1, 0, 0, 1, 1], [-1, -1, 0, 1, 0, 1]])
155+
assert mi_nan_dup.is_unique is False
156+
assert mi_nan_dup.has_duplicates is True
157+
146158

147159
def test_has_duplicates_from_tuples():
148160
# GH 9075

pandas/tests/indexes/period/test_indexing.py

-12
Original file line numberDiff line numberDiff line change
@@ -441,18 +441,6 @@ def test_is_monotonic_decreasing(self):
441441
assert idx_dec1.is_monotonic_decreasing is True
442442
assert idx.is_monotonic_decreasing is False
443443

444-
def test_is_unique(self):
445-
# GH 17717
446-
p0 = pd.Period('2017-09-01')
447-
p1 = pd.Period('2017-09-02')
448-
p2 = pd.Period('2017-09-03')
449-
450-
idx0 = pd.PeriodIndex([p0, p1, p2])
451-
assert idx0.is_unique is True
452-
453-
idx1 = pd.PeriodIndex([p1, p1, p2])
454-
assert idx1.is_unique is False
455-
456444
def test_contains(self):
457445
# GH 17717
458446
p0 = pd.Period('2017-09-01')

pandas/tests/indexes/test_category.py

-9
Original file line numberDiff line numberDiff line change
@@ -611,15 +611,6 @@ def test_is_monotonic(self, data, non_lexsorted_data):
611611
assert c.is_monotonic_increasing is True
612612
assert c.is_monotonic_decreasing is False
613613

614-
@pytest.mark.parametrize('values, expected', [
615-
([1, 2, 3], True),
616-
([1, 3, 1], False),
617-
(list('abc'), True),
618-
(list('aba'), False)])
619-
def test_is_unique(self, values, expected):
620-
ci = CategoricalIndex(values)
621-
assert ci.is_unique is expected
622-
623614
def test_has_duplicates(self):
624615

625616
idx = CategoricalIndex([0, 0, 0], name='foo')

pandas/tests/series/test_duplicates.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,18 @@ def test_unique_data_ownership():
5959
Series(Series(["a", "c", "b"]).unique()).sort_values()
6060

6161

62-
def test_is_unique():
63-
# GH11946
64-
s = Series(np.random.randint(0, 10, size=1000))
65-
assert s.is_unique is False
66-
s = Series(np.arange(1000))
67-
assert s.is_unique is True
62+
@pytest.mark.parametrize('data, expected', [
63+
(np.random.randint(0, 10, size=1000), False),
64+
(np.arange(1000), True),
65+
([], True),
66+
([np.nan], True),
67+
(['foo', 'bar', np.nan], True),
68+
(['foo', 'foo', np.nan], False),
69+
(['foo', 'bar', np.nan, np.nan], False)])
70+
def test_is_unique(data, expected):
71+
# GH11946 / GH25180
72+
s = Series(data)
73+
assert s.is_unique is expected
6874

6975

7076
def test_is_unique_class_ne(capsys):

0 commit comments

Comments
 (0)