Skip to content

Commit ded51c8

Browse files
committed
BUG: .ix setting logic error with non-unique MultiIndex close #1750
1 parent e47bf26 commit ded51c8

File tree

4 files changed

+36
-3
lines changed

4 files changed

+36
-3
lines changed

RELEASE.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pandas 0.8.2
8888
- Fix handling of DatetimeIndex in DataFrame.to_records (#1720)
8989
- Fix handling of general objects in isnull on which bool(...) fails (#1749)
9090
- Fix .ix indexing with MultiIndex ambiguity (#1678)
91+
- Fix .ix setting logic error with non-unique MultiIndex (#1750)
9192

9293
pandas 0.8.1
9394
============

pandas/core/index.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,7 +2022,10 @@ def get_loc(self, key):
20222022
"""
20232023
if isinstance(key, tuple):
20242024
if len(key) == self.nlevels:
2025-
return self._engine.get_loc(key)
2025+
if self.is_unique:
2026+
return self._engine.get_loc(key)
2027+
else:
2028+
return slice(*self.slice_locs(key, key))
20262029
else:
20272030
# partial selection
20282031
result = slice(*self.slice_locs(key, key))
@@ -2078,7 +2081,11 @@ def _drop_levels(indexer, levels):
20782081

20792082
if not any(isinstance(k, slice) for k in key):
20802083
if len(key) == self.nlevels:
2081-
return self._engine.get_loc(key), None
2084+
if self.is_unique:
2085+
return self._engine.get_loc(key), None
2086+
else:
2087+
indexer = slice(*self.slice_locs(key, key))
2088+
return indexer, self[indexer]
20822089
else:
20832090
# partial selection
20842091
indexer = slice(*self.slice_locs(key, key))

pandas/core/indexing.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pandas.core.common import _asarray_tuplesafe
44
from pandas.core.index import Index, MultiIndex
55
import pandas.core.common as com
6+
import pandas.lib as lib
67

78
import numpy as np
89

@@ -409,7 +410,20 @@ def _convert_to_indexer(self, obj, axis=0):
409410
check = labels.levels[0].get_indexer(objarr)
410411
else:
411412
level = None
412-
indexer = check = labels.get_indexer(objarr)
413+
# XXX
414+
if labels.is_unique:
415+
indexer = check = labels.get_indexer(objarr)
416+
else:
417+
mask = np.zeros(len(labels), dtype=bool)
418+
lvalues = labels.values
419+
for x in objarr:
420+
# ugh
421+
to_or = lib.map_infer(lvalues, x.__eq__)
422+
if not to_or.any():
423+
raise KeyError('%s not in index' % str(x))
424+
mask |= to_or
425+
426+
indexer = check = mask.nonzero()[0]
413427

414428
mask = check == -1
415429
if mask.any():

pandas/tests/test_multilevel.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,17 @@ def test_indexing_ambiguity_bug_1678(self):
14561456
self.assert_(isinstance(result, Series))
14571457
assert_series_equal(result, exp)
14581458

1459+
def test_nonunique_assignment_1750(self):
1460+
df = DataFrame([[1, 1, "x", "X"], [1, 1, "y", "Y"], [1, 2, "z", "Z"]],
1461+
columns=list("ABCD"))
1462+
1463+
df = df.set_index(['A', 'B'])
1464+
ix = MultiIndex.from_tuples([(1, 1)])
1465+
1466+
df.ix[ix, "C"] = '_'
1467+
1468+
self.assert_((df.xs((1, 1))['C'] == '_').all())
1469+
14591470
if __name__ == '__main__':
14601471

14611472
# unittest.main()

0 commit comments

Comments
 (0)