Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOC: Add examples for MultiIndex.get_locs + cleanups #17675

Merged
merged 3 commits into from
Sep 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pandas/core/categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class Categorical(PandasObject):

See also
--------
pandas.api.types.CategoricalDtype
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this property xref here? (CategoricalDtype is NOT in the main namespace)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've changed it to api.types.CategoricalDtype. I had misunderstood the location.

Copy link
Contributor Author

@topper-123 topper-123 Sep 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking more into it, I actually think CategoricalDtype isn't shown at all in the generated API docs, so the reference will be not work in any case. Is this correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the problem is not that 'pandas' is there (that is perfectly OK, and in this case I even prefer to show the full path for clarity, as api is not a commonly used submodule of pandas), the issue is that this page does not exist, so it cannot link to it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll put pandas. back in then.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. You can also add it to the api.rst pages so the link will work

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change uploaded.

There seems to be something in the API.rst (line 649), but it mustn't work. @TomAugspurger has started looking into it, I'll wait till he figures it out.

If I get to know what I should add to API.rst, I can add it to this PR.

Copy link
Contributor

@TomAugspurger TomAugspurger Sep 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In api.rst it should be pandas.api.type.CategoricalDtype (missing the pandas).

But the autoclass fit the best with the rest of the autosummary's, so I may change it. For now, I'd just leave your reference as pandas.api.type.CategoricalDtype, and I'll make sure they're valid before the release.

pandas.api.types.CategoricalDtype : Type for categorical data
CategoricalIndex : An Index with an underlying ``Categorical``
"""

Expand Down
65 changes: 46 additions & 19 deletions pandas/core/indexes/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ class MultiIndex(Index):
Examples
---------
A new ``MultiIndex`` is typically constructed using one of the helper
methods :meth:`MultiIndex.from_arrays``, :meth:`MultiIndex.from_product``
and :meth:`MultiIndex.from_tuples``. For example (using ``.from_arrays``):
methods :meth:`MultiIndex.from_arrays`, :meth:`MultiIndex.from_product`
and :meth:`MultiIndex.from_tuples`. For example (using ``.from_arrays``):

>>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
>>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
Expand Down Expand Up @@ -1982,33 +1982,41 @@ def _partial_tup_index(self, tup, side='left'):

def get_loc(self, key, method=None):
"""
Get integer location, slice or boolean mask for requested label or
tuple. If the key is past the lexsort depth, the return may be a
boolean mask array, otherwise it is always a slice or int.
Get location for a label or a tuple of labels as an integer, slice or
boolean mask.

Parameters
----------
key : label or tuple
key : label or tuple of labels (one for each level)
method : None

Returns
-------
loc : int, slice object or boolean mask
If the key is past the lexsort depth, the return may be a
boolean mask array, otherwise it is always a slice or int.

Examples
---------
>>> mi = pd.MultiIndex.from_arrays([list('abb'), list('def')])

>>> mi.get_loc('b')
slice(1, 3, None)

>>> mi.get_loc(('b', 'e'))
1

Notes
------
The key cannot be a slice, list of same-level labels, a boolean mask,
or a sequence of such. If you want to use those, use
:meth:`MultiIndex.get_locs` instead.

See also
--------
Index.get_loc : get_loc method for (single-level) index.
get_locs : Given a tuple of slices/lists/labels/boolean indexer to a
level-wise spec, produce an indexer to extract those
locations.
MultiIndex.get_locs : Get location for a label/slice/list/mask or a
sequence of such.
"""
if method is not None:
raise NotImplementedError('only the default get_loc method is '
Expand Down Expand Up @@ -2117,8 +2125,9 @@ def get_loc_level(self, key, level=0, drop_level=True):

See Also
---------
MultiIndex.get_loc : Get integer location, slice or boolean mask for
requested label or tuple.
MultiIndex.get_loc : Get location for a label or a tuple of labels.
MultiIndex.get_locs : Get location for a label/slice/list/mask or a
sequence of such
"""

def maybe_droplevels(indexer, levels, drop_level):
Expand Down Expand Up @@ -2328,23 +2337,41 @@ def convert_indexer(start, stop, step, indexer=indexer, labels=labels):
j = labels.searchsorted(loc, side='right')
return slice(i, j)

def get_locs(self, tup):
def get_locs(self, seq):
"""
Given a tuple of slices/lists/labels/boolean indexer to a level-wise
spec produce an indexer to extract those locations
Get location for a given label/slice/list/mask or a sequence of such as
an array of integers.

Parameters
----------
key : tuple of (slices/list/labels)
seq : label/slice/list/mask or a sequence of such
You should use one of the above for each level.
If a level should not be used, set it to ``slice(None)``.

Returns
-------
locs : integer list of locations or boolean indexer suitable
for passing to iloc
locs : array of integers suitable for passing to iloc

Examples
---------
>>> mi = pd.MultiIndex.from_arrays([list('abb'), list('def')])

>>> mi.get_locs('b')
array([1, 2], dtype=int64)

>>> mi.get_locs([slice(None), ['e', 'f']])
array([1, 2], dtype=int64)

>>> mi.get_locs([[True, False, True], slice('e', 'f')])
array([2], dtype=int64)

See also
--------
MultiIndex.get_loc : Get location for a label or a tuple of labels.
"""

# must be lexsorted to at least as many levels
true_slices = [i for (i, s) in enumerate(is_true_slices(tup)) if s]
true_slices = [i for (i, s) in enumerate(is_true_slices(seq)) if s]
if true_slices and true_slices[-1] >= self.lexsort_depth:
raise UnsortedIndexError('MultiIndex slicing requires the index '
'to be lexsorted: slicing on levels {0}, '
Expand Down Expand Up @@ -2377,7 +2404,7 @@ def _update_indexer(idxr, indexer=indexer):
return indexer
return indexer & idxr

for i, k in enumerate(tup):
for i, k in enumerate(seq):

if is_bool_indexer(k):
# a boolean indexer, must be the same length!
Expand Down