Skip to content

Commit c9df3d4

Browse files
committed
Merge pull request #7107 from jreback/mi_slicers
BUG: remove unique requirement rom MultiIndex.get_locs (GH7106)
2 parents 4c30610 + 8c1cc5a commit c9df3d4

File tree

4 files changed

+44
-5
lines changed

4 files changed

+44
-5
lines changed

doc/source/release.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ Improvements to existing features
295295
the func (:issue:`6289`)
296296
- ``plot(legend='reverse')`` will now reverse the order of legend labels for most plot kinds.
297297
(:issue:`6014`)
298-
- Allow multi-index slicers (:issue:`6134`, :issue:`4036`, :issue:`3057`, :issue:`2598`, :issue:`5641`)
298+
- Allow multi-index slicers (:issue:`6134`, :issue:`4036`, :issue:`3057`, :issue:`2598`, :issue:`5641`, :issue:`7106`)
299299
- improve performance of slice indexing on Series with string keys (:issue:`6341`, :issue:`6372`)
300300
- implement joining a single-level indexed DataFrame on a matching column of a multi-indexed DataFrame (:issue:`3662`)
301301
- Performance improvement in indexing into a multi-indexed Series (:issue:`5567`)

doc/source/v0.14.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ You can use ``slice(None)`` to select all the contents of *that* level. You do n
290290
As usual, **both sides** of the slicers are included as this is label indexing.
291291

292292
See :ref:`the docs<indexing.mi_slicers>`
293-
See also issues (:issue:`6134`, :issue:`4036`, :issue:`3057`, :issue:`2598`, :issue:`5641`)
293+
See also issues (:issue:`6134`, :issue:`4036`, :issue:`3057`, :issue:`2598`, :issue:`5641`, :issue:`7106`)
294294

295295
.. warning::
296296

pandas/core/index.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -2595,7 +2595,7 @@ def get_level_values(self, level):
25952595
unique = self.levels[num] # .values
25962596
labels = self.labels[num]
25972597
filled = com.take_1d(unique.values, labels, fill_value=unique._na_value)
2598-
values = unique._simple_new(filled, self.names[num],
2598+
values = unique._simple_new(filled, self.names[num],
25992599
freq=getattr(unique, 'freq', None),
26002600
tz=getattr(unique, 'tz', None))
26012601
return values
@@ -3556,8 +3556,6 @@ def get_locs(self, tup):
35563556
if not self.is_lexsorted_for_tuple(tup):
35573557
raise KeyError('MultiIndex Slicing requires the index to be fully lexsorted'
35583558
' tuple len ({0}), lexsort depth ({1})'.format(len(tup), self.lexsort_depth))
3559-
if not self.is_unique:
3560-
raise ValueError('MultiIndex Slicing requires a unique index')
35613559

35623560
def _convert_indexer(r):
35633561
if isinstance(r, slice):

pandas/tests/test_indexing.py

+41
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,47 @@ def f():
13561356
df.loc[(slice(None),[1])]
13571357
self.assertRaises(KeyError, f)
13581358

1359+
# not lexsorted
1360+
self.assertEquals(df.index.lexsort_depth,2)
1361+
df = df.sortlevel(level=1,axis=0)
1362+
self.assertEquals(df.index.lexsort_depth,0)
1363+
with tm.assertRaisesRegexp(KeyError, 'MultiIndex Slicing requires the index to be fully lexsorted tuple len \(2\), lexsort depth \(0\)'):
1364+
df.loc[(slice(None),df.loc[:,('a','bar')]>5),:]
1365+
1366+
def test_multiindex_slicers_non_unique(self):
1367+
1368+
# GH 7106
1369+
# non-unique mi index support
1370+
df = DataFrame(dict(A = ['foo','foo','foo','foo'],
1371+
B = ['a','a','a','a'],
1372+
C = [1,2,1,3],
1373+
D = [1,2,3,4])).set_index(['A','B','C']).sortlevel()
1374+
self.assertFalse(df.index.is_unique)
1375+
expected = DataFrame(dict(A = ['foo','foo'],
1376+
B = ['a','a'],
1377+
C = [1,1],
1378+
D = [1,3])).set_index(['A','B','C']).sortlevel()
1379+
result = df.loc[(slice(None),slice(None),1),:]
1380+
assert_frame_equal(result, expected)
1381+
1382+
# this is equivalent of an xs expression
1383+
result = df.xs(1,level=2,drop_level=False)
1384+
assert_frame_equal(result, expected)
1385+
1386+
df = DataFrame(dict(A = ['foo','foo','foo','foo'],
1387+
B = ['a','a','a','a'],
1388+
C = [1,2,1,2],
1389+
D = [1,2,3,4])).set_index(['A','B','C']).sortlevel()
1390+
self.assertFalse(df.index.is_unique)
1391+
expected = DataFrame(dict(A = ['foo','foo'],
1392+
B = ['a','a'],
1393+
C = [1,1],
1394+
D = [1,3])).set_index(['A','B','C']).sortlevel()
1395+
result = df.loc[(slice(None),slice(None),1),:]
1396+
self.assertFalse(result.index.is_unique)
1397+
assert_frame_equal(result, expected)
1398+
1399+
13591400
def test_per_axis_per_level_doc_examples(self):
13601401

13611402
# test index maker

0 commit comments

Comments
 (0)