Repository: pandas-dev/pandas

Issue:
Bug in set_labels of MultiIndex
```python
import pandas as pd
                                 
idx = pd.MultiIndex.from_tuples([(0, i) for i in range(130)])
print idx.labels[1].dtype  
# --> int16
idx.set_labels(labels=idx.labels[1], level=1, inplace=True) 
print idx.labels[1].dtype  
# --> int8
```

Imho this is caused by the following line, because the erratic assumption that the indices of `labels` and `self.levels` would be index-aligned.
https://github.com/pandas-dev/pandas/blame/master/pandas/core/indexes/multi.py#L331
Hence the call to `coerce_indexer_dtype` casts the given `labels` to int8. This is because its l'ooking at the number of categories in level 0.

I would suggest to replace 
```python
            for l, lev, lab in zip(level, self.levels, labels):
                new_labels[l] = _ensure_frozen(
                    lab, lev, copy=copy)._shallow_copy()
```
with
```python
            for l, lab in zip(level, labels):
                lev = self.levels[l]
                new_labels[l] = _ensure_frozen(
                    lab, lev, copy=copy)._shallow_copy()
```

Bug in set_labels of MultiIndex
```python
import pandas as pd
                                 
idx = pd.MultiIndex.from_tuples([(0, i) for i in range(130)])
print idx.labels[1].dtype  
# --> int16
idx.set_labels(labels=idx.labels[1], level=1, inplace=True) 
print idx.labels[1].dtype  
# --> int8
```

Imho this is caused by the following line, because the erratic assumption that the indices of `labels` and `self.levels` would be index-aligned.
https://github.com/pandas-dev/pandas/blame/master/pandas/core/indexes/multi.py#L331
Hence the call to `coerce_indexer_dtype` casts the given `labels` to int8. This is because its l'ooking at the number of categories in level 0.

I would suggest to replace 
```python
            for l, lev, lab in zip(level, self.levels, labels):
                new_labels[l] = _ensure_frozen(
                    lab, lev, copy=copy)._shallow_copy()
```
with
```python
            for l, lab in zip(level, labels):
                lev = self.levels[l]
                new_labels[l] = _ensure_frozen(
                    lab, lev, copy=copy)._shallow_copy()
```



Discussion:

Resolving patch:
diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py
--- a/pandas/core/indexes/multi.py
+++ b/pandas/core/indexes/multi.py
@@ -328,8 +328,9 @@ def _set_labels(self, labels, level=None, copy=False, validate=True,
         else:
             level = [self._get_level_number(l) for l in level]
             new_labels = list(self._labels)
-            for l, lev, lab in zip(level, self.levels, labels):
-                new_labels[l] = _ensure_frozen(
+            for lev_idx, lab in zip(level, labels):
+                lev = self.levels[lev_idx]
+                new_labels[lev_idx] = _ensure_frozen(
                     lab, lev, copy=copy)._shallow_copy()
             new_labels = FrozenList(new_labels)
 


Test patch:
diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py
--- a/pandas/tests/indexes/test_multi.py
+++ b/pandas/tests/indexes/test_multi.py
@@ -327,6 +327,21 @@ def assert_matching(actual, expected):
         assert_matching(ind2.labels, new_labels)
         assert_matching(self.index.labels, labels)
 
+        # label changing for levels of different magnitude of categories
+        ind = pd.MultiIndex.from_tuples([(0, i) for i in range(130)])
+        new_labels = range(129, -1, -1)
+        expected = pd.MultiIndex.from_tuples(
+            [(0, i) for i in new_labels])
+
+        # [w/o mutation]
+        result = ind.set_labels(labels=new_labels, level=1)
+        assert result.equals(expected)
+
+        # [w/ mutation]
+        result = ind.copy()
+        result.set_labels(labels=new_labels, level=1, inplace=True)
+        assert result.equals(expected)
+
     def test_set_levels_labels_names_bad_input(self):
         levels, labels = self.index.levels, self.index.labels
         names = self.index.names