From 85459965a7e5054e8ba429d37404039cec9c66cd Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 2 Aug 2022 16:11:23 -0700 Subject: [PATCH 1/3] ENH: copy kwd for add_suffix/add_prefix --- doc/source/whatsnew/v1.5.0.rst | 1 + pandas/core/generic.py | 16 ++++++--- .../frame/methods/test_add_prefix_suffix.py | 34 +++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst index 6e38024e02f36..a7f6cd045b961 100644 --- a/doc/source/whatsnew/v1.5.0.rst +++ b/doc/source/whatsnew/v1.5.0.rst @@ -279,6 +279,7 @@ Other enhancements - :class:`Series` reducers (e.g. ``min``, ``max``, ``sum``, ``mean``) will now successfully operate when the dtype is numeric and ``numeric_only=True`` is provided; previously this would raise a ``NotImplementedError`` (:issue:`47500`) - :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:`??`) .. --------------------------------------------------------------------------- .. _whatsnew_150.notable_bug_fixes: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 7352ad2a4985d..499912596bdd9 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -4549,7 +4549,7 @@ def _update_inplace(self, result, verify_is_copy: bool_t = True) -> None: self._maybe_update_cacher(verify_is_copy=verify_is_copy, inplace=True) @final - def add_prefix(self: NDFrameT, prefix: str) -> NDFrameT: + def add_prefix(self: NDFrameT, prefix: str, copy: bool_t = True) -> NDFrameT: """ Prefix labels with string `prefix`. @@ -4560,6 +4560,10 @@ def add_prefix(self: NDFrameT, prefix: str) -> NDFrameT: ---------- prefix : str The string to add before each label. + copy : bool, default True + Whether to copy the underlying data. + + .. versionadded:: 1.5.0 Returns ------- @@ -4610,10 +4614,10 @@ def add_prefix(self: NDFrameT, prefix: str) -> NDFrameT: # expected "NDFrameT") # error: Argument 1 to "rename" of "NDFrame" has incompatible type # "**Dict[str, partial[str]]"; expected "Union[str, int, None]" - return self._rename(**mapper) # type: ignore[return-value, arg-type] + return self._rename(**mapper, copy=copy) # type: ignore[return-value, arg-type] @final - def add_suffix(self: NDFrameT, suffix: str) -> NDFrameT: + def add_suffix(self: NDFrameT, suffix: str, copy: bool_t = True) -> NDFrameT: """ Suffix labels with string `suffix`. @@ -4624,6 +4628,10 @@ def add_suffix(self: NDFrameT, suffix: str) -> NDFrameT: ---------- suffix : str The string to add after each label. + copy : bool, default True + Whether to copy the underlying data. + + .. versionadded:: 1.5.0 Returns ------- @@ -4674,7 +4682,7 @@ def add_suffix(self: NDFrameT, suffix: str) -> NDFrameT: # expected "NDFrameT") # error: Argument 1 to "rename" of "NDFrame" has incompatible type # "**Dict[str, partial[str]]"; expected "Union[str, int, None]" - return self._rename(**mapper) # type: ignore[return-value, arg-type] + return self._rename(**mapper, copy=copy) # type: ignore[return-value, arg-type] @overload def sort_values( diff --git a/pandas/tests/frame/methods/test_add_prefix_suffix.py b/pandas/tests/frame/methods/test_add_prefix_suffix.py index ea75e9ff51552..8f93ab270f6b0 100644 --- a/pandas/tests/frame/methods/test_add_prefix_suffix.py +++ b/pandas/tests/frame/methods/test_add_prefix_suffix.py @@ -18,3 +18,37 @@ def test_add_prefix_suffix(float_frame): with_pct_suffix = float_frame.add_suffix("%") expected = Index([f"{c}%" for c in float_frame.columns]) tm.assert_index_equal(with_pct_suffix.columns, expected) + + +def test_add_prefix_suffix_copy(float_frame): + with_prefix = float_frame.add_prefix("foo#", copy=True) + expected = Index([f"foo#{c}" for c in float_frame.columns]) + tm.assert_index_equal(with_prefix.columns, expected) + assert not any( + tm.shares_memory(float_frame.iloc[:, i], with_prefix.iloc[:, i]) + for i in range(float_frame.shape[1]) + ) + + with_prefix = float_frame.add_prefix("foo#", copy=False) + expected = Index([f"foo#{c}" for c in float_frame.columns]) + tm.assert_index_equal(with_prefix.columns, expected) + assert all( + tm.shares_memory(float_frame.iloc[:, i], with_prefix.iloc[:, i]) + for i in range(float_frame.shape[1]) + ) + + with_suffix = float_frame.add_suffix("#foo", copy=True) + expected = Index([f"{c}#foo" for c in float_frame.columns]) + tm.assert_index_equal(with_suffix.columns, expected) + assert not any( + tm.shares_memory(float_frame.iloc[:, i], with_suffix.iloc[:, i]) + for i in range(float_frame.shape[1]) + ) + + with_suffix = float_frame.add_suffix("#foo", copy=False) + expected = Index([f"{c}#foo" for c in float_frame.columns]) + tm.assert_index_equal(with_suffix.columns, expected) + assert all( + tm.shares_memory(float_frame.iloc[:, i], with_suffix.iloc[:, i]) + for i in range(float_frame.shape[1]) + ) From c57a7aa546931a0824afcc5bb7e43a912d4a094a Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 2 Aug 2022 16:12:39 -0700 Subject: [PATCH 2/3] GH ref --- doc/source/whatsnew/v1.5.0.rst | 2 +- pandas/tests/frame/methods/test_add_prefix_suffix.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst index a7f6cd045b961..cd93329a75c8a 100644 --- a/doc/source/whatsnew/v1.5.0.rst +++ b/doc/source/whatsnew/v1.5.0.rst @@ -279,7 +279,7 @@ Other enhancements - :class:`Series` reducers (e.g. ``min``, ``max``, ``sum``, ``mean``) will now successfully operate when the dtype is numeric and ``numeric_only=True`` is provided; previously this would raise a ``NotImplementedError`` (:issue:`47500`) - :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:`??`) +- :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`) .. --------------------------------------------------------------------------- .. _whatsnew_150.notable_bug_fixes: diff --git a/pandas/tests/frame/methods/test_add_prefix_suffix.py b/pandas/tests/frame/methods/test_add_prefix_suffix.py index 8f93ab270f6b0..325a954035b25 100644 --- a/pandas/tests/frame/methods/test_add_prefix_suffix.py +++ b/pandas/tests/frame/methods/test_add_prefix_suffix.py @@ -21,6 +21,7 @@ def test_add_prefix_suffix(float_frame): def test_add_prefix_suffix_copy(float_frame): + # GH#47934 with_prefix = float_frame.add_prefix("foo#", copy=True) expected = Index([f"foo#{c}" for c in float_frame.columns]) tm.assert_index_equal(with_prefix.columns, expected) From 609dcd387063e94d779a11c18ca3e0790dd2d1fd Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 9 Aug 2022 08:47:52 -0700 Subject: [PATCH 3/3] test series --- .../frame/methods/test_add_prefix_suffix.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pandas/tests/frame/methods/test_add_prefix_suffix.py b/pandas/tests/frame/methods/test_add_prefix_suffix.py index 325a954035b25..cc36a3caf6ec7 100644 --- a/pandas/tests/frame/methods/test_add_prefix_suffix.py +++ b/pandas/tests/frame/methods/test_add_prefix_suffix.py @@ -22,6 +22,8 @@ def test_add_prefix_suffix(float_frame): def test_add_prefix_suffix_copy(float_frame): # GH#47934 + ser = float_frame.iloc[0] + with_prefix = float_frame.add_prefix("foo#", copy=True) expected = Index([f"foo#{c}" for c in float_frame.columns]) tm.assert_index_equal(with_prefix.columns, expected) @@ -30,6 +32,10 @@ def test_add_prefix_suffix_copy(float_frame): for i in range(float_frame.shape[1]) ) + ser_with_prefix = ser.add_prefix("foo#", copy=True) + tm.assert_index_equal(ser_with_prefix.index, expected) + assert not tm.shares_memory(ser_with_prefix, ser) + with_prefix = float_frame.add_prefix("foo#", copy=False) expected = Index([f"foo#{c}" for c in float_frame.columns]) tm.assert_index_equal(with_prefix.columns, expected) @@ -38,6 +44,10 @@ def test_add_prefix_suffix_copy(float_frame): for i in range(float_frame.shape[1]) ) + ser_with_prefix = ser.add_prefix("foo#", copy=False) + tm.assert_index_equal(ser_with_prefix.index, expected) + assert tm.shares_memory(ser_with_prefix, ser) + with_suffix = float_frame.add_suffix("#foo", copy=True) expected = Index([f"{c}#foo" for c in float_frame.columns]) tm.assert_index_equal(with_suffix.columns, expected) @@ -46,6 +56,10 @@ def test_add_prefix_suffix_copy(float_frame): for i in range(float_frame.shape[1]) ) + ser_with_suffix = ser.add_suffix("#foo", copy=True) + tm.assert_index_equal(ser_with_suffix.index, expected) + assert not tm.shares_memory(ser_with_suffix, ser) + with_suffix = float_frame.add_suffix("#foo", copy=False) expected = Index([f"{c}#foo" for c in float_frame.columns]) tm.assert_index_equal(with_suffix.columns, expected) @@ -53,3 +67,7 @@ def test_add_prefix_suffix_copy(float_frame): tm.shares_memory(float_frame.iloc[:, i], with_suffix.iloc[:, i]) for i in range(float_frame.shape[1]) ) + + ser_with_suffix = ser.add_suffix("#foo", copy=False) + tm.assert_index_equal(ser_with_suffix.index, expected) + assert tm.shares_memory(ser_with_suffix, ser)