Repository: modin-project/modin

Issue:
PERF: add_suffix and add_prefix shouldn't map partitions
### Describe the problem
`add_suffix` and `add_prefix` call the modin frame's `rename`, which [maps all blocks](https://github.com/modin-project/modin/blob/49f47b1ed66583d4b90d3c06faf3e1d457cf4df8/modin/core/dataframe/pandas/dataframe/dataframe.py#L1719). Instead, we can just change the names of the indices entire pandas object, and defer the index renaming in the partitions till later.


Discussion:

Resolving patch:
diff --git a/modin/core/dataframe/base/dataframe/dataframe.py b/modin/core/dataframe/base/dataframe/dataframe.py
--- a/modin/core/dataframe/base/dataframe/dataframe.py
+++ b/modin/core/dataframe/base/dataframe/dataframe.py
@@ -478,7 +478,6 @@ def rename(
         self,
         new_row_labels: Optional[Union[Dict[Hashable, Hashable], Callable]] = None,
         new_col_labels: Optional[Union[Dict[Hashable, Hashable], Callable]] = None,
-        level: Optional[Union[int, List[int]]] = None,
     ) -> "ModinDataframe":
         """
         Replace the row and column labels with the specified new labels.
@@ -489,17 +488,11 @@ def rename(
             Mapping or callable that relates old row labels to new labels.
         new_col_labels : dictionary or callable, optional
             Mapping or callable that relates old col labels to new labels.
-        level : int or list of ints, optional
-            Level(s) whose row labels to replace.
 
         Returns
         -------
         ModinDataframe
             A new ModinDataframe with the new row and column labels.
-
-        Notes
-        -----
-        If level is not specified, the default behavior is to replace row labels in all levels.
         """
         pass
 
diff --git a/modin/core/dataframe/pandas/dataframe/dataframe.py b/modin/core/dataframe/pandas/dataframe/dataframe.py
--- a/modin/core/dataframe/pandas/dataframe/dataframe.py
+++ b/modin/core/dataframe/pandas/dataframe/dataframe.py
@@ -1610,57 +1610,6 @@ def astype_builder(df):
             new_dtypes,
         )
 
-    # Metadata modification methods
-    def add_prefix(self, prefix, axis):
-        """
-        Add a prefix to the current row or column labels.
-
-        Parameters
-        ----------
-        prefix : str
-            The prefix to add.
-        axis : int
-            The axis to update.
-
-        Returns
-        -------
-        PandasDataframe
-            A new dataframe with the updated labels.
-        """
-
-        def new_labels_mapper(x, prefix=str(prefix)):
-            return prefix + str(x)
-
-        if axis == 0:
-            return self.rename(new_row_labels=new_labels_mapper)
-        return self.rename(new_col_labels=new_labels_mapper)
-
-    def add_suffix(self, suffix, axis):
-        """
-        Add a suffix to the current row or column labels.
-
-        Parameters
-        ----------
-        suffix : str
-            The suffix to add.
-        axis : int
-            The axis to update.
-
-        Returns
-        -------
-        PandasDataframe
-            A new dataframe with the updated labels.
-        """
-
-        def new_labels_mapper(x, suffix=str(suffix)):
-            return str(x) + suffix
-
-        if axis == 0:
-            return self.rename(new_row_labels=new_labels_mapper)
-        return self.rename(new_col_labels=new_labels_mapper)
-
-    # END Metadata modification methods
-
     def numeric_columns(self, include_bool=True):
         """
         Return the names of numeric columns in the frame.
@@ -2323,7 +2272,6 @@ def rename(
         self,
         new_row_labels: Optional[Union[Dict[Hashable, Hashable], Callable]] = None,
         new_col_labels: Optional[Union[Dict[Hashable, Hashable], Callable]] = None,
-        level: Optional[Union[int, List[int]]] = None,
     ) -> "PandasDataframe":
         """
         Replace the row and column labels with the specified new labels.
@@ -2334,60 +2282,22 @@ def rename(
             Mapping or callable that relates old row labels to new labels.
         new_col_labels : dictionary or callable, optional
             Mapping or callable that relates old col labels to new labels.
-        level : int, optional
-            Level whose row labels to replace.
 
         Returns
         -------
         PandasDataframe
             A new PandasDataframe with the new row and column labels.
-
-        Notes
-        -----
-        If level is not specified, the default behavior is to replace row labels in all levels.
         """
-        new_index = self.index.copy()
-
-        def make_label_swapper(label_dict):
-            if isinstance(label_dict, dict):
-                return lambda label: label_dict.get(label, label)
-            return label_dict
-
-        def swap_labels_levels(index_tuple):
-            if isinstance(new_row_labels, dict):
-                return tuple(new_row_labels.get(label, label) for label in index_tuple)
-            return tuple(new_row_labels(label) for label in index_tuple)
-
-        if new_row_labels:
-            swap_row_labels = make_label_swapper(new_row_labels)
-            if isinstance(self.index, pandas.MultiIndex):
-                if level is not None:
-                    new_index.set_levels(
-                        new_index.levels[level].map(swap_row_labels), level
-                    )
-                else:
-                    new_index = new_index.map(swap_labels_levels)
-            else:
-                new_index = new_index.map(swap_row_labels)
-        new_cols = self.columns.copy()
-        if new_col_labels:
-            new_cols = new_cols.map(make_label_swapper(new_col_labels))
-
-        def map_fn(df):
-            return df.rename(index=new_row_labels, columns=new_col_labels, level=level)
-
-        new_parts = self._partition_mgr_cls.map_partitions(self._partitions, map_fn)
-        new_dtypes = None
-        if self.has_materialized_dtypes:
-            new_dtypes = self.dtypes.set_axis(new_cols)
-        return self.__constructor__(
-            new_parts,
-            new_index,
-            new_cols,
-            self._row_lengths_cache,
-            self._column_widths_cache,
-            new_dtypes,
-        )
+        result = self.copy()
+        if new_row_labels is not None:
+            if callable(new_row_labels):
+                new_row_labels = result.index.map(new_row_labels)
+            result.index = new_row_labels
+        if new_col_labels is not None:
+            if callable(new_col_labels):
+                new_col_labels = result.columns.map(new_col_labels)
+            result.columns = new_col_labels
+        return result
 
     def combine_and_apply(
         self, func, new_index=None, new_columns=None, new_dtypes=None
diff --git a/modin/core/storage_formats/pandas/query_compiler.py b/modin/core/storage_formats/pandas/query_compiler.py
--- a/modin/core/storage_formats/pandas/query_compiler.py
+++ b/modin/core/storage_formats/pandas/query_compiler.py
@@ -326,10 +326,24 @@ def get_dtypes_set(self):
 
     # Metadata modification methods
     def add_prefix(self, prefix, axis=1):
-        return self.__constructor__(self._modin_frame.add_prefix(prefix, axis))
+        if axis == 1:
+            return self.__constructor__(
+                self._modin_frame.rename(new_col_labels=lambda x: f"{prefix}{x}")
+            )
+        else:
+            return self.__constructor__(
+                self._modin_frame.rename(new_row_labels=lambda x: f"{prefix}{x}")
+            )
 
     def add_suffix(self, suffix, axis=1):
-        return self.__constructor__(self._modin_frame.add_suffix(suffix, axis))
+        if axis == 1:
+            return self.__constructor__(
+                self._modin_frame.rename(new_col_labels=lambda x: f"{x}{suffix}")
+            )
+        else:
+            return self.__constructor__(
+                self._modin_frame.rename(new_row_labels=lambda x: f"{x}{suffix}")
+            )
 
     # END Metadata modification methods
 


Test patch: