Repository: pandas-dev/pandas

Issue:
DataFrame.loc[] loses index name
```
In [1]: from pandas import DataFrame

In [2]: x = DataFrame([[1, 1], [1, 1]])

In [3]: x.index.name = 'index_name'

In [4]: x.iloc[[0, 1]].index.name
Out[4]: 'index_name'

In [5]: x.loc[[0, 1]].index.name

In [6]: x.loc[[0, 1]].index.name is None
Out[6]: True
```



Discussion:

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -2712,14 +2712,14 @@ def _reindex_multi(self, new_index, new_columns, copy, fill_value):
     def _reindex_index(self, new_index, method, copy, level, fill_value=NA,
                        limit=None):
         new_index, indexer = self.index.reindex(new_index, method, level,
-                                                limit=limit)
+                                                limit=limit, copy_if_needed=True)
         return self._reindex_with_indexers(new_index, indexer, None, None,
                                            copy, fill_value)
 
     def _reindex_columns(self, new_columns, copy, level, fill_value=NA,
                          limit=None):
         new_columns, indexer = self.columns.reindex(new_columns, level=level,
-                                                    limit=limit)
+                                                    limit=limit, copy_if_needed=True)
         return self._reindex_with_indexers(None, None, new_columns, indexer,
                                            copy, fill_value)
 
diff --git a/pandas/core/index.py b/pandas/core/index.py
--- a/pandas/core/index.py
+++ b/pandas/core/index.py
@@ -920,7 +920,7 @@ def _get_method(self, method):
         }
         return aliases.get(method, method)
 
-    def reindex(self, target, method=None, level=None, limit=None):
+    def reindex(self, target, method=None, level=None, limit=None, copy_if_needed=False):
         """
         For Index, simply returns the new index and the results of
         get_indexer. Provided here to enable an interface that is amenable for
@@ -939,6 +939,12 @@ def reindex(self, target, method=None, level=None, limit=None):
         else:
             if self.equals(target):
                 indexer = None
+
+                # to avoid aliasing an existing index
+                if copy_if_needed and target.name != self.name and self.name is not None:
+                    if target.name is None:
+                        target = self.copy()
+
             else:
                 if self.is_unique:
                     indexer = self.get_indexer(target, method=method,
@@ -2196,7 +2202,7 @@ def get_indexer(self, target, method=None, limit=None):
 
         return com._ensure_platform_int(indexer)
 
-    def reindex(self, target, method=None, level=None, limit=None):
+    def reindex(self, target, method=None, level=None, limit=None, copy_if_needed=False):
         """
         Performs any necessary conversion on the input index and calls
         get_indexer. This method is here so MultiIndex and an Index of
diff --git a/pandas/core/internals.py b/pandas/core/internals.py
--- a/pandas/core/internals.py
+++ b/pandas/core/internals.py
@@ -1948,7 +1948,7 @@ def reindex_axis(self, new_axis, method=None, axis=0, copy=True):
                                      'axis == 0')
             return self.reindex_items(new_axis)
 
-        new_axis, indexer = cur_axis.reindex(new_axis, method)
+        new_axis, indexer = cur_axis.reindex(new_axis, method, copy_if_needed=True)
         return self.reindex_indexer(new_axis, indexer, axis=axis)
 
     def reindex_indexer(self, new_axis, indexer, axis=1, fill_value=np.nan):
@@ -2014,7 +2014,7 @@ def reindex_items(self, new_items, copy=True, fill_value=np.nan):
             return data.reindex_items(new_items)
 
         # TODO: this part could be faster (!)
-        new_items, indexer = self.items.reindex(new_items)
+        new_items, indexer = self.items.reindex(new_items, copy_if_needed=True)
         new_axes = [new_items] + self.axes[1:]
 
         # could have so me pathological (MultiIndex) issues here


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
@@ -7207,6 +7207,7 @@ def test_reindex_name_remains(self):
         s = Series(random.rand(10))
         df = DataFrame(s, index=np.arange(len(s)))
         i = Series(np.arange(10), name='iname')
+
         df = df.reindex(i)
         self.assert_(df.index.name == 'iname')
 
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
@@ -1024,6 +1024,19 @@ def test_non_unique_loc(self):
         expected = DataFrame({'A' : [2,4,5], 'B' : [4,6,7]}, index = [1,1,2])
         assert_frame_equal(result,expected)
 
+    def test_loc_name(self):
+        # GH 3880
+        df = DataFrame([[1, 1], [1, 1]])
+        df.index.name = 'index_name'
+        result = df.iloc[[0, 1]].index.name
+        self.assert_(result == 'index_name')
+
+        result = df.ix[[0, 1]].index.name
+        self.assert_(result == 'index_name')
+
+        result = df.loc[[0, 1]].index.name
+        self.assert_(result == 'index_name')
+
 if __name__ == '__main__':
     import nose
     nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],