Skip to content

Remove DataFrame.swapaxes #57363

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 2 commits into from
Feb 12, 2024
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
2 changes: 0 additions & 2 deletions doc/redirects.csv
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,6 @@ generated/pandas.DataFrame.style,../reference/api/pandas.DataFrame.style
generated/pandas.DataFrame.sub,../reference/api/pandas.DataFrame.sub
generated/pandas.DataFrame.subtract,../reference/api/pandas.DataFrame.subtract
generated/pandas.DataFrame.sum,../reference/api/pandas.DataFrame.sum
generated/pandas.DataFrame.swapaxes,../reference/api/pandas.DataFrame.swapaxes
generated/pandas.DataFrame.swaplevel,../reference/api/pandas.DataFrame.swaplevel
generated/pandas.DataFrame.tail,../reference/api/pandas.DataFrame.tail
generated/pandas.DataFrame.take,../reference/api/pandas.DataFrame.take
Expand Down Expand Up @@ -1206,7 +1205,6 @@ generated/pandas.Series.str.zfill,../reference/api/pandas.Series.str.zfill
generated/pandas.Series.sub,../reference/api/pandas.Series.sub
generated/pandas.Series.subtract,../reference/api/pandas.Series.subtract
generated/pandas.Series.sum,../reference/api/pandas.Series.sum
generated/pandas.Series.swapaxes,../reference/api/pandas.Series.swapaxes
generated/pandas.Series.swaplevel,../reference/api/pandas.Series.swaplevel
generated/pandas.Series.tail,../reference/api/pandas.Series.tail
generated/pandas.Series.take,../reference/api/pandas.Series.take
Expand Down
1 change: 0 additions & 1 deletion doc/source/reference/frame.rst
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ Reshaping, sorting, transposing
DataFrame.swaplevel
DataFrame.stack
DataFrame.unstack
DataFrame.swapaxes
DataFrame.melt
DataFrame.explode
DataFrame.squeeze
Expand Down
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Removal of prior version deprecations/changes
- Removed :meth:`DataFrame.applymap`, :meth:`Styler.applymap` and :meth:`Styler.applymap_index` (:issue:`52364`)
- Removed ``DataFrame.bool`` and ``Series.bool`` (:issue:`51756`)
- Removed ``DataFrame.first`` and ``DataFrame.last`` (:issue:`53710`)
- Removed ``DataFrame.swapaxes`` and ``Series.swapaxes`` (:issue:`51946`)
- Removed ``DataFrameGroupBy.grouper`` and ``SeriesGroupBy.grouper`` (:issue:`56521`)
- Removed ``DataFrameGroupby.fillna`` and ``SeriesGroupBy.fillna``` (:issue:`55719`)
- Removed ``Index.format``, use :meth:`Index.astype` with ``str`` or :meth:`Index.map` with a ``formatter`` function instead (:issue:`55439`)
Expand Down
61 changes: 0 additions & 61 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@
ensure_index,
)
from pandas.core.internals import BlockManager
from pandas.core.internals.construction import ndarray_to_mgr
from pandas.core.methods.describe import describe_ndframe
from pandas.core.missing import (
clean_fill_method,
Expand Down Expand Up @@ -755,66 +754,6 @@ def _set_axis(self, axis: AxisInt, labels: AnyArrayLike | list) -> None:
labels = ensure_index(labels)
self._mgr.set_axis(axis, labels)

@final
def swapaxes(self, axis1: Axis, axis2: Axis, copy: bool | None = None) -> Self:
"""
Interchange axes and swap values axes appropriately.

.. deprecated:: 2.1.0
``swapaxes`` is deprecated and will be removed.
Please use ``transpose`` instead.

Returns
-------
same as input

Examples
--------
Please see examples for :meth:`DataFrame.transpose`.
"""
warnings.warn(
# GH#51946
f"'{type(self).__name__}.swapaxes' is deprecated and "
"will be removed in a future version. "
f"Please use '{type(self).__name__}.transpose' instead.",
FutureWarning,
stacklevel=find_stack_level(),
)

i = self._get_axis_number(axis1)
j = self._get_axis_number(axis2)

if i == j:
return self.copy(deep=False)

mapping = {i: j, j: i}

new_axes = [self._get_axis(mapping.get(k, k)) for k in range(self._AXIS_LEN)]
new_values = self._values.swapaxes(i, j) # type: ignore[union-attr]
if self._mgr.is_single_block and isinstance(self._mgr, BlockManager):
# This should only get hit in case of having a single block, otherwise a
# copy is made, we don't have to set up references.
new_mgr = ndarray_to_mgr(
new_values,
new_axes[0],
new_axes[1],
dtype=None,
copy=False,
)
assert isinstance(new_mgr, BlockManager)
assert isinstance(self._mgr, BlockManager)
new_mgr.blocks[0].refs = self._mgr.blocks[0].refs
new_mgr.blocks[0].refs.add_reference(new_mgr.blocks[0])
out = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes)
return out.__finalize__(self, method="swapaxes")

return self._constructor(
new_values,
*new_axes,
# The no-copy case for CoW is handled above
copy=False,
).__finalize__(self, method="swapaxes")

@final
@doc(klass=_shared_doc_kwargs["klass"])
def droplevel(self, level: IndexLabel, axis: Axis = 0) -> Self:
Expand Down
69 changes: 2 additions & 67 deletions pandas/tests/copy_view/test_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ def test_copy_shallow(using_copy_on_write):
lambda df, copy: df.rename_axis(columns="test", copy=copy),
lambda df, copy: df.astype({"b": "int64"}, copy=copy),
# lambda df, copy: df.swaplevel(0, 0, copy=copy),
lambda df, copy: df.swapaxes(0, 0, copy=copy),
lambda df, copy: df.truncate(0, 5, copy=copy),
lambda df, copy: df.infer_objects(copy=copy),
lambda df, copy: df.to_timestamp(copy=copy),
Expand All @@ -105,7 +104,6 @@ def test_copy_shallow(using_copy_on_write):
"rename_axis1",
"astype",
# "swaplevel", # only series
"swapaxes",
"truncate",
"infer_objects",
"to_timestamp",
Expand All @@ -127,13 +125,7 @@ def test_methods_copy_keyword(request, method, copy, using_copy_on_write):
index = date_range("2012-01-01", freq="D", periods=3, tz="Europe/Brussels")

df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [0.1, 0.2, 0.3]}, index=index)

if "swapaxes" in request.node.callspec.id:
msg = "'DataFrame.swapaxes' is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
df2 = method(df, copy=copy)
else:
df2 = method(df, copy=copy)
df2 = method(df, copy=copy)

share_memory = using_copy_on_write or copy is False

Expand Down Expand Up @@ -161,7 +153,6 @@ def test_methods_copy_keyword(request, method, copy, using_copy_on_write):
lambda ser, copy: ser.rename_axis(index="test", copy=copy),
lambda ser, copy: ser.astype("int64", copy=copy),
lambda ser, copy: ser.swaplevel(0, 1, copy=copy),
lambda ser, copy: ser.swapaxes(0, 0, copy=copy),
lambda ser, copy: ser.truncate(0, 5, copy=copy),
lambda ser, copy: ser.infer_objects(copy=copy),
lambda ser, copy: ser.to_timestamp(copy=copy),
Expand All @@ -180,7 +171,6 @@ def test_methods_copy_keyword(request, method, copy, using_copy_on_write):
"rename_axis0",
"astype",
"swaplevel",
"swapaxes",
"truncate",
"infer_objects",
"to_timestamp",
Expand All @@ -204,13 +194,7 @@ def test_methods_series_copy_keyword(request, method, copy, using_copy_on_write)
index = MultiIndex.from_arrays([[1, 2, 3], [4, 5, 6]])

ser = Series([1, 2, 3], index=index)

if "swapaxes" in request.node.callspec.id:
msg = "'Series.swapaxes' is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
ser2 = method(ser, copy=copy)
else:
ser2 = method(ser, copy=copy)
ser2 = method(ser, copy=copy)

share_memory = using_copy_on_write or copy is False

Expand Down Expand Up @@ -688,55 +672,6 @@ def test_to_frame(using_copy_on_write):
tm.assert_frame_equal(df, expected)


@pytest.mark.parametrize("ax", ["index", "columns"])
def test_swapaxes_noop(using_copy_on_write, ax):
df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
df_orig = df.copy()
msg = "'DataFrame.swapaxes' is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
df2 = df.swapaxes(ax, ax)

if using_copy_on_write:
assert np.shares_memory(get_array(df2, "a"), get_array(df, "a"))
else:
assert not np.shares_memory(get_array(df2, "a"), get_array(df, "a"))

# mutating df2 triggers a copy-on-write for that column/block
df2.iloc[0, 0] = 0
if using_copy_on_write:
assert not np.shares_memory(get_array(df2, "a"), get_array(df, "a"))
tm.assert_frame_equal(df, df_orig)


def test_swapaxes_single_block(using_copy_on_write):
df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}, index=["x", "y", "z"])
df_orig = df.copy()
msg = "'DataFrame.swapaxes' is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
df2 = df.swapaxes("index", "columns")

if using_copy_on_write:
assert np.shares_memory(get_array(df2, "x"), get_array(df, "a"))
else:
assert not np.shares_memory(get_array(df2, "x"), get_array(df, "a"))

# mutating df2 triggers a copy-on-write for that column/block
df2.iloc[0, 0] = 0
if using_copy_on_write:
assert not np.shares_memory(get_array(df2, "x"), get_array(df, "a"))
tm.assert_frame_equal(df, df_orig)


def test_swapaxes_read_only_array():
df = DataFrame({"a": [1, 2], "b": 3})
msg = "'DataFrame.swapaxes' is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
df = df.swapaxes(axis1="index", axis2="columns")
df.iloc[0, 0] = 100
expected = DataFrame({0: [100, 3], 1: [2, 3]}, index=["a", "b"])
tm.assert_frame_equal(df, expected)


@pytest.mark.parametrize(
"method, idx",
[
Expand Down
37 changes: 0 additions & 37 deletions pandas/tests/frame/methods/test_swapaxes.py

This file was deleted.

7 changes: 2 additions & 5 deletions pandas/tests/generic/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,8 @@ def test_size_compat(self, frame_or_series):
def test_split_compat(self, frame_or_series):
# xref GH8846
o = construct(frame_or_series, shape=10)
with tm.assert_produces_warning(
FutureWarning, match=".swapaxes' is deprecated", check_stacklevel=False
):
assert len(np.array_split(o, 5)) == 5
assert len(np.array_split(o, 2)) == 2
assert len(np.array_split(o, 5)) == 5
assert len(np.array_split(o, 2)) == 2
Copy link

Choose a reason for hiding this comment

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

hi 👋 ref numpy/numpy#24889 (comment)

after this PR, calling np.array_split(df) will no longer return list[pd.DataFrame], but list[np.ndarray]. this was not tested here ^

could you fix the split compat? currently, this PR poses quite a nasty breaking change with no obvious migration / alternative at hand.

Copy link

Choose a reason for hiding this comment

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


# See gh-12301
def test_stat_unexpected_keyword(self, frame_or_series):
Expand Down