Repository: pandas-dev/pandas

Issue:
Why is DataFrame.loc[[1]] 1,800x slower than df.ix [[1]] and 3,500x than df.loc[1]?
import pandas as pd
s=pd.Series(xrange(5000000))
%timeit s.loc[[0]] # You need pandas 0.15.1 or newer for it to be that slow
1 loops, best of 3: 445 ms per loop

Also see the question and the answer here: http://stackoverflow.com/questions/27596832/why-is-dataframe-loc1-1-800x-slower-than-df-ix-1-and-3-500x-than-df-loc

Since .loc[] started to raise KeyError in pandas 0.15.1, the calls via `.loc[ [1] ]` (when passed a list) have slowed down enormously, because, I think, an exhaustive search is done to determine if a KeyError has to be raised or not, even if the list has only one element that can be easily located. 

Profiling:
    File: .../anaconda/lib/python2.7/site-packages/pandas/core/indexing.py,

```
1278                                                       # require at least 1 element in the index
1279         1          241    241.0      0.1              idx = _ensure_index(key)
1280         1       391040 391040.0     99.9              if len(idx) and not idx.isin(ax).any():
1281                                           
1282                                                           raise KeyError("None of [%s] are in the [%s]" %
```



Discussion:
Thanks for the report!

There were no performance tests for `.loc` previously, so this snuck through (in #8003).

#9127 includes a fix.


Resolving patch:
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -1275,9 +1275,8 @@ def _has_valid_type(self, key, axis):
             if isinstance(key, tuple) and isinstance(ax, MultiIndex):
                 return True
 
-            # require at least 1 element in the index
-            idx = _ensure_index(key)
-            if len(idx) and not idx.isin(ax).any():
+            # TODO: don't check the entire key unless necessary
+            if len(key) and np.all(ax.get_indexer_for(key) < 0):
 
                 raise KeyError("None of [%s] are in the [%s]" %
                                (key, self.obj._get_axis_name(axis)))
diff --git a/vb_suite/indexing.py b/vb_suite/indexing.py
--- a/vb_suite/indexing.py
+++ b/vb_suite/indexing.py
@@ -209,3 +209,30 @@
 
 frame_iloc_big = Benchmark('df.iloc[:100,0]', setup,
                             start_date=datetime(2013, 1, 1))
+
+#----------------------------------------------------------------------
+# basic tests for [], .loc[], .iloc[] and .ix[]
+
+setup = common_setup + """
+s = Series(np.random.rand(1000000))
+"""
+
+series_getitem_scalar = Benchmark("s[800000]", setup)
+series_getitem_slice = Benchmark("s[:800000]", setup)
+series_getitem_list_like = Benchmark("s[[800000]]", setup)
+series_getitem_array = Benchmark("s[np.arange(10000)]", setup)
+
+series_loc_scalar = Benchmark("s.loc[800000]", setup)
+series_loc_slice = Benchmark("s.loc[:800000]", setup)
+series_loc_list_like = Benchmark("s.loc[[800000]]", setup)
+series_loc_array = Benchmark("s.loc[np.arange(10000)]", setup)
+
+series_iloc_scalar = Benchmark("s.loc[800000]", setup)
+series_iloc_slice = Benchmark("s.loc[:800000]", setup)
+series_iloc_list_like = Benchmark("s.loc[[800000]]", setup)
+series_iloc_array = Benchmark("s.loc[np.arange(10000)]", setup)
+
+series_ix_scalar = Benchmark("s.ix[800000]", setup)
+series_ix_slice = Benchmark("s.ix[:800000]", setup)
+series_ix_list_like = Benchmark("s.ix[[800000]]", setup)
+series_ix_array = Benchmark("s.ix[np.arange(10000)]", setup)


Test patch: