Repository: modin-project/modin

Issue:
Modin df.isnull().sum() slower than Stock Pandas
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: Linux Ubuntu 20.08
- **Modin version** (`modin.__version__`): 0.9
- **Python version**: 3.8
- **Code we can use to reproduce**: https://github.com/oneapi-src/oneAPI-samples/tree/master/AI-and-Analytics/Getting-Started-Samples/IntelModin_GettingStarted and code on screenshot (add at end):
- 
![image](https://user-images.githubusercontent.com/26121125/115251549-a7a6eb80-a0f8-11eb-8c0d-15a529490f14.png)


<!--
You can obtain the Modin version with

python -c "import modin; print(modin.__version__)"
-->

### Describe the problem
Tested on 2 separate datasets, and machines, on AI Kit Modin and pip Modin installations - the dataset used in the screenshot code is 1.67 GB, so should be large enough to show performance. 
df.isnull().sum() is significantly slower than stock Pandas (Modin performs at approximately 0.17x of stock Pandas speed).

Slow-down performance seen on multiple runs.

### Source code / logs
See GitHub and screenshot above^



Discussion:
@aregm please prioritize

Resolving patch:
diff --git a/modin/backends/pandas/query_compiler.py b/modin/backends/pandas/query_compiler.py
--- a/modin/backends/pandas/query_compiler.py
+++ b/modin/backends/pandas/query_compiler.py
@@ -1335,15 +1335,6 @@ def stack(self, level, dropna):
         )
     )
 
-    def repeat(self, repeats):
-        def map_fn(df):
-            return pandas.DataFrame(df.squeeze(axis=1).repeat(repeats))
-
-        if isinstance(repeats, int) or (is_list_like(repeats) and len(repeats) == 1):
-            return MapFunction.register(map_fn, validate_index=True)(self)
-        else:
-            return self.__constructor__(self._modin_frame._apply_full_axis(0, map_fn))
-
     # END Map partitions operations
 
     # String map partitions operations
@@ -1488,9 +1479,6 @@ def datetime_freq(df):
     dt_days = MapFunction.register(_dt_prop_map("days"))
     dt_microseconds = MapFunction.register(_dt_prop_map("microseconds"))
     dt_nanoseconds = MapFunction.register(_dt_prop_map("nanoseconds"))
-    dt_components = MapFunction.register(
-        _dt_prop_map("components"), validate_columns=True
-    )
     dt_qyear = MapFunction.register(_dt_prop_map("qyear"))
     dt_start_time = MapFunction.register(_dt_prop_map("start_time"))
     dt_end_time = MapFunction.register(_dt_prop_map("end_time"))
diff --git a/modin/engines/base/frame/data.py b/modin/engines/base/frame/data.py
--- a/modin/engines/base/frame/data.py
+++ b/modin/engines/base/frame/data.py
@@ -1241,7 +1241,7 @@ def _map_reduce(self, axis, map_func, reduce_func=None):
         )
         return self._compute_map_reduce_metadata(axis, reduce_parts)
 
-    def _map(self, func, dtypes=None, validate_index=False, validate_columns=False):
+    def _map(self, func, dtypes=None):
         """
         Perform a function that maps across the entire dataset.
 
@@ -1253,10 +1253,6 @@ def _map(self, func, dtypes=None, validate_index=False, validate_columns=False):
             The data types for the result. This is an optimization
             because there are functions that always result in a particular data
             type, and this allows us to avoid (re)computing it.
-        validate_index : bool, default: False
-            Is index validation required after performing `func` on partitions.
-        validate_columns : bool, default: False
-            Is column validation required after performing `func` on partitions.
 
         Returns
         -------
@@ -1270,26 +1266,12 @@ def _map(self, func, dtypes=None, validate_index=False, validate_columns=False):
             dtypes = pandas.Series(
                 [np.dtype(dtypes)] * len(self.columns), index=self.columns
             )
-
-        axis_validate_mask = [validate_index, validate_columns]
-        new_axes = [
-            self._compute_axis_labels(axis, new_partitions)
-            if should_validate
-            else self.axes[axis]
-            for axis, should_validate in enumerate(axis_validate_mask)
-        ]
-
-        new_lengths = [
-            self._axes_lengths[axis]
-            if len(new_axes[axis]) == len(self.axes[axis])
-            else None
-            for axis in [0, 1]
-        ]
-
         return self.__constructor__(
             new_partitions,
-            *new_axes,
-            *new_lengths,
+            self.axes[0],
+            self.axes[1],
+            self._row_lengths_cache,
+            self._column_widths_cache,
             dtypes=dtypes,
         )
 


Test patch: