Skip to content

Commit

Permalink
Add defaults to swaplevel() parameters i and j
Browse files Browse the repository at this point in the history
Closes #12934 feature request.

Author: Brandon Rhodes <brandon@rhodesmill.org>

Closes #12943 from brandon-rhodes/master and squashes the following commits:

c6fbb3e [Brandon Rhodes] Add default values to swaplevel() i, j parameters
  • Loading branch information
brandon-rhodes authored and jreback committed Apr 22, 2016
1 parent 5688d27 commit ed324e8
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 18 deletions.
4 changes: 3 additions & 1 deletion doc/source/whatsnew/v0.18.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ v0.18.1 (April ??, 2016)
------------------------

This is a minor bug-fix release from 0.18.0 and includes a large number of
bug fixes along several new features, enhancements, and performance improvements.
bug fixes along with several new features, enhancements, and performance improvements.
We recommend that all users upgrade to this version.

Highlights include:
Expand Down Expand Up @@ -131,6 +131,8 @@ These changes conform sparse handling to return the correct types and work to ma

API changes
~~~~~~~~~~~
- ``.swaplevel()`` for ``Series``, ``DataFrame``, ``Panel``, and ``MultiIndex`` now features defaults for its first two parameters ``i`` and ``j`` that swap the two innermost levels of the index. (:issue:`12934`)

- ``.searchsorted()`` for ``Index`` and ``TimedeltaIndex`` now accept a ``sorter`` argument to maintain compatibility with numpy's ``searchsorted`` function (:issue:`12238`)

- ``Period`` and ``PeriodIndex`` now raises ``IncompatibleFrequency`` error which inherits ``ValueError`` rather than raw ``ValueError`` (:issue:`12615`)
Expand Down
8 changes: 7 additions & 1 deletion pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -3384,7 +3384,7 @@ def nsmallest(self, n, columns, keep='first'):
"""
return self._nsorted(columns, n, 'nsmallest', keep)

def swaplevel(self, i, j, axis=0):
def swaplevel(self, i=-2, j=-1, axis=0):
"""
Swap levels i and j in a MultiIndex on a particular axis
Expand All @@ -3396,6 +3396,12 @@ def swaplevel(self, i, j, axis=0):
Returns
-------
swapped : type of caller (new object)
.. versionchanged:: 0.18.1
The indexes ``i`` and ``j`` are now optional, and default to
the two innermost levels of the index.
"""
result = self.copy()

Expand Down
8 changes: 7 additions & 1 deletion pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ def squeeze(self):
except:
return self

def swaplevel(self, i, j, axis=0):
def swaplevel(self, i=-2, j=-1, axis=0):
"""
Swap levels i and j in a MultiIndex on a particular axis
Expand All @@ -534,6 +534,12 @@ def swaplevel(self, i, j, axis=0):
Returns
-------
swapped : type of caller (new object)
.. versionchanged:: 0.18.1
The indexes ``i`` and ``j`` are now optional, and default to
the two innermost levels of the index.
"""
axis = self._get_axis_number(axis)
result = self.copy()
Expand Down
8 changes: 7 additions & 1 deletion pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -1949,7 +1949,7 @@ def sortlevel(self, level=0, ascending=True, sort_remaining=True):
return self.sort_index(level=level, ascending=ascending,
sort_remaining=sort_remaining)

def swaplevel(self, i, j, copy=True):
def swaplevel(self, i=-2, j=-1, copy=True):
"""
Swap levels i and j in a MultiIndex
Expand All @@ -1961,6 +1961,12 @@ def swaplevel(self, i, j, copy=True):
Returns
-------
swapped : Series
.. versionchanged:: 0.18.1
The indexes ``i`` and ``j`` are now optional, and default to
the two innermost levels of the index.
"""
new_index = self.index.swaplevel(i, j)
return self._constructor(self._values, index=new_index,
Expand Down
8 changes: 7 additions & 1 deletion pandas/indexes/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,7 @@ def droplevel(self, level=0):
return MultiIndex(levels=new_levels, labels=new_labels,
names=new_names, verify_integrity=False)

def swaplevel(self, i, j):
def swaplevel(self, i=-2, j=-1):
"""
Swap level i with level j. Do not change the ordering of anything
Expand All @@ -1206,6 +1206,12 @@ def swaplevel(self, i, j):
Returns
-------
swapped : MultiIndex
.. versionchanged:: 0.18.1
The indexes ``i`` and ``j`` are now optional, and default to
the two innermost levels of the index.
"""
new_levels = list(self.levels)
new_labels = list(self.labels)
Expand Down
15 changes: 9 additions & 6 deletions pandas/tests/indexes/test_multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2095,12 +2095,15 @@ def test_partial_string_timestamp_multiindex(self):
# c 14

# partial string matching on a single index
df_swap = df.swaplevel(0, 1).sort_index()
just_a = df_swap.loc['a']
result = just_a.loc['2016-01-01']
expected = df.loc[idx[:, 'a'], :].iloc[0:2]
expected.index = expected.index.droplevel(1)
tm.assert_frame_equal(result, expected)
for df_swap in (df.swaplevel(),
df.swaplevel(0),
df.swaplevel(0, 1)):
df_swap = df_swap.sort_index()
just_a = df_swap.loc['a']
result = just_a.loc['2016-01-01']
expected = df.loc[idx[:, 'a'], :].iloc[0:2]
expected.index = expected.index.droplevel(1)
tm.assert_frame_equal(result, expected)

# indexing with IndexSlice
result = df.loc[idx['2016-01-01':'2016-02-01', :], :]
Expand Down
24 changes: 17 additions & 7 deletions pandas/tests/test_multilevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1320,15 +1320,23 @@ def test_join(self):
) # TODO what should join do with names ?

def test_swaplevel(self):
swapped = self.frame['A'].swaplevel(0, 1)
swapped2 = self.frame['A'].swaplevel('first', 'second')
swapped = self.frame['A'].swaplevel()
swapped2 = self.frame['A'].swaplevel(0)
swapped3 = self.frame['A'].swaplevel(0, 1)
swapped4 = self.frame['A'].swaplevel('first', 'second')
self.assertFalse(swapped.index.equals(self.frame.index))
assert_series_equal(swapped, swapped2)
assert_series_equal(swapped, swapped3)
assert_series_equal(swapped, swapped4)

back = swapped.swaplevel(0, 1)
back2 = swapped.swaplevel('second', 'first')
back = swapped.swaplevel()
back2 = swapped.swaplevel(0)
back3 = swapped.swaplevel(0, 1)
back4 = swapped.swaplevel('second', 'first')
self.assertTrue(back.index.equals(self.frame.index))
assert_series_equal(back, back2)
assert_series_equal(back, back3)
assert_series_equal(back, back4)

ft = self.frame.T
swapped = ft.swaplevel('first', 'second', axis=1)
Expand All @@ -1337,11 +1345,13 @@ def test_swaplevel(self):

def test_swaplevel_panel(self):
panel = Panel({'ItemA': self.frame, 'ItemB': self.frame * 2})

result = panel.swaplevel(0, 1, axis='major')
expected = panel.copy()
expected.major_axis = expected.major_axis.swaplevel(0, 1)
tm.assert_panel_equal(result, expected)

for result in (panel.swaplevel(axis='major'),
panel.swaplevel(0, axis='major'),
panel.swaplevel(0, 1, axis='major')):
tm.assert_panel_equal(result, expected)

def test_reorder_levels(self):
result = self.ymd.reorder_levels(['month', 'day', 'year'])
Expand Down

0 comments on commit ed324e8

Please sign in to comment.