Repository: pandas-dev/pandas

Issue:
DEPR: DataFrame.swapaxes
This is listed in the general deprecation issue https://github.com/pandas-dev/pandas/issues/18262. 

Now that we have a max dimension of 2, i.e. DataFrame (while before you could have a 3D Panel or NDFrame), I don't think there is any use case for `swapaxes` where it's not exactly the same as `transpose()`. 
It's still implemented independently from `transpose()`, but I _think_ that `df.swapaxes(0, 1)` and `df.swapaxes(1, 0)` are the only two valid options and that gives exactly the same as a `transpose()` (you can do eg `df.swapaxes(0, 0)` which is a no-op, but this generalization doesn't really seem worth keeping it as a separate method, I would say)

So let's deprecate it? (in favor of `transpose()`)


Discussion:
Yeah I don't see a real use case for this either. +1
take
+1

Patch:
diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst
index 1f5c3c88c5ff5..71fda39a05e55 100644
--- a/doc/source/whatsnew/v2.1.0.rst
+++ b/doc/source/whatsnew/v2.1.0.rst
@@ -114,6 +114,7 @@ Deprecations
 - Deprecated 'method', 'limit', and 'fill_axis' keywords in :meth:`DataFrame.align` and :meth:`Series.align`, explicitly call ``fillna`` on the alignment results instead (:issue:`51856`)
 - Deprecated 'broadcast_axis' keyword in :meth:`Series.align` and :meth:`DataFrame.align`, upcast before calling ``align`` with ``left = DataFrame({col: left for col in right.columns}, index=right.index)`` (:issue:`51856`)
 - Deprecated the 'axis' keyword in :meth:`.GroupBy.idxmax`, :meth:`.GroupBy.idxmin`, :meth:`.GroupBy.fillna`, :meth:`.GroupBy.take`, :meth:`.GroupBy.skew`, :meth:`.GroupBy.rank`, :meth:`.GroupBy.cumprod`, :meth:`.GroupBy.cumsum`, :meth:`.GroupBy.cummax`, :meth:`.GroupBy.cummin`, :meth:`.GroupBy.pct_change`, :meth:`GroupBy.diff`, :meth:`.GroupBy.shift`, and :meth:`DataFrameGroupBy.corrwith`; for ``axis=1`` operate on the underlying :class:`DataFrame` instead (:issue:`50405`, :issue:`51046`)
+- Deprecated :meth:`DataFrame.swapaxes` and :meth:`Series.swapaxes`, use :meth:`DataFrame.transpose` or :meth:`Series.transpose` instead (:issue:`51946`)
 -
 
 .. ---------------------------------------------------------------------------
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
index 2b650d99c7e6c..80ac49d460d3d 100644
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -741,6 +741,15 @@ def swapaxes(self, axis1: Axis, axis2: Axis, copy: bool_t | None = None) -> Self
         -------
         same as input
         """
+        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)
 


Test patch:
diff --git a/pandas/tests/copy_view/test_methods.py b/pandas/tests/copy_view/test_methods.py
index 1d8f1dea7d478..7b8bc35f016b1 100644
--- a/pandas/tests/copy_view/test_methods.py
+++ b/pandas/tests/copy_view/test_methods.py
@@ -115,7 +115,13 @@ def test_methods_copy_keyword(
         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)
-    df2 = method(df, copy=copy)
+
+    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)
 
     share_memory = using_copy_on_write or copy is False
 
@@ -184,7 +190,13 @@ 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)
-    ser2 = method(ser, copy=copy)
+
+    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)
 
     share_memory = using_copy_on_write or copy is False
 
@@ -625,7 +637,9 @@ def test_to_frame(using_copy_on_write):
 def test_swapaxes_noop(using_copy_on_write, ax):
     df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
     df_orig = df.copy()
-    df2 = df.swapaxes(ax, ax)
+    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"))
@@ -642,7 +656,9 @@ def test_swapaxes_noop(using_copy_on_write, ax):
 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()
-    df2 = df.swapaxes("index", "columns")
+    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"))
@@ -658,7 +674,9 @@ def test_swapaxes_single_block(using_copy_on_write):
 
 def test_swapaxes_read_only_array():
     df = DataFrame({"a": [1, 2], "b": 3})
-    df = df.swapaxes(axis1="index", axis2="columns")
+    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)
diff --git a/pandas/tests/frame/methods/test_swapaxes.py b/pandas/tests/frame/methods/test_swapaxes.py
index 5da2c2292f137..f2667fc973cf4 100644
--- a/pandas/tests/frame/methods/test_swapaxes.py
+++ b/pandas/tests/frame/methods/test_swapaxes.py
@@ -8,22 +8,30 @@
 class TestSwapAxes:
     def test_swapaxes(self):
         df = DataFrame(np.random.randn(10, 5))
-        tm.assert_frame_equal(df.T, df.swapaxes(0, 1))
-        tm.assert_frame_equal(df.T, df.swapaxes(1, 0))
+        msg = "'DataFrame.swapaxes' is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            tm.assert_frame_equal(df.T, df.swapaxes(0, 1))
+            tm.assert_frame_equal(df.T, df.swapaxes(1, 0))
 
     def test_swapaxes_noop(self):
         df = DataFrame(np.random.randn(10, 5))
-        tm.assert_frame_equal(df, df.swapaxes(0, 0))
+        msg = "'DataFrame.swapaxes' is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            tm.assert_frame_equal(df, df.swapaxes(0, 0))
 
     def test_swapaxes_invalid_axis(self):
         df = DataFrame(np.random.randn(10, 5))
-        msg = "No axis named 2 for object type DataFrame"
-        with pytest.raises(ValueError, match=msg):
-            df.swapaxes(2, 5)
+        msg = "'DataFrame.swapaxes' is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            msg = "No axis named 2 for object type DataFrame"
+            with pytest.raises(ValueError, match=msg):
+                df.swapaxes(2, 5)
 
     def test_round_empty_not_input(self):
         # GH#51032
         df = DataFrame({"a": [1, 2]})
-        result = df.swapaxes("index", "index")
+        msg = "'DataFrame.swapaxes' is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            result = df.swapaxes("index", "index")
         tm.assert_frame_equal(df, result)
         assert df is not result
diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py
index d85de12566fb6..cdab112e7ad86 100644
--- a/pandas/tests/generic/test_finalize.py
+++ b/pandas/tests/generic/test_finalize.py
@@ -251,7 +251,6 @@
             operator.methodcaller("isin", pd.DataFrame({"A": [1]})),
         ),
     ),
-    (pd.DataFrame, frame_data, operator.methodcaller("swapaxes", 0, 1)),
     (pd.DataFrame, frame_mi_data, operator.methodcaller("droplevel", "A")),
     (pd.DataFrame, frame_data, operator.methodcaller("pop", "A")),
     pytest.param(
diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py
index 74d8277c975e4..d23d97f43de03 100644
--- a/pandas/tests/generic/test_generic.py
+++ b/pandas/tests/generic/test_generic.py
@@ -230,8 +230,11 @@ 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)
-        assert len(np.array_split(o, 5)) == 5
-        assert len(np.array_split(o, 2)) == 2
+        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
 
     # See gh-12301
     def test_stat_unexpected_keyword(self, frame_or_series):