Repository: modin-project/modin

Issue:
loc gives incorrect values when given a Boolean indexer
<!--
General questions should be asked on the mailing list modin-dev@googlegroups.com.

Before submitting an issue, please fill out the following form.
-->

### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: OSX
- **Modin installed from (source or binary)**: source
- **Modin version**: 0.6.0.dev.0
- **Python version**: 3.6
- **Exact command to reproduce**: `df.loc[df.col1 < 5]`

<!--
You can obtain the Modin version with

python -c "import modin; print(modin.__version__)"
-->

### Describe the problem
<!-- Describe the problem clearly here. -->
`loc` does not support Boolean indexers. This was originally reported over email and reproduced by me locally.

### Source code / logs
<!-- Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached. Try to provide a reproducible test case that is the bare minimum necessary to generate the problem. -->
```python
import modin.pandas as pd
df = pd.DataFrame({"col1":[1,2,3,4,5,6], "col2":[1,2,3,4,5,6]})
df.loc[df.col1 < 5]
```


Discussion:
Hi Devin, i check and loc does not support boolean and callable, the idea is to fallback or support it? 

Thanks @ipacheco-uy, we won't fallback to support this because it would be really expensive.

I outlined a bit of what is needed in a post on the discourse: https://discuss.modin.org/t/indexing-update-rewrite/57

Indexing needs to be updated because some of the general implementation is too slow. Indexing should be fast and correct. We also have diverged codepaths for `loc` and `__getitem__`, which doesn't make a lot of sense because they do similar things. They should at least be the same in the backend.

Resolving patch:
diff --git a/modin/backends/pandas/query_compiler.py b/modin/backends/pandas/query_compiler.py
--- a/modin/backends/pandas/query_compiler.py
+++ b/modin/backends/pandas/query_compiler.py
@@ -1925,11 +1925,13 @@ def back(self, n):
     # End Head/Tail/Front/Back
 
     # __getitem__ methods
-    def getitem_column_array(self, key):
+    def getitem_column_array(self, key, numeric=False):
         """Get column data for target labels.
 
         Args:
             key: Target labels by which to retrieve data.
+            numeric: A boolean representing whether or not the key passed in represents
+                the numeric index or the named index.
 
         Returns:
             A new QueryCompiler.
@@ -1941,7 +1943,10 @@ def getitem_column_array(self, key):
                 .transpose()
             )
         # Convert to list for type checking
-        numeric_indices = self.columns.get_indexer_for(key)
+        if not numeric:
+            numeric_indices = self.columns.get_indexer_for(key)
+        else:
+            numeric_indices = key
         result = self.data.mask(col_indices=numeric_indices)
         # We can't just set the columns to key here because there may be
         # multiple instances of a key.
@@ -1962,7 +1967,7 @@ def getitem_row_array(self, key):
             A new QueryCompiler.
         """
         if self._is_transposed:
-            return self.transpose().getitem_column_array(key).transpose()
+            return self.transpose().getitem_column_array(key, numeric=True).transpose()
         result = self.data.mask(row_indices=key)
         # We can't just set the index to key here because there may be multiple
         # instances of a key.
diff --git a/modin/pandas/indexing.py b/modin/pandas/indexing.py
--- a/modin/pandas/indexing.py
+++ b/modin/pandas/indexing.py
@@ -227,6 +227,19 @@ class _LocIndexer(_LocationIndexerBase):
     """A indexer for ray_df.loc[] functionality"""
 
     def __getitem__(self, key):
+        # When getting along a single axis,
+        if not isinstance(key, tuple):
+            # Try to fasttrack the code through already optimized path
+            try:
+                return self.df.__getitem__(key)
+            # This can happen if it is a list of rows
+            except KeyError:
+                pass
+        else:
+            if len(key) > self.df.ndim:
+                raise IndexingError("Too many indexers")
+            if key[0] == slice(None):
+                return self.df.__getitem__(key[1])
         row_loc, col_loc, ndim, self.row_scaler, self.col_scaler = _parse_tuple(key)
         self._handle_enlargement(row_loc, col_loc)
         row_lookup, col_lookup = self._compute_lookup(row_loc, col_loc)


Test patch: