Repository: pandas-dev/pandas

Issue:
ENH: set_index drops index name
Index

```
df = pd.util.testing.makeDataFrame()
df.index.name = 'name'
df.set_index(df.index)
df.set_index(df.index).index.names
```

MultiIndex

```
from statsmodels.datasets import grunfeld
data = sm.datasets.grunfeld.load_pandas().data
data = data.set_index(['firm', 'year'])
data.set_index(data.index).index.names
```

Version

```
[~/]
[33]: pd.version.version
[33]: '0.13.1-254-g150f323'
```



Discussion:
I guess I shouldn't be using set_index to do this. Use reindex. Might want to either raise an error or pass along to reindex under the hood?

This is technically not valid according to the doc-string, as it accepts `arrays` which is sufficiently ambiguous, but 'works' with Series/ndarray (and index happens to be a ndarray subclass currently). So I think this could easily work; marking as an enhancement.


Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -2240,7 +2240,15 @@ def set_index(self, keys, drop=True, append=False, inplace=False,
 
         to_remove = []
         for col in keys:
-            if isinstance(col, Series):
+            if isinstance(col, MultiIndex):
+                # append all but the last column so we don't have to modify
+                # the end of this loop
+                for n in range(col.nlevels - 1):
+                    arrays.append(col.get_level_values(n))
+
+                level = col.get_level_values(col.nlevels - 1)
+                names.extend(col.names)
+            elif isinstance(col, (Series, Index)):
                 level = col.values
                 names.append(col.name)
             elif isinstance(col, (list, np.ndarray)):


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -12280,6 +12280,33 @@ def test_dtypes_are_correct_after_column_slice(self):
                             pd.Series(odict([('a', np.float_), ('b', np.float_),
                                              ('c', np.float_),])))
 
+    def test_set_index_names(self):
+        df = pd.util.testing.makeDataFrame()
+        df.index.name = 'name'
+
+        self.assertEquals(df.set_index(df.index).index.names, ['name'])
+
+        mi = MultiIndex.from_arrays(df[['A', 'B']].T.values, names=['A', 'B'])
+        mi2 = MultiIndex.from_arrays(df[['A', 'B', 'A', 'B']].T.values,
+                                     names=['A', 'B', 'A', 'B'])
+
+        df = df.set_index(['A', 'B'])
+
+        self.assertEquals(df.set_index(df.index).index.names, ['A', 'B'])
+
+        # Check that set_index isn't converting a MultiIndex into an Index
+        self.assertTrue(isinstance(df.set_index(df.index).index, MultiIndex))
+
+        # Check actual equality
+        tm.assert_index_equal(df.set_index(df.index).index, mi)
+
+        # Check that [MultiIndex, MultiIndex] yields a MultiIndex rather
+        # than a pair of tuples
+        self.assertTrue(isinstance(df.set_index([df.index, df.index]).index, MultiIndex))
+
+        # Check equality
+        tm.assert_index_equal(df.set_index([df.index, df.index]).index, mi2)
+
 
 def skip_if_no_ne(engine='numexpr'):
     if engine == 'numexpr':