Repository: pandas-dev/pandas

Issue:
BUG: ValueError when indexing using range only when length >= 1,000,000
From SO (http://stackoverflow.com/questions/33814223/strange-error-in-pandas-indexing-with-range-when-length-1-000-000)

Pandas raises a ValueError when assigning multiple values to a Series (or DataFrame) using range(x) where x > 1. This error is raised only when its length is one million or larger.

``` python
import pandas as pd

for x in [5, 999999, 1000000]:
    s = pd.Series(index=range(x))
    print('series length =', len(s))
    # assigning value with range(1), always works
    s.loc[range(1)] = 42 
    # reading values with range(x>1), always works
    _ = s.loc[range(2)] 
    # assigning values with range(x>1), fails only when len >= 1 million
    s.loc[range(2)] = 42 
```

Output:

``` python
series length = 5
series length = 999999
series length = 1000000
Traceback (most recent call last):
  File "<stdin>", line 9, in <module>
  File "/home/nekobon/.env_exp/lib/python3.4/site-packages/pandas/core/indexing.py", line 114, in __setitem__
    indexer = self._get_setitem_indexer(key)
  File "/home/nekobon/.env_exp/lib/python3.4/site-packages/pandas/core/indexing.py", line 109, in _get_setitem_indexer
    return self._convert_to_indexer(key, is_setter=True)
  File "/home/nekobon/.env_exp/lib/python3.4/site-packages/pandas/core/indexing.py", line 1042, in _convert_to_indexer
    return labels.get_loc(obj)
  File "/home/nekobon/.env_exp/lib/python3.4/site-packages/pandas/core/index.py", line 1692, in get_loc
    return self._engine.get_loc(_values_from_object(key))
  File "pandas/index.pyx", line 137, in pandas.index.IndexEngine.get_loc (pandas/index.c:3979)
  File "pandas/index.pyx", line 145, in pandas.index.IndexEngine.get_loc (pandas/index.c:3680)
  File "pandas/index.pyx", line 464, in pandas.index._bin_search (pandas/index.c:9124)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
```

Tested on pandas 0.17.0 and python 3.4.



Discussion:
odd, only happens on py3.

`range(2)` is a list in py2.x.  `s.loc[list[range(2)]] = 42` works fine with py3, too. 
It seems to be failing only with `range` object.


Resolving patch:
diff --git a/pandas/core/index.py b/pandas/core/index.py
--- a/pandas/core/index.py
+++ b/pandas/core/index.py
@@ -1755,7 +1755,8 @@ def get_loc(self, key, method=None, tolerance=None):
             if tolerance is not None:
                 raise ValueError('tolerance argument only valid if using pad, '
                                  'backfill or nearest lookups')
-            return self._engine.get_loc(_values_from_object(key))
+            key = _values_from_object(key)
+            return self._engine.get_loc(key)
 
         indexer = self.get_indexer([key], method=method,
                                    tolerance=tolerance)
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -104,6 +104,8 @@ def _get_setitem_indexer(self, key):
 
         if isinstance(key, tuple) and not self.ndim < len(key):
             return self._convert_tuple(key, is_setter=True)
+        if isinstance(key, range):
+            return self._convert_range(key, is_setter=True)
 
         try:
             return self._convert_to_indexer(key, is_setter=True)
@@ -156,6 +158,10 @@ def _convert_tuple(self, key, is_setter=False):
                 keyidx.append(idx)
         return tuple(keyidx)
 
+    def _convert_range(self, key, is_setter=False):
+        """ convert a range argument """
+        return list(key)
+
     def _convert_scalar_indexer(self, key, axis):
         # if we are accessing via lowered dim, use the last dim
         ax = self.obj._get_axis(min(axis, self.ndim - 1))


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
@@ -4726,6 +4726,17 @@ def test_indexing_dtypes_on_empty(self):
         assert_series_equal(df2.loc[:,'a'], df2.iloc[:,0])
         assert_series_equal(df2.loc[:,'a'], df2.ix[:,0])
 
+    def test_range_in_series_indexing(self):
+        # range can cause an indexing error
+        # GH 11652
+        for x in [5, 999999, 1000000]:
+            s = pd.Series(index=range(x))
+            s.loc[range(1)] = 42
+            assert_series_equal(s.loc[range(1)],Series(42.0,index=[0]))
+
+            s.loc[range(2)] = 43
+            assert_series_equal(s.loc[range(2)],Series(43.0,index=[0,1]))
+
     @slow
     def test_large_dataframe_indexing(self):
         #GH10692