Skip to content

Add defaults to swaplevel() parameters i and j #12943

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

Closed
wants to merge 1 commit into from
Closed
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
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
7 changes: 6 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
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's worth noting in the doc strings (of alll of these) that the defaults were added in 0.18.1

you can use a versionadded directive


Expand All @@ -3396,6 +3396,11 @@ 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
7 changes: 6 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,11 @@ 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
7 changes: 6 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,11 @@ 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
7 changes: 6 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,11 @@ 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