Skip to content

Commit e01b88b

Browse files
committed
API: add droplevel() to flat indexes, for compatibility with MultiIndex
closes pandas-dev#21115
1 parent e033c06 commit e01b88b

File tree

3 files changed

+55
-46
lines changed

3 files changed

+55
-46
lines changed

doc/source/whatsnew/v0.23.1.txt

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Indexing
6565
^^^^^^^^
6666

6767
- Bug in :meth:`Series.reset_index` where appropriate error was not raised with an invalid level name (:issue:`20925`)
68+
- :meth:`Index.droplevel` is now implemented also for flat indexes, for compatibility with MultiIndex (:issue:`21115`)
6869
-
6970

7071
I/O

pandas/core/indexes/base.py

+54
Original file line numberDiff line numberDiff line change
@@ -3158,6 +3158,60 @@ def _get_level_values(self, level):
31583158

31593159
get_level_values = _get_level_values
31603160

3161+
def droplevel(self, level=0):
3162+
"""
3163+
Return index with requested level(s) removed. If resulting index has
3164+
only 1 level left, the result will be of Index type, not MultiIndex.
3165+
3166+
.. versionadded:: 0.23.1 (support for non-MultiIndex)
3167+
3168+
Parameters
3169+
----------
3170+
level : int, str, or list-like, default 0
3171+
If a string is given, must be the name of a level
3172+
If list-like, elements must be names or indexes of levels.
3173+
3174+
Returns
3175+
-------
3176+
index : Index or MultiIndex
3177+
"""
3178+
if not isinstance(level, (tuple, list)):
3179+
level = [level]
3180+
3181+
levnums = sorted(self._get_level_number(lev) for lev in level)[::-1]
3182+
3183+
if len(level) == 0:
3184+
return self
3185+
if len(level) >= self.nlevels:
3186+
raise ValueError("Cannot remove {} levels from an index with {} "
3187+
"levels: at least one level must be "
3188+
"left.".format(len(level), self.nlevels))
3189+
# The two checks above guarantee that here self is a MultiIndex
3190+
3191+
new_levels = list(self.levels)
3192+
new_labels = list(self.labels)
3193+
new_names = list(self.names)
3194+
3195+
for i in levnums:
3196+
new_levels.pop(i)
3197+
new_labels.pop(i)
3198+
new_names.pop(i)
3199+
3200+
if len(new_levels) == 1:
3201+
3202+
# set nan if needed
3203+
mask = new_labels[0] == -1
3204+
result = new_levels[0].take(new_labels[0])
3205+
if mask.any():
3206+
result = result.putmask(mask, np.nan)
3207+
3208+
result.name = new_names[0]
3209+
return result
3210+
else:
3211+
from .multi import MultiIndex
3212+
return MultiIndex(levels=new_levels, labels=new_labels,
3213+
names=new_names, verify_integrity=False)
3214+
31613215
_index_shared_docs['get_indexer'] = """
31623216
Compute indexer and mask for new index given the current index. The
31633217
indexer should be then used as an input to ndarray.take to align the

pandas/core/indexes/multi.py

-46
Original file line numberDiff line numberDiff line change
@@ -1761,52 +1761,6 @@ def _drop_from_level(self, labels, level):
17611761

17621762
return self[mask]
17631763

1764-
def droplevel(self, level=0):
1765-
"""
1766-
Return Index with requested level removed. If MultiIndex has only 2
1767-
levels, the result will be of Index type not MultiIndex.
1768-
1769-
Parameters
1770-
----------
1771-
level : int/level name or list thereof
1772-
1773-
Notes
1774-
-----
1775-
Does not check if result index is unique or not
1776-
1777-
Returns
1778-
-------
1779-
index : Index or MultiIndex
1780-
"""
1781-
levels = level
1782-
if not isinstance(levels, (tuple, list)):
1783-
levels = [level]
1784-
1785-
new_levels = list(self.levels)
1786-
new_labels = list(self.labels)
1787-
new_names = list(self.names)
1788-
1789-
levnums = sorted(self._get_level_number(lev) for lev in levels)[::-1]
1790-
1791-
for i in levnums:
1792-
new_levels.pop(i)
1793-
new_labels.pop(i)
1794-
new_names.pop(i)
1795-
1796-
if len(new_levels) == 1:
1797-
1798-
# set nan if needed
1799-
mask = new_labels[0] == -1
1800-
result = new_levels[0].take(new_labels[0])
1801-
if mask.any():
1802-
result = result.putmask(mask, np.nan)
1803-
1804-
result.name = new_names[0]
1805-
return result
1806-
else:
1807-
return MultiIndex(levels=new_levels, labels=new_labels,
1808-
names=new_names, verify_integrity=False)
1809-
18101764
def swaplevel(self, i=-2, j=-1):
18111765
"""
18121766
Swap level i with level j.

0 commit comments

Comments
 (0)