Repository: pandas-dev/pandas

Issue:
Inconsistent integer column indexing
When columns have an integer as their name, indexing them becomes inconsistent:

``` python
>>> import pandas as pd
>>> df = pd.DataFrame({1:[1,1],2:[2,2],'a':['a','a']})
>>> df
   1  2  a
0  1  2  a
1  1  2  a

[2 rows x 3 columns]
>>> df[1]
0    1
1    1
Name: 1, dtype: int64
>>> df[['a',1]]
   a  1
0  a  1
1  a  1

[2 rows x 2 columns]
>>> df[[1,2]]
   2  a
0  2  a
1  2  a

[2 rows x 2 columns]
```

Desired behavior would be:

``` python

>>> df[[1,2]]
   1  2
0  1  2
1  1  2

[2 rows x 2 columns]
```

This is in pandas 0.13.1



Discussion:
Actually it IS consistent with using `ix`. You are pretty much asking for troublie mixing 
positions and labels, here are some solns. Read the docs: http://pandas.pydata.org/pandas-docs/stable/indexing.html#different-choices-for-indexing-loc-iloc-and-ix

Things are laid out very explicty, and you have all of the tools to do what you want. However, pandas cannot guess at what you are after; you need to be more explicit.

```
In [5]: df.ix[:,[1,2]]
Out[5]: 
   1  2
0  1  2
1  1  2

[2 rows x 2 columns]

In [6]: df.iloc[:,[1,2]]
Out[6]: 
   2  a
0  2  a
1  2  a

[2 rows x 2 columns]

In [7]: df.loc[:,[1,2]]
Out[7]: 
   1  2
0  1  2
1  1  2

[2 rows x 2 columns]
```

Thanks for the response.

Perhaps you can comment on this behavior?

``` python
>>> df.loc[0,[1,2]]
1    1
2    2
Name: 0, dtype: object
>>> df.loc[0,[1,2]] = [3,4]
>>> df
   1  2  a
0  1  3  4
1  1  2  a

[2 rows x 3 columns]
```

Apparently loc selects a different part of the dataframe for getting than it does for setting?


Resolving patch:
diff --git a/pandas/core/index.py b/pandas/core/index.py
--- a/pandas/core/index.py
+++ b/pandas/core/index.py
@@ -555,6 +555,29 @@ def _convert_list_indexer(self, key, typ=None):
         """ convert a list indexer. these should be locations """
         return key
 
+    def _convert_list_indexer_for_mixed(self, keyarr, typ=None):
+        """ passed a key that is tuplesafe that is integer based
+            and we have a mixed index (e.g. number/labels). figure out
+            the indexer. return None if we can't help
+        """
+        if com.is_integer_dtype(keyarr) and not self.is_floating():
+            if self.inferred_type != 'integer':
+                keyarr = np.where(keyarr < 0,
+                                  len(self) + keyarr, keyarr)
+
+            if self.inferred_type == 'mixed-integer':
+                indexer = self.get_indexer(keyarr)
+                if (indexer >= 0).all():
+                    return indexer
+
+                from pandas.core.indexing import _maybe_convert_indices
+                return _maybe_convert_indices(indexer, len(self))
+
+            elif not self.inferred_type == 'integer':
+                return keyarr
+
+        return None
+
     def _convert_indexer_error(self, key, msg=None):
         if msg is None:
             msg = 'label'
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -911,20 +911,10 @@ def _reindex(keys, level=None):
                 # asarray can be unsafe, NumPy strings are weird
                 keyarr = _asarray_tuplesafe(key)
 
-            if is_integer_dtype(keyarr) and not labels.is_floating():
-                if labels.inferred_type != 'integer':
-                    keyarr = np.where(keyarr < 0,
-                                      len(labels) + keyarr, keyarr)
-
-                if labels.inferred_type == 'mixed-integer':
-                    indexer = labels.get_indexer(keyarr)
-                    if (indexer >= 0).all():
-                        self.obj.take(indexer, axis=axis, convert=True)
-                    else:
-                        return self.obj.take(keyarr, axis=axis)
-                elif not labels.inferred_type == 'integer':
-
-                    return self.obj.take(keyarr, axis=axis)
+            # handle a mixed integer scenario
+            indexer = labels._convert_list_indexer_for_mixed(keyarr, typ=self.name)
+            if indexer is not None:
+                return self.obj.take(indexer, axis=axis)
 
             # this is not the most robust, but...
             if (isinstance(labels, MultiIndex) and
@@ -1064,11 +1054,9 @@ def _convert_to_indexer(self, obj, axis=0, is_setter=False):
                     objarr = _asarray_tuplesafe(obj)
 
                 # If have integer labels, defer to label-based indexing
-                if is_integer_dtype(objarr) and not is_int_index:
-                    if labels.inferred_type != 'integer':
-                        objarr = np.where(objarr < 0,
-                                          len(labels) + objarr, objarr)
-                    return objarr
+                indexer = labels._convert_list_indexer_for_mixed(objarr, typ=self.name)
+                if indexer is not None:
+                    return indexer
 
                 # this is not the most robust, but...
                 if (isinstance(labels, MultiIndex) and


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
@@ -835,6 +835,19 @@ def test_loc_setitem_frame(self):
         expected = DataFrame(dict(A = Series(val1,index=keys1), B = Series(val2,index=keys2))).reindex(index=index)
         assert_frame_equal(df, expected)
 
+        # GH 6546
+        # setting with mixed labels
+        df = DataFrame({1:[1,2],2:[3,4],'a':['a','b']})
+
+        result = df.loc[0,[1,2]]
+        expected = Series([1,3],index=[1,2],dtype=object)
+        assert_series_equal(result,expected)
+
+        expected = DataFrame({1:[5,2],2:[6,4],'a':['a','b']})
+        df.loc[0,[1,2]] = [5,6]
+        assert_frame_equal(df, expected)
+
+
     def test_loc_setitem_frame_multiples(self):
 
         # multiple setting