Skip to content

API: harmonize drop/reindex/rename args (GH12392) - drop #17644

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

Merged
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
18 changes: 18 additions & 0 deletions doc/source/whatsnew/v0.21.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ This does not raise any obvious exceptions, but also does not create a new colum

Setting a list-like data structure into a new attribute now raise a ``UserWarning`` about the potential for unexpected behavior. See :ref:`Attribute Access <indexing.attribute_access>`.

``drop`` now also accepts index/columns keywords
Copy link
Contributor

Choose a reason for hiding this comment

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

add ref here

Copy link
Member Author

@jorisvandenbossche jorisvandenbossche Sep 23, 2017

Choose a reason for hiding this comment

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

this is only needed when you actually want to explicitly link to it from somewhere else in the docs, so I personally prefer to only add it when actually needed

(bug can certainly add it for consistency)

Copy link
Contributor

Choose a reason for hiding this comment

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

no, all sub-sections should have a reference as a general rule. yes we may not always link to it, but by definition when creating a non-trivial sub-section it should have a reference

Copy link
Member Author

Choose a reason for hiding this comment

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

There is nothing "by definition" about it (I mean, sphinx does not require it). IMO it just gives more overhead by always asking contributors to do this.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The :meth:`~DataFrame.drop` method has gained ``index``/``columns`` keywords as an
alternative to specify the ``axis`` and to make it similar in usage to ``reindex``
(:issue:`12392`).

For example:

.. ipython:: python

df = pd.DataFrame(np.arange(8).reshape(2,4),
columns=['A', 'B', 'C', 'D'])
df
df.drop(['B', 'C'], axis=1)
# the following is now equivalent
df.drop(columns=['B', 'C'])

.. _whatsnew_0210.enhancements.categorical_dtype:

``CategoricalDtype`` for specifying categoricals
Expand Down
102 changes: 76 additions & 26 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2333,14 +2333,23 @@ def reindex_like(self, other, method=None, copy=True, limit=None,

return self.reindex(**d)

def drop(self, labels, axis=0, level=None, inplace=False, errors='raise'):
def drop(self, labels=None, axis=0, index=None, columns=None, level=None,
inplace=False, errors='raise'):
"""
Return new object with labels in requested axis removed.

Parameters
----------
labels : single label or list-like
Index or column labels to drop.
axis : int or axis name
Whether to drop labels from the index (0 / 'index') or
columns (1 / 'columns').
index, columns : single label or list-like
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps add a Notes section saying that specifying both labels and index or columns will raise an error.

Alternative to specifying `axis` (``labels, axis=1`` is
equivalent to ``columns=labels``).
Copy link
Contributor

Choose a reason for hiding this comment

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

add a versionadded tag


.. versionadded:: 0.21.0
level : int or level name, default None
For MultiIndex
inplace : bool, default False
Expand All @@ -2354,36 +2363,80 @@ def drop(self, labels, axis=0, level=None, inplace=False, errors='raise'):

Examples
--------
>>> df = pd.DataFrame([[1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 1, 2, 3],
... [4, 5, 6, 7]
... ],
... columns=list('ABCD'))
>>> df = pd.DataFrame(np.arange(12).reshape(3,4),
columns=['A', 'B', 'C', 'D'])
>>> df
A B C D
0 1 2 3 4
1 5 6 7 8
2 9 1 2 3
3 4 5 6 7
A B C D
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11

Drop columns

>>> df.drop(['B', 'C'], axis=1)
A D
0 0 3
1 4 7
2 8 11

>>> df.drop(columns=['B', 'C'])
A D
0 0 3
1 4 7
2 8 11

Drop a row by index

>>> df.drop([0, 1])
A B C D
2 9 1 2 3
3 4 5 6 7
A B C D
2 8 9 10 11

Drop columns
Notes
-----
Specifying both `labels` and `index` or `columns` will raise a
ValueError.

>>> df.drop(['A', 'B'], axis=1)
C D
0 3 4
1 7 8
2 2 3
3 6 7
"""
inplace = validate_bool_kwarg(inplace, 'inplace')

if labels is not None:
if index is not None or columns is not None:
raise ValueError("Cannot specify both 'labels' and "
"'index'/'columns'")
axis_name = self._get_axis_name(axis)
axes = {axis_name: labels}
elif index is not None or columns is not None:
axes, _ = self._construct_axes_from_arguments((index, columns), {})
else:
raise ValueError("Need to specify at least one of 'labels', "
"'index' or 'columns'")

obj = self

for axis, labels in axes.items():
if labels is not None:
obj = obj._drop_axis(labels, axis, level=level, errors=errors)

if inplace:
self._update_inplace(obj)
else:
return obj

def _drop_axis(self, labels, axis, level=None, errors='raise'):
"""
Drop labels from specified axis. Used in the ``drop`` method
internally.

Parameters
----------
labels : single label or list-like
axis : int or axis name
level : int or level name, default None
For MultiIndex
errors : {'ignore', 'raise'}, default 'raise'
If 'ignore', suppress error and existing labels are dropped.

"""
axis = self._get_axis_number(axis)
axis_name = self._get_axis_name(axis)
axis, axis_ = self._get_axis(axis), axis
Expand Down Expand Up @@ -2416,10 +2469,7 @@ def drop(self, labels, axis=0, level=None, inplace=False, errors='raise'):

result = self.loc[tuple(slicer)]

if inplace:
self._update_inplace(result)
else:
return result
return result

def _update_inplace(self, result, verify_is_copy=True):
"""
Expand Down
35 changes: 35 additions & 0 deletions pandas/tests/frame/test_axis_select_reindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,41 @@ def test_drop_multiindex_not_lexsorted(self):

tm.assert_frame_equal(result, expected)

def test_drop_api_equivalence(self):
# equivalence of the labels/axis and index/columns API's (GH12392)
df = DataFrame([[1, 2, 3], [3, 4, 5], [5, 6, 7]],
index=['a', 'b', 'c'],
columns=['d', 'e', 'f'])

res1 = df.drop('a')
res2 = df.drop(index='a')
tm.assert_frame_equal(res1, res2)

res1 = df.drop('d', 1)
res2 = df.drop(columns='d')
tm.assert_frame_equal(res1, res2)

res1 = df.drop(labels='e', axis=1)
res2 = df.drop(columns='e')
tm.assert_frame_equal(res1, res2)

res1 = df.drop(['a'], axis=0)
res2 = df.drop(index=['a'])
tm.assert_frame_equal(res1, res2)

res1 = df.drop(['a'], axis=0).drop(['d'], axis=1)
res2 = df.drop(index=['a'], columns=['d'])
tm.assert_frame_equal(res1, res2)

Copy link
Contributor

Choose a reason for hiding this comment

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

test with columns as well

Copy link
Member Author

Choose a reason for hiding this comment

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

Did you mean for the error test? (added one for that) Or for one of the tests above?

Copy link
Contributor

Choose a reason for hiding this comment

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

yep

with pytest.raises(ValueError):
df.drop(labels='a', index='b')

with pytest.raises(ValueError):
df.drop(labels='a', columns='b')

with pytest.raises(ValueError):
df.drop(axis=1)

def test_merge_join_different_levels(self):
# GH 9455

Expand Down