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

ENH: DataFrame.drop copy kwd #47993

Closed
wants to merge 4 commits 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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ Other enhancements
- :meth:`RangeIndex.union` now can return a :class:`RangeIndex` instead of a :class:`Int64Index` if the resulting values are equally spaced (:issue:`47557`, :issue:`43885`)
- :meth:`DataFrame.compare` now accepts an argument ``result_names`` to allow the user to specify the result's names of both left and right DataFrame which are being compared. This is by default ``'self'`` and ``'other'`` (:issue:`44354`)
- :meth:`Series.add_suffix`, :meth:`DataFrame.add_suffix`, :meth:`Series.add_prefix` and :meth:`DataFrame.add_prefix` support a ``copy`` argument. If ``False``, the underlying data is not copied in the returned object (:issue:`47934`)
- :meth:`DataFrame.drop` with ``axis=1`` can now accept ``copy=False`` to prevent a copy of the underlying data (:issue:`47993`)

.. ---------------------------------------------------------------------------
.. _whatsnew_150.notable_bug_fixes:
Expand Down
4 changes: 1 addition & 3 deletions pandas/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,7 @@ def _obj_with_exclusions(self):
if len(self.exclusions) > 0:
# equivalent to `self.obj.drop(self.exclusions, axis=1)
# but this avoids consolidating and making a copy
# TODO: following GH#45287 can we now use .drop directly without
# making a copy?
return self.obj._drop_axis(self.exclusions, axis=1, only_slice=True)
return self.obj.drop(self.exclusions, axis=1, copy=False)
else:
return self.obj

Expand Down
10 changes: 10 additions & 0 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -5096,6 +5096,7 @@ def drop(
level: Level | None = ...,
inplace: Literal[True],
errors: IgnoreRaise = ...,
copy: bool | lib.NoDefault = ...,
) -> None:
...

Expand All @@ -5110,6 +5111,7 @@ def drop(
level: Level | None = ...,
inplace: Literal[False] = ...,
errors: IgnoreRaise = ...,
copy: bool | lib.NoDefault = ...,
) -> DataFrame:
...

Expand All @@ -5124,6 +5126,7 @@ def drop(
level: Level | None = ...,
inplace: bool = ...,
errors: IgnoreRaise = ...,
copy: bool | lib.NoDefault = ...,
) -> DataFrame | None:
...

Expand All @@ -5139,6 +5142,8 @@ def drop( # type: ignore[override]
level: Level | None = None,
inplace: bool = False,
errors: IgnoreRaise = "raise",
*,
copy: bool | lib.NoDefault = lib.no_default,
) -> DataFrame | None:
"""
Drop specified labels from rows or columns.
Expand Down Expand Up @@ -5171,6 +5176,10 @@ def drop( # type: ignore[override]
errors : {'ignore', 'raise'}, default 'raise'
If 'ignore', suppress error and only existing labels are
dropped.
copy : bool, default True
If False and axis == 1, do not make a copy of the underlying data.

.. versionadded:: 1.5.0

Returns
-------
Expand Down Expand Up @@ -5285,6 +5294,7 @@ def drop( # type: ignore[override]
level=level,
inplace=inplace,
errors=errors,
copy=copy,
)

@overload
Expand Down
15 changes: 14 additions & 1 deletion pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4376,6 +4376,7 @@ def drop(
level: Level | None = ...,
inplace: Literal[True],
errors: IgnoreRaise = ...,
copy: bool_t | lib.NoDefault = ...,
) -> None:
...

Expand All @@ -4390,6 +4391,7 @@ def drop(
level: Level | None = ...,
inplace: Literal[False] = ...,
errors: IgnoreRaise = ...,
copy: bool_t | lib.NoDefault = ...,
) -> NDFrameT:
...

Expand All @@ -4404,6 +4406,7 @@ def drop(
level: Level | None = ...,
inplace: bool_t = ...,
errors: IgnoreRaise = ...,
copy: bool_t | lib.NoDefault = ...,
) -> NDFrameT | None:
...

Expand All @@ -4417,9 +4420,17 @@ def drop(
level: Level | None = None,
inplace: bool_t = False,
errors: IgnoreRaise = "raise",
*,
copy: bool_t | lib.NoDefault = lib.no_default,
) -> NDFrameT | None:

inplace = validate_bool_kwarg(inplace, "inplace")
if inplace:
if copy is not lib.no_default:
raise ValueError("Cannot pass both inplace=True and copy")
copy = True
elif copy is lib.no_default:
copy = True

if labels is not None:
if index is not None or columns is not None:
Expand All @@ -4437,7 +4448,9 @@ def drop(

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

if inplace:
self._update_inplace(obj)
Expand Down
4 changes: 3 additions & 1 deletion pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -4992,7 +4992,8 @@ def reindex(self, *args, **kwargs) -> Series:
kwargs.update({"index": index})
return super().reindex(**kwargs)

@overload
# error: Signature of "drop" incompatible with supertype "NDFrame" [override]
@overload # type: ignore[override]
def drop(
self,
labels: IndexLabel = ...,
Expand Down Expand Up @@ -5141,6 +5142,7 @@ def drop( # type: ignore[override]
level=level,
inplace=inplace,
errors=errors,
copy=lib.no_default,
)

@overload
Expand Down
19 changes: 19 additions & 0 deletions pandas/tests/frame/methods/test_drop.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ def test_drop_with_non_unique_datetime_index_and_invalid_keys():


class TestDataFrameDrop:
def test_drop_copy(self):
df = DataFrame(
[[1, 2, 3], [3, 4, 5], [5, 6, 7]],
index=["a", "b", "c"],
columns=["d", "e", "f"],
)

msg = "Cannot pass both inplace=True and copy"
with pytest.raises(ValueError, match=msg):
df.drop("d", axis=1, inplace=True, copy=True)
with pytest.raises(ValueError, match=msg):
df.drop("d", axis=1, inplace=True, copy=False)

res = df.drop("d", axis=1, copy=True)
assert not any(tm.shares_memory(res[c], df[c]) for c in res.columns)

res = df.drop("d", axis=1, copy=False)
assert all(tm.shares_memory(res[c], df[c]) for c in res.columns)

def test_drop_names(self):
df = DataFrame(
[[1, 2, 3], [3, 4, 5], [5, 6, 7]],
Expand Down