Repository: pandas-dev/pandas

Issue:
BUG: duplicate selection with missing values raises
Hard to reprod.

Select from a duplicate indexed axis in a frame with ix where part of the
selection set is missing

```
In [22]: df = DataFrame(np.random.randn(5,5),columns=['A.1','B.1','B.2','B.3','A.2'],index=date_range('20130101',periods=5))

In [23]: df2 = df.rename(columns=lambda x: x.split('.')[0])

In [24]: df2
Out[24]: 
                   A         B         B         B         A
2013-01-01 -1.029245 -0.782139  0.584956  1.097301 -0.150675
2013-01-02 -0.723246 -0.356150 -0.441952  0.027012 -1.851583
2013-01-03 -1.001412  0.129464  0.093433  0.952615 -1.338390
2013-01-04  0.165987  0.227918  0.557940 -0.102501 -1.194053
2013-01-05  0.249493 -1.102096 -0.977755 -0.529540  0.783277

[5 rows x 5 columns]

In [25]: df2.ix[:,['A','B','C']]

AssertionError: Number of manager items must equal union of block items
# manager items: 6, # tot_items: 14
```



Discussion:

Resolving patch:
diff --git a/pandas/core/internals.py b/pandas/core/internals.py
--- a/pandas/core/internals.py
+++ b/pandas/core/internals.py
@@ -3119,6 +3119,9 @@ def reindex_indexer(self, new_axis, indexer, axis=1, fill_value=None,
         if not allow_dups and not self.axes[axis].is_unique:
             raise ValueError("cannot reindex from a duplicate axis")
 
+        if not self.is_consolidated():
+            self = self.consolidate()
+
         if axis == 0:
             return self._reindex_indexer_items(new_axis, indexer, fill_value)
 
@@ -3140,38 +3143,62 @@ def _reindex_indexer_items(self, new_items, indexer, fill_value):
         new_blocks = []
         is_unique = new_items.is_unique
 
+        # we have duplicates in the items and what we are reindexing
+        if not is_unique and not self.items.is_unique:
+
+            rl = self._set_ref_locs(do_refs='force')
+            for i, idx in enumerate(indexer):
+                item = new_items.take([i])
+                if idx >= 0:
+                    blk, lidx = rl[idx]
+                    blk = make_block(_block_shape(blk.iget(lidx)), item,
+                                     new_items, ndim=self.ndim, fastpath=True,
+                                     placement=[i])
+
+                # a missing value
+                else:
+                    blk = self._make_na_block(item,
+                                              new_items,
+                                              placement=[i],
+                                              fill_value=fill_value)
+                new_blocks.append(blk)
+            new_blocks = _consolidate(new_blocks, new_items)
+
+
         # keep track of what items aren't found anywhere
-        l = np.arange(len(item_order))
-        mask = np.zeros(len(item_order), dtype=bool)
-        for blk in self.blocks:
-            blk_indexer = blk.items.get_indexer(item_order)
-            selector = blk_indexer != -1
+        else:
+            l = np.arange(len(item_order))
+            mask = np.zeros(len(item_order), dtype=bool)
 
-            # update with observed items
-            mask |= selector
+            for blk in self.blocks:
+                blk_indexer = blk.items.get_indexer(item_order)
+                selector = blk_indexer != -1
+
+                # update with observed items
+                mask |= selector
 
-            if not selector.any():
-                continue
+                if not selector.any():
+                    continue
 
-            new_block_items = new_items.take(selector.nonzero()[0])
-            new_values = com.take_nd(blk.values, blk_indexer[selector], axis=0,
-                                     allow_fill=False)
-            placement = l[selector] if not is_unique else None
-            new_blocks.append(make_block(new_values,
-                                         new_block_items,
+                new_block_items = new_items.take(selector.nonzero()[0])
+                new_values = com.take_nd(blk.values, blk_indexer[selector], axis=0,
+                                         allow_fill=False)
+                placement = l[selector] if not is_unique else None
+                new_blocks.append(make_block(new_values,
+                                             new_block_items,
                                          new_items,
-                                         placement=placement,
-                                         fastpath=True))
-
-        if not mask.all():
-            na_items = new_items[-mask]
-            placement = l[-mask] if not is_unique else None
-            na_block = self._make_na_block(na_items,
-                                           new_items,
-                                           placement=placement,
-                                           fill_value=fill_value)
-            new_blocks.append(na_block)
-            new_blocks = _consolidate(new_blocks, new_items)
+                                             placement=placement,
+                                             fastpath=True))
+
+            if not mask.all():
+                na_items = new_items[-mask]
+                placement = l[-mask] if not is_unique else None
+                na_block = self._make_na_block(na_items,
+                                               new_items,
+                                               placement=placement,
+                                               fill_value=fill_value)
+                new_blocks.append(na_block)
+                new_blocks = _consolidate(new_blocks, new_items)
 
         return self.__class__(new_blocks, new_axes)
 


Test patch:
diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py
--- a/pandas/tests/test_indexing.py
+++ b/pandas/tests/test_indexing.py
@@ -981,6 +981,14 @@ def test_dups_fancy_indexing(self):
         result = df.ix[['A','A','E']]
         assert_frame_equal(result, expected)
 
+        # GH 5835
+        # dups on index and missing values
+        df = DataFrame(np.random.randn(5,5),columns=['A','B','B','B','A'])
+
+        expected = pd.concat([df.ix[:,['A','B']],DataFrame(np.nan,columns=['C'],index=df.index)],axis=1)
+        result = df.ix[:,['A','B','C']]
+        assert_frame_equal(result, expected)
+
     def test_indexing_mixed_frame_bug(self):
 
         # GH3492