Repository: modin-project/modin

Issue:
Document `modin.backends.pandas`



Discussion:

Resolving patch:
diff --git a/modin/backends/pandas/__init__.py b/modin/backends/pandas/__init__.py
--- a/modin/backends/pandas/__init__.py
+++ b/modin/backends/pandas/__init__.py
@@ -11,6 +11,8 @@
 # ANY KIND, either express or implied. See the License for the specific language
 # governing permissions and limitations under the License.
 
+"""The module represents the query compiler level for the pandas backend."""
+
 from .query_compiler import PandasQueryCompiler
 
 __all__ = ["PandasQueryCompiler"]
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
@@ -11,6 +11,13 @@
 # ANY KIND, either express or implied. See the License for the specific language
 # governing permissions and limitations under the License.
 
+"""
+Module contains ``PandasQueryCompiler`` class.
+
+``PandasQueryCompiler`` is responsible for compiling efficient DataFrame algebra
+queries for the ``BasePandasFrame``.
+"""
+
 import numpy as np
 import pandas
 from pandas.core.common import is_bool_indexer
@@ -30,7 +37,12 @@
 
 from modin.backends.base.query_compiler import BaseQueryCompiler
 from modin.error_message import ErrorMessage
-from modin.utils import try_cast_to_pandas, wrap_udf_function, hashable
+from modin.utils import (
+    try_cast_to_pandas,
+    wrap_udf_function,
+    hashable,
+    _inherit_docstrings,
+)
 from modin.data_management.functions import (
     FoldFunction,
     MapFunction,
@@ -43,6 +55,18 @@
 
 
 def _get_axis(axis):
+    """
+    Build index labels getter of the specified axis.
+
+    Parameters
+    ----------
+    axis : {0, 1}
+        Axis to get labels from. 0 is for index and 1 is for column.
+
+    Returns
+    -------
+    callable(PandasQueryCompiler) -> pandas.Index
+    """
     if axis == 0:
         return lambda self: self._modin_frame.index
     else:
@@ -50,6 +74,18 @@ def _get_axis(axis):
 
 
 def _set_axis(axis):
+    """
+    Build index labels setter of the specified axis.
+
+    Parameters
+    ----------
+    axis : {0, 1}
+        Axis to set labels on. 0 is for index and 1 is for column.
+
+    Returns
+    -------
+    callable(PandasQueryCompiler)
+    """
     if axis == 0:
 
         def set_axis(self, idx):
@@ -64,7 +100,21 @@ def set_axis(self, cols):
 
 
 def _str_map(func_name):
+    """
+    Build function that calls specified string function on frames ``str`` accessor.
+
+    Parameters
+    ----------
+    func_name : str
+        String function name to execute on ``str`` accessor.
+
+    Returns
+    -------
+    callable(pandas.DataFrame, *args, **kwargs) -> pandas.DataFrame
+    """
+
     def str_op_builder(df, *args, **kwargs):
+        """Apply specified function against `str` accessor of the passed frame."""
         str_s = df.squeeze(axis=1).str
         return getattr(pandas.Series.str, func_name)(str_s, *args, **kwargs).to_frame()
 
@@ -73,23 +123,25 @@ def str_op_builder(df, *args, **kwargs):
 
 def _dt_prop_map(property_name):
     """
-    Create a function that call property of property `dt` of the series.
+    Build function that access specified property of the ``dt`` property of the passed frame.
 
     Parameters
     ----------
-    property_name
-        The property of `dt`, which will be applied.
+    property_name : str
+        Date-time property name to access.
 
     Returns
     -------
-        A callable function to be applied in the partitions
+    callable(pandas.DataFrame, *args, **kwargs) -> pandas.DataFrame
+        Function to be applied in the partitions.
 
     Notes
     -----
-    This applies non-callable properties of `Series.dt`.
+    This applies non-callable properties of ``Series.dt``.
     """
 
     def dt_op_builder(df, *args, **kwargs):
+        """Access specified date-time property of the passed frame."""
         prop_val = getattr(df.squeeze(axis=1).dt, property_name)
         if isinstance(prop_val, pandas.Series):
             return prop_val.to_frame()
@@ -103,23 +155,25 @@ def dt_op_builder(df, *args, **kwargs):
 
 def _dt_func_map(func_name):
     """
-    Create a function that call method of property `dt` of the series.
+    Build function that apply specified method against ``dt`` property of the passed frame.
 
     Parameters
     ----------
-    func_name
-        The method of `dt`, which will be applied.
+    func_name : str
+        Date-time function name to apply.
 
     Returns
     -------
-        A callable function to be applied in the partitions
+    callable(pandas.DataFrame, *args, **kwargs) -> pandas.DataFrame
+        Function to be applied in the partitions.
 
     Notes
     -----
-    This applies callable methods of `Series.dt`.
+    This applies callable methods of ``Series.dt``.
     """
 
     def dt_op_builder(df, *args, **kwargs):
+        """Apply specified function against ``dt`` accessor of the passed frame."""
         dt_s = df.squeeze(axis=1).dt
         return pandas.DataFrame(
             getattr(pandas.Series.dt, func_name)(dt_s, *args, **kwargs)
@@ -130,22 +184,26 @@ def dt_op_builder(df, *args, **kwargs):
 
 def copy_df_for_func(func, display_name: str = None):
     """
-    Create a function that copies the dataframe, likely because `func` is inplace.
+    Build function that execute specified `func` against passed frame inplace.
+
+    Built function copies passed frame, applies `func` to the copy and returns
+    the modified frame.
 
     Parameters
     ----------
-    func : callable
+    func : callable(pandas.DataFrame)
         The function, usually updates a dataframe inplace.
     display_name : str, optional
         The function's name, which is displayed by progress bar.
 
     Returns
     -------
-    callable
-        A callable function to be applied in the partitions
+    callable(pandas.DataFrame)
+        A callable function to be applied in the partitions.
     """
 
     def caller(df, *args, **kwargs):
+        """Apply specified function the passed frame inplace."""
         df = df.copy()
         func(df, *args, **kwargs)
         return df
@@ -155,35 +213,24 @@ def caller(df, *args, **kwargs):
     return caller
 
 
+@_inherit_docstrings(BaseQueryCompiler)
 class PandasQueryCompiler(BaseQueryCompiler):
-    """This class implements the logic necessary for operating on partitions
-    with a Pandas backend. This logic is specific to Pandas."""
+    """
+    Query compiler for the pandas backend.
+
+    This class translates common query compiler API into the DataFrame Algebra
+    queries, that is supposed to be executed by :py:class:`~modin.engines.base.frame.data.BasePandasFrame`.
+
+    Parameters
+    ----------
+    modin_frame : BasePandasFrame
+        Modin Frame to query with the compiled queries.
+    """
 
     def __init__(self, modin_frame):
         self._modin_frame = modin_frame
 
     def default_to_pandas(self, pandas_op, *args, **kwargs):
-        """
-        Default to pandas behavior.
-
-        Parameters
-        ----------
-        pandas_op : callable
-            The operation to apply, must be compatible pandas DataFrame call
-        args
-            The arguments for the `pandas_op`
-        kwargs
-            The keyword arguments for the `pandas_op`
-
-        Returns
-        -------
-        PandasQueryCompiler
-            The result of the `pandas_op`, converted back to PandasQueryCompiler
-
-        Notes
-        -----
-        This operation takes a distributed object and converts it directly to pandas.
-        """
         op_name = getattr(pandas_op, "__name__", str(pandas_op))
         ErrorMessage.default_to_pandas(op_name)
         args = (a.to_pandas() if isinstance(a, type(self)) else a for a in args)
@@ -256,15 +303,6 @@ def copy(self):
     # future. TODO (devin-petersohn): Delay reindexing
 
     def concat(self, axis, other, **kwargs):
-        """Concatenates two objects together.
-
-        Args:
-            axis: The axis index object to join (0 for columns, 1 for index).
-            other: The other_index to concat with.
-
-        Returns:
-            Concatenated objects.
-        """
         if not isinstance(other, list):
             other = [other]
         assert all(
@@ -290,7 +328,6 @@ def concat(self, axis, other, **kwargs):
 
     # Data Management Methods
     def free(self):
-        """In the future, this will hopefully trigger a cleanup of this object."""
         # TODO create a way to clean up this object.
         return
 
@@ -298,13 +335,6 @@ def free(self):
 
     # To NumPy
     def to_numpy(self, **kwargs):
-        """
-        Converts Modin DataFrame to NumPy array.
-
-        Returns
-        -------
-            NumPy array of the QueryCompiler.
-        """
         arr = self._modin_frame.to_numpy(**kwargs)
         ErrorMessage.catch_bugs_and_request_email(
             len(arr) != len(self.index) or len(arr[0]) != len(self.columns)
@@ -358,15 +388,6 @@ def to_numpy(self, **kwargs):
     )
 
     def where(self, cond, other, **kwargs):
-        """Gets values from this manager where cond is true else from other.
-
-        Args:
-            cond: Condition on which to evaluate values.
-
-        Returns:
-            New QueryCompiler with updated data and index.
-        """
-
         assert isinstance(
             cond, type(self)
         ), "Must have the same QueryCompiler subclass to perform this operation"
@@ -402,23 +423,6 @@ def where_builder_series(df, cond):
         return self.__constructor__(new_modin_frame)
 
     def merge(self, right, **kwargs):
-        """
-        Merge DataFrame or named Series objects with a database-style join.
-
-        Parameters
-        ----------
-        right : PandasQueryCompiler
-            The query compiler of the right DataFrame to merge with.
-
-        Returns
-        -------
-        PandasQueryCompiler
-            A new query compiler that contains result of the merge.
-
-        Notes
-        -----
-        See pd.merge or pd.DataFrame.merge for more info on kwargs.
-        """
         how = kwargs.get("how", "inner")
         on = kwargs.get("on", None)
         left_on = kwargs.get("left_on", None)
@@ -470,23 +474,6 @@ def map_func(left, right=right, kwargs=kwargs):
             return self.default_to_pandas(pandas.DataFrame.merge, right, **kwargs)
 
     def join(self, right, **kwargs):
-        """
-        Join columns of another DataFrame.
-
-        Parameters
-        ----------
-        right : BaseQueryCompiler
-            The query compiler of the right DataFrame to join with.
-
-        Returns
-        -------
-        BaseQueryCompiler
-            A new query compiler that contains result of the join.
-
-        Notes
-        -----
-        See pd.DataFrame.join for more info on kwargs.
-        """
         on = kwargs.get("on", None)
         how = kwargs.get("how", "left")
         sort = kwargs.get("sort", False)
@@ -508,15 +495,6 @@ def map_func(left, right=right, kwargs=kwargs):
 
     # Reindex/reset_index (may shuffle data)
     def reindex(self, axis, labels, **kwargs):
-        """Fits a new index for this Manager.
-
-        Args:
-            axis: The axis index object to target the reindex on.
-            labels: New labels to conform 'axis' on to.
-
-        Returns:
-            A new QueryCompiler with updated data and new index.
-        """
         new_index = self.index if axis else labels
         new_columns = labels if axis else self.columns
         new_modin_frame = self._modin_frame._apply_full_axis(
@@ -528,11 +506,6 @@ def reindex(self, axis, labels, **kwargs):
         return self.__constructor__(new_modin_frame)
 
     def reset_index(self, **kwargs):
-        """Removes all levels from index and sets a default level_0 index.
-
-        Returns:
-            A new QueryCompiler with updated data and reset index.
-        """
         drop = kwargs.get("drop", False)
         level = kwargs.get("level", None)
         new_index = None
@@ -636,23 +609,6 @@ def reset_index(self, **kwargs):
     def set_index_from_columns(
         self, keys: List[Hashable], drop: bool = True, append: bool = False
     ):
-        """Create new row labels from a list of columns.
-
-        Parameters
-        ----------
-        keys : list of hashable
-            The list of column names that will become the new index.
-        drop : boolean
-            Whether or not to drop the columns provided in the `keys` argument
-        append : boolean
-            Whether or not to add the columns in `keys` as new levels appended to the
-            existing index.
-
-        Returns
-        -------
-        PandasQueryCompiler
-            A new QueryCompiler with updated index.
-        """
         new_modin_frame = self._modin_frame.to_labels(keys)
         if append:
             arrays = []
@@ -696,26 +652,10 @@ def set_index_from_columns(
     # for simplicity of implementation.
 
     def transpose(self, *args, **kwargs):
-        """Transposes this QueryCompiler.
-
-        Returns:
-            Transposed new QueryCompiler.
-        """
         # Switch the index and columns and transpose the data within the blocks.
         return self.__constructor__(self._modin_frame.transpose())
 
     def columnarize(self):
-        """
-        Transposes this QueryCompiler if it has a single row but multiple columns.
-
-        This method should be called for QueryCompilers representing a Series object,
-        i.e. self.is_series_like() should be True.
-
-        Returns
-        -------
-        PandasQueryCompiler
-            Transposed new QueryCompiler or self.
-        """
         if len(self.columns) != 1 or (
             len(self.index) == 1 and self.index[0] == "__reduced__"
         ):
@@ -723,7 +663,6 @@ def columnarize(self):
         return self
 
     def is_series_like(self):
-        """Return True if QueryCompiler has a single column or row"""
         return len(self.columns) == 1 or len(self.index) == 1
 
     # END Transpose
@@ -732,12 +671,14 @@ def is_series_like(self):
 
     def is_monotonic_decreasing(self):
         def is_monotonic_decreasing(df):
+            """Check whether data in the passed frame is monotonic decreasing."""
             return pandas.DataFrame([df.squeeze(axis=1).is_monotonic_decreasing])
 
         return self.default_to_pandas(is_monotonic_decreasing)
 
     def is_monotonic_increasing(self):
         def is_monotonic_increasing(df):
+            """Check whether data in the passed frame is monotonic increasing."""
             return pandas.DataFrame([df.squeeze(axis=1).is_monotonic_increasing])
 
         return self.default_to_pandas(is_monotonic_increasing)
@@ -747,7 +688,7 @@ def is_monotonic_increasing(df):
     def sum(self, squeeze_self, axis, **kwargs):
         # TODO: rework to original implementation after pandas issue #41074 resolves if possible.
         def map_func(df, **kwargs):
-            """Apply .sum to DataFrame or Series in depend on `squeeze_self.`"""
+            """Apply sum function to DataFrame or Series depending on `squeeze_self`."""
             if squeeze_self:
                 result = df.squeeze(axis=1).sum(**kwargs)
                 if is_scalar(result):
@@ -770,7 +711,7 @@ def map_func(df, **kwargs):
     def prod(self, squeeze_self, axis, **kwargs):
         # TODO: rework to original implementation after pandas issue #41074 resolves if possible.
         def map_func(df, **kwargs):
-            """Apply .prod to DataFrame or Series in depend on `squeeze_self.`"""
+            """Apply product function to DataFrame or Series depending on `squeeze_self`."""
             if squeeze_self:
                 result = df.squeeze(axis=1).prod(**kwargs)
                 if is_scalar(result):
@@ -836,6 +777,11 @@ def mean(self, axis, **kwargs):
         # Since `count(numeric_only=True)` discards all unknown "numeric" types, we can get incorrect
         # divisor inside the reduce function.
         def map_fn(df, **kwargs):
+            """
+            Perform Map phase of the `mean`.
+
+            Compute sum and number of elements in a given partition.
+            """
             result = pandas.DataFrame(
                 {
                     "sum": df.sum(axis=axis, skipna=skipna),
@@ -845,6 +791,12 @@ def map_fn(df, **kwargs):
             return result if axis else result.T
 
         def reduce_fn(df, **kwargs):
+            """
+            Perform Reduce phase of the `mean`.
+
+            Compute sum for all the the partitions and divide it to
+            the total number of elements.
+            """
             sum_cols = df["sum"] if axis else df.loc["sum"]
             count_cols = df["count"] if axis else df.loc["count"]
 
@@ -861,14 +813,6 @@ def reduce_fn(df, **kwargs):
         )(self, axis=axis, **kwargs)
 
     def value_counts(self, **kwargs):
-        """
-        Return a QueryCompiler of Series containing counts of unique values.
-
-        Returns
-        -------
-        PandasQueryCompiler
-        """
-
         def value_counts(df):
             return df.squeeze(axis=1).value_counts(**kwargs).to_frame()
 
@@ -890,7 +834,7 @@ def value_counts(df):
     def sum_min_count(self, squeeze_self, axis, **kwargs):
         # TODO: rework to original implementation after pandas issue #41074 resolves if possible.
         def reduce_func(df, **kwargs):
-            """Apply .sum to DataFrame or Series in depend on `squeeze_self.`"""
+            """Apply sum function to DataFrame or Series depending on `squeeze_self`."""
             if squeeze_self:
                 result = df.squeeze(axis=1).sum(**kwargs)
                 if is_scalar(result):
@@ -912,7 +856,7 @@ def reduce_func(df, **kwargs):
     def prod_min_count(self, squeeze_self, axis, **kwargs):
         # TODO: rework to original implementation after pandas issue #41074 resolves if possible.
         def reduce_func(df, **kwargs):
-            """Apply .prod to DataFrame or Series in depend on `squeeze_self.`"""
+            """Apply product function to DataFrame or Series depending on `squeeze_self`."""
             if squeeze_self:
                 result = df.squeeze(axis=1).prod(**kwargs)
                 if is_scalar(result):
@@ -945,7 +889,33 @@ def reduce_func(df, **kwargs):
     def _resample_func(
         self, resample_args, func_name, new_columns=None, df_op=None, *args, **kwargs
     ):
+        """
+        Resample underlying time-series data and apply aggregation on it.
+
+        Parameters
+        ----------
+        resample_args : list
+            Resample parameters in the format of ``modin.pandas.DataFrame.resample`` signature.
+        func_name : str
+            Aggregation function name to apply on resampler object.
+        new_columns : list of labels, optional
+            Actual column labels of the resulted frame, supposed to be a hint for the
+            Modin frame. If not specified will be computed automaticly.
+        df_op : callable(pandas.DataFrame) -> [pandas.DataFrame, pandas.Series], optional
+            Preprocessor function to apply to the passed frame before resampling.
+        *args : args
+            Arguments to pass to the aggregation function.
+        **kwargs : kwargs
+            Arguments to pass to the aggregation function.
+
+        Returns
+        -------
+        PandasQueryCompiler
+            New QueryCompiler containing the result of resample aggregation.
+        """
+
         def map_func(df, resample_args=resample_args):
+            """Resample time-series data of the passed frame and apply aggregation function on it."""
             if df_op is not None:
                 df = df_op(df)
             resampled_val = df.resample(*resample_args)
@@ -1281,6 +1251,22 @@ def map_func(df):
             return pandas.DataFrame(df.unstack(level=level, fill_value=fill_value))
 
         def is_tree_like_or_1d(calc_index, valid_index):
+            """
+            Check whether specified index is a single dimensional or built in a tree manner.
+
+            Parameters
+            ----------
+            calc_index : pandas.Index
+                Frame index to check.
+            valid_index : pandas.Index
+                Frame index on the opposite from `calc_index` axis.
+
+            Returns
+            -------
+            bool
+                True if `calc_index` is not MultiIndex or MultiIndex and built in a tree manner.
+                False otherwise.
+            """
             if not isinstance(calc_index, pandas.MultiIndex):
                 return True
             actual_len = 1
@@ -1313,6 +1299,28 @@ def is_tree_like_or_1d(calc_index, valid_index):
         result = self.__constructor__(new_modin_frame)
 
         def compute_index(index, columns, consider_index=True, consider_columns=True):
+            """
+            Compute new index for the unstacked frame.
+
+            Parameters
+            ----------
+            index : pandas.Index
+                Index of the original frame.
+            columns : pandas.Index
+                Columns of the original frame.
+            consider_index : bool, default: True
+                Whether original index contains duplicated values.
+                If True all duplicates will be droped.
+            consider_columns : bool, default: True
+                Whether original columns contains duplicated values.
+                If True all duplicates will be droped.
+
+            Returns
+            -------
+            pandas.Index
+                New index to use in the unstacked frame.
+            """
+
             def get_unique_level_values(index):
                 return [
                     index.get_level_values(lvl).unique()
@@ -1478,13 +1486,6 @@ def stack(self, level, dropna):
     # END String map partitions operations
 
     def unique(self):
-        """Return unique values of Series object.
-
-        Returns
-        -------
-        ndarray
-            The unique values returned as a NumPy array.
-        """
         new_modin_frame = self._modin_frame._apply_full_axis(
             0,
             lambda x: x.squeeze(axis=1).unique(),
@@ -1493,16 +1494,8 @@ def unique(self):
         return self.__constructor__(new_modin_frame)
 
     def searchsorted(self, **kwargs):
-        """
-        Return a QueryCompiler with value/values indicies, which they should be inserted
-        to maintain order of the passed Series.
-
-        Returns
-        -------
-        PandasQueryCompiler
-        """
-
         def searchsorted(df):
+            """Apply `searchsorted` function to a single partition."""
             result = df.squeeze(axis=1).searchsorted(**kwargs)
             if not is_list_like(result):
                 result = [result]
@@ -1576,27 +1569,13 @@ def datetime_freq(df):
     # END Dt map partitions operations
 
     def astype(self, col_dtypes, **kwargs):
-        """Converts columns dtypes to given dtypes.
-
-        Args:
-            col_dtypes: Dictionary of {col: dtype,...} where col is the column
-                name and dtype is a numpy dtype.
-
-        Returns:
-            DataFrame with updated dtypes.
-        """
         return self.__constructor__(self._modin_frame.astype(col_dtypes))
 
     # Column/Row partitions reduce operations
 
     def first_valid_index(self):
-        """Returns index of first non-NaN/NULL value.
-
-        Return:
-            Scalar of index name.
-        """
-
         def first_valid_index_builder(df):
+            """Get the position of the first valid index in a single partition."""
             return df.set_axis(
                 pandas.RangeIndex(len(df.index)), axis="index", inplace=False
             ).apply(lambda df: df.first_valid_index())
@@ -1615,13 +1594,8 @@ def first_valid_index_builder(df):
         return self.index[first_result]
 
     def last_valid_index(self):
-        """Returns index of last non-NaN/NULL value.
-
-        Return:
-            Scalar of index name.
-        """
-
         def last_valid_index_builder(df):
+            """Get the position of the last valid index in a single partition."""
             return df.set_axis(
                 pandas.RangeIndex(len(df.index)), axis="index", inplace=False
             ).apply(lambda df: df.last_valid_index())
@@ -1647,11 +1621,6 @@ def last_valid_index_builder(df):
     # This will return a new QueryCompiler object which the front end will handle.
 
     def describe(self, **kwargs):
-        """Generates descriptive statistics.
-
-        Returns:
-            DataFrame object containing the descriptive statistics of the DataFrame.
-        """
         # Use pandas to calculate the correct columns
         empty_df = (
             pandas.DataFrame(columns=self.columns)
@@ -1674,6 +1643,7 @@ def describe(self, **kwargs):
                     break
 
         def describe_builder(df, internal_indices=[]):
+            """Apply `describe` function to the subset of columns in a single partition."""
             return df.iloc[:, internal_indices].describe(**kwargs)
 
         return self.__constructor__(
@@ -1727,21 +1697,22 @@ def cov(self, min_periods=None):
 
     def _nancorr(self, min_periods=1, cov=False):
         """
-        Compute either pairwise covariance or pairwise correlation of columns,
-        considering NA/null values the same like pandas does.
+        Compute either pairwise covariance or pairwise correlation of columns.
+
+        This function considers NA/null values the same like pandas does.
 
         Parameters
         ----------
-        min_periods : int, default 1
+        min_periods : int, default: 1
             Minimum number of observations required per pair of columns
             to have a valid result.
-        cov : boolean, default False
+        cov : boolean, default: False
             Either covariance or correlation should be computed.
 
         Returns
         -------
         PandasQueryCompiler
-            The covariance or correlation matrix of the series of the DataFrame.
+            The covariance or correlation matrix.
         """
         other = self.to_numpy()
         other_mask = self._isfinite().to_numpy()
@@ -1751,6 +1722,7 @@ def _nancorr(self, min_periods=1, cov=False):
             min_periods = 1
 
         def map_func(df):
+            """Compute covariance or correlation matrix for the passed frame."""
             df = df.to_numpy()
             n_rows = df.shape[0]
             df_mask = np.isfinite(df)
@@ -1797,23 +1769,6 @@ def map_func(df):
         return transponed_self.__constructor__(new_modin_frame)
 
     def dot(self, other, squeeze_self=None, squeeze_other=None):
-        """
-        Computes the matrix multiplication of self and other.
-
-        Parameters
-        ----------
-            other : PandasQueryCompiler or NumPy array
-                The other query compiler or NumPy array to matrix multiply with self.
-            squeeze_self : boolean
-                The flag to squeeze self.
-            squeeze_other : boolean
-                The flag to squeeze other (this flag is applied if other is query compiler).
-
-        Returns
-        -------
-        PandasQueryCompiler
-            A new query compiler that contains result of the matrix multiply.
-        """
         if isinstance(other, PandasQueryCompiler):
             other = (
                 other.to_pandas().squeeze(axis=1)
@@ -1822,6 +1777,7 @@ def dot(self, other, squeeze_self=None, squeeze_other=None):
             )
 
         def map_func(df, other=other, squeeze_self=squeeze_self):
+            """Compute matrix multiplication of the passed frames."""
             result = df.squeeze(axis=1).dot(other) if squeeze_self else df.dot(other)
             if is_list_like(result):
                 return pandas.DataFrame(result)
@@ -1848,7 +1804,33 @@ def map_func(df, other=other, squeeze_self=squeeze_self):
         return self.__constructor__(new_modin_frame)
 
     def _nsort(self, n, columns=None, keep="first", sort_type="nsmallest"):
+        """
+        Return first N rows of the data sorted in the specified order.
+
+        Parameters
+        ----------
+        n : int
+            Number of rows to return.
+        columns : list of labels, optional
+            Column labels to sort data by.
+        keep : {"first", "last", "all"}, default: "first"
+            How to pick first rows in case of duplicated values:
+            - "first": prioritize first occurence.
+            - "last": prioritize last occurence.
+            - "all": do not drop any duplicates, even if it means selecting more than `n` rows.
+        sort_type : {"nsmallest", "nlargest"}, default: "nsmallest"
+            "nsmallest" means sort in descending order, "nlargest" means
+            sort in ascending order.
+
+        Returns
+        -------
+        PandasQueryCompiler
+            New QueryCompiler containing the first N rows of the data
+            sorted in the given order.
+        """
+
         def map_func(df, n=n, keep=keep, columns=columns):
+            """Return first `N` rows of the sorted data for a single partition."""
             if columns is None:
                 return pandas.DataFrame(
                     getattr(pandas.Series, sort_type)(
@@ -1876,14 +1858,6 @@ def nlargest(self, *args, **kwargs):
         return self._nsort(sort_type="nlargest", *args, **kwargs)
 
     def eval(self, expr, **kwargs):
-        """Returns a new QueryCompiler with expr evaluated on columns.
-
-        Args:
-            expr: The string expression to evaluate.
-
-        Returns:
-            A new QueryCompiler with new columns after applying expr.
-        """
         # Make a copy of columns and eval on the copy to determine if result type is
         # series or not
         empty_eval = (
@@ -1906,14 +1880,10 @@ def eval(self, expr, **kwargs):
         return self.__constructor__(new_modin_frame)
 
     def mode(self, **kwargs):
-        """Returns a new QueryCompiler with modes calculated for each label along given axis.
-
-        Returns:
-            A new QueryCompiler with modes calculated.
-        """
         axis = kwargs.get("axis", 0)
 
         def mode_builder(df):
+            """Compute modes for a single partition."""
             result = pandas.DataFrame(df.mode(**kwargs))
             # We return a dataframe with the same shape as the input to ensure
             # that all the partitions will be the same shape
@@ -1937,11 +1907,6 @@ def mode_builder(df):
         return self.__constructor__(new_modin_frame).dropna(axis=axis, how="all")
 
     def fillna(self, **kwargs):
-        """Replaces NaN values with the method provided.
-
-        Returns:
-            A new QueryCompiler with null values filled.
-        """
         axis = kwargs.get("axis", 0)
         value = kwargs.get("value")
         method = kwargs.get("method", None)
@@ -1966,11 +1931,6 @@ def fillna(df):
         return self.__constructor__(new_modin_frame)
 
     def quantile_for_list_of_values(self, **kwargs):
-        """Returns Manager containing quantiles along an axis for numeric columns.
-
-        Returns:
-            QueryCompiler containing quantiles of original QueryCompiler along an axis.
-        """
         axis = kwargs.get("axis", 0)
         q = kwargs.get("q")
         numeric_only = kwargs.get("numeric_only", True)
@@ -2018,15 +1978,6 @@ def quantile_builder(df, **kwargs):
         return result.transpose() if axis == 1 else result
 
     def query(self, expr, **kwargs):
-        """Query columns of the QueryCompiler with a boolean expression.
-
-        Args:
-            expr: Boolean expression to query the columns with.
-
-        Returns:
-            QueryCompiler containing the rows where the boolean expression is satisfied.
-        """
-
         def query_builder(df, **kwargs):
             return df.query(expr, inplace=False, **kwargs)
 
@@ -2035,11 +1986,6 @@ def query_builder(df, **kwargs):
         )
 
     def rank(self, **kwargs):
-        """Computes numerical rank along axis. Equal values are set to the average.
-
-        Returns:
-            QueryCompiler containing the ranks of the values along an axis.
-        """
         axis = kwargs.get("axis", 0)
         numeric_only = True if axis else kwargs.get("numeric_only", False)
         new_modin_frame = self._modin_frame._apply_full_axis(
@@ -2052,11 +1998,6 @@ def rank(self, **kwargs):
         return self.__constructor__(new_modin_frame)
 
     def sort_index(self, **kwargs):
-        """Sorts the data with respect to either the columns or the indices.
-
-        Returns:
-            QueryCompiler containing the data sorted by columns or indices.
-        """
         axis = kwargs.pop("axis", 0)
         level = kwargs.pop("level", None)
         sort_remaining = kwargs.pop("sort_remaining", True)
@@ -2112,6 +2053,7 @@ def melt(
             var_name = "variable"
 
         def _convert_to_list(x):
+            """Convert passed object to a list."""
             if is_list_like(x):
                 x = [*x]
             elif x is not None:
@@ -2131,6 +2073,28 @@ def _convert_to_list(x):
             to_broadcast = None
 
         def applyier(df, internal_indices, other=[], internal_other_indices=[]):
+            """
+            Apply `melt` function to a single partition.
+
+            Parameters
+            ----------
+            df : pandas.DataFrame
+                Partition of the self frame.
+            internal_indices : list of ints
+                Positional indices of columns in this particular partition which
+                represents `value_vars` columns in the source frame.
+            other : pandas.DataFrame
+                Broadcasted partition which contains `id_vars` columns of the
+                source frame.
+            internal_other_indices : list of ints
+                Positional indices of columns in `other` partition which
+                represents `id_vars` columns in the source frame.
+
+            Returns
+            -------
+            pandas.DataFrame
+                The result of the `melt` function for this particular partition.
+            """
             if len(other):
                 other = pandas.concat(other, axis=1)
                 columns_to_add = other.columns.difference(df.columns)
@@ -2176,19 +2140,6 @@ def applyier(df, internal_indices, other=[], internal_other_indices=[]):
 
     # __getitem__ methods
     def getitem_array(self, key):
-        """
-        Get column or row data specified by key.
-
-        Parameters
-        ----------
-        key : PandasQueryCompiler, numpy.ndarray, pandas.Index or list
-            Target numeric indices or labels by which to retrieve data.
-
-        Returns
-        -------
-        PandasQueryCompiler
-            A new Query Compiler.
-        """
         # TODO: dont convert to pandas for array indexing
         if isinstance(key, type(self)):
             key = key.to_pandas().squeeze(axis=1)
@@ -2226,16 +2177,6 @@ def getitem_array(self, key):
             return self.getitem_column_array(key)
 
     def getitem_column_array(self, key, numeric=False):
-        """Get column data for target labels.
-
-        Args:
-            key: Target labels by which to retrieve data.
-            numeric: A boolean representing whether or not the key passed in represents
-                the numeric index or the named index.
-
-        Returns:
-            A new QueryCompiler.
-        """
         # Convert to list for type checking
         if numeric:
             new_modin_frame = self._modin_frame.mask(col_numeric_idx=key)
@@ -2244,30 +2185,53 @@ def getitem_column_array(self, key, numeric=False):
         return self.__constructor__(new_modin_frame)
 
     def getitem_row_array(self, key):
-        """Get row data for target labels.
+        return self.__constructor__(self._modin_frame.mask(row_numeric_idx=key))
 
-        Args:
-            key: Target numeric indices by which to retrieve data.
+    def setitem(self, axis, key, value):
+        return self._setitem(axis=axis, key=key, value=value, how=None)
 
-        Returns:
-            A new QueryCompiler.
+    def _setitem(self, axis, key, value, how="inner"):
         """
-        return self.__constructor__(self._modin_frame.mask(row_numeric_idx=key))
+        Set the row/column defined by `key` to the `value` provided.
 
-    def setitem(self, axis, key, value):
-        """Set the column defined by `key` to the `value` provided.
+        In contrast with `setitem` with this function you can specify how
+        to handle non-aligned `self` and `value`.
 
-        Args:
-            key: The column name to set.
-            value: The value to set the column to.
+        Parameters
+        ----------
+        axis : {0, 1}
+            Axis to set `value` along. 0 means set row, 1 means set column.
+        key : label
+            Row/column label to set `value` in.
+        value : PandasQueryCompiler, list-like or scalar
+            Define new row/column value.
+        how : {"inner", "outer", "left", "right", None}, default: "inner"
+            Type of join to perform if specified axis of `self` and `value` are not
+            equal. If `how` is `None`, reindex `value` with `self` labels without joining.
 
-        Returns:
-             A new QueryCompiler
+        Returns
+        -------
+        BaseQueryCompiler
+            New QueryCompiler with updated `key` value.
         """
-        return self._setitem(axis=axis, key=key, value=value, how=None)
 
-    def _setitem(self, axis, key, value, how="inner"):
         def setitem_builder(df, internal_indices=[]):
+            """
+            Set the row/column to the `value` in a single partition.
+
+            Parameters
+            ----------
+            df : pandas.DataFrame
+                Partition of the self frame.
+            internal_indices : list of ints
+                Positional indices of rows/columns in this particular partition
+                which represents `key` in the source frame.
+
+            Returns
+            -------
+            pandas.DataFrame
+                Partition data with updated values.
+            """
             df = df.copy()
             if len(internal_indices) == 1:
                 if axis == 0:
@@ -2315,12 +2279,6 @@ def setitem_builder(df, internal_indices=[]):
     # Drop/Dropna
     # This will change the shape of the resulting data.
     def dropna(self, **kwargs):
-        """Returns a new QueryCompiler with null values dropped along given axis.
-
-        Return:
-            a new QueryCompiler
-        """
-
         return self.__constructor__(
             self._modin_frame.filter_full_axis(
                 kwargs.get("axis", 0) ^ 1,
@@ -2329,15 +2287,6 @@ def dropna(self, **kwargs):
         )
 
     def drop(self, index=None, columns=None):
-        """Remove row data for target index and columns.
-
-        Args:
-            index: Target index to drop.
-            columns: Target columns to drop.
-
-        Returns:
-            A new QueryCompiler.
-        """
         if index is not None:
             # The unique here is to avoid duplicating rows with the same name
             index = np.sort(
@@ -2363,17 +2312,6 @@ def drop(self, index=None, columns=None):
     # return a new one from here and let the front end handle the inplace
     # update.
     def insert(self, loc, column, value):
-        """Insert new column data.
-
-        Args:
-            loc: Insertion index.
-            column: Column labels to insert.
-            value: Dtype object values to insert.
-
-        Returns:
-            A new PandasQueryCompiler with new data inserted.
-        """
-
         if isinstance(value, type(self)):
             value.columns = [column]
             return self.insert_item(axis=1, loc=loc, value=value, how=None)
@@ -2384,6 +2322,17 @@ def insert(self, loc, column, value):
             value = [value] * len(self.index)
 
         def insert(df, internal_indices=[]):
+            """
+            Insert new column to the partition.
+
+            Parameters
+            ----------
+            df : pandas.DataFrame
+                Partition of the self frame.
+            internal_indices : list of ints
+                Positional index of the column in this particular partition
+                to insert new column after.
+            """
             internal_idx = int(internal_indices[0])
             df.insert(internal_idx, column, value)
             return df
@@ -2406,15 +2355,6 @@ def insert(df, internal_indices=[]):
     # There is a wide range of behaviors that are supported, so a lot of the
     # logic can get a bit convoluted.
     def apply(self, func, axis, *args, **kwargs):
-        """Apply func across given axis.
-
-        Args:
-            func: The function to apply.
-            axis: Target axis to apply the function along.
-
-        Returns:
-            A new PandasQueryCompiler.
-        """
         # if any of args contain modin object, we should
         # convert it to pandas
         args = try_cast_to_pandas(args)
@@ -2430,15 +2370,29 @@ def apply(self, func, axis, *args, **kwargs):
         else:
             pass
 
+    # FIXME: `_apply_text_func_elementwise` duplicates most of the logic of `_callable_func`,
+    # these methods should be combined.
     def _apply_text_func_elementwise(self, func, axis, *args, **kwargs):
-        """Apply func passed as str across given axis in elementwise manner.
+        """
+        Apply passed string function to each row/column.
 
-        Args:
-            func: The function to apply.
-            axis: Target axis to apply the function along.
+        Parameters
+        ----------
+        func : str
+            Function name to apply.
+        axis : {0, 1}
+            Target axis to apply function along. 0 means apply to columns,
+            1 means apply to rows.
+        *args : args
+            Arguments to pass to the specified function.
+        **kwargs : kwargs
+            Arguments to pass to the specified function.
 
-        Returns:
-            A new PandasQueryCompiler.
+        Returns
+        -------
+        PandasQueryCompiler
+            New QueryCompiler containing the results of passed function
+            for each row/column.
         """
         assert isinstance(func, str)
         kwargs["axis"] = axis
@@ -2448,14 +2402,25 @@ def _apply_text_func_elementwise(self, func, axis, *args, **kwargs):
         return self.__constructor__(new_modin_frame)
 
     def _dict_func(self, func, axis, *args, **kwargs):
-        """Apply function to certain indices across given axis.
+        """
+        Apply passed functions to the specified rows/columns.
 
-        Args:
-            func: The function to apply.
-            axis: Target axis to apply the function along.
+        Parameters
+        ----------
+        func : dict(label) -> [callable, str]
+            Dictionary that maps axis labels to the function to apply against them.
+        axis : {0, 1}
+            Target axis to apply functions along. 0 means apply to columns,
+            1 means apply to rows.
+        *args : args
+            Arguments to pass to the specified functions.
+        **kwargs : kwargs
+            Arguments to pass to the specified functions.
 
-        Returns:
-            A new PandasQueryCompiler.
+        Returns
+        -------
+        PandasQueryCompiler
+            New QueryCompiler containing the results of passed functions.
         """
         if "axis" not in kwargs:
             kwargs["axis"] = axis
@@ -2474,19 +2439,24 @@ def dict_apply_builder(df, func_dict={}):
 
     def _list_like_func(self, func, axis, *args, **kwargs):
         """
-        Apply list-like function across given axis.
+        Apply passed functions to each row/column.
 
         Parameters
         ----------
-            func : list-like
-                The function to apply.
-            axis : 0 or 1 (0 - index, 1 - columns)
-                Target axis to apply the function along.
+        func : list of callable
+            List of functions to apply against each row/column.
+        axis : {0, 1}
+            Target axis to apply functions along. 0 means apply to columns,
+            1 means apply to rows.
+        *args : args
+            Arguments to pass to the specified functions.
+        **kwargs : kwargs
+            Arguments to pass to the specified functions.
 
         Returns
         -------
         PandasQueryCompiler
-            A new QueryCompiler.
+            New QueryCompiler containing the results of passed functions.
         """
         # When the function is list-like, the function names become the index/columns
         new_index = (
@@ -2509,14 +2479,26 @@ def _list_like_func(self, func, axis, *args, **kwargs):
         return self.__constructor__(new_modin_frame)
 
     def _callable_func(self, func, axis, *args, **kwargs):
-        """Apply callable functions across given axis.
+        """
+        Apply passed function to each row/column.
 
-        Args:
-            func: The functions to apply.
-            axis: Target axis to apply the function along.
+        Parameters
+        ----------
+        func : callable
+            Function to apply.
+        axis : {0, 1}
+            Target axis to apply function along. 0 means apply to columns,
+            1 means apply to rows.
+        *args : args
+            Arguments to pass to the specified function.
+        **kwargs : kwargs
+            Arguments to pass to the specified function.
 
-        Returns:
-            A new PandasQueryCompiler.
+        Returns
+        -------
+        PandasQueryCompiler
+            New QueryCompiler containing the results of passed function
+            for each row/column.
         """
         func = wrap_udf_function(func)
         new_modin_frame = self._modin_frame._apply_full_axis(
@@ -2573,6 +2555,41 @@ def _groupby_dict_reduce(
         drop=False,
         **kwargs,
     ):
+        """
+        Group underlying data and apply aggregation functions to each group of the specified column/row.
+
+        This method is responsible of performing dictionary groupby aggregation for such functions,
+        that can be implemented via MapReduce approach.
+
+        Parameters
+        ----------
+        by : PandasQueryCompiler, column or index label, Grouper or list of such
+            Object that determine groups.
+        axis : {0, 1}
+            Axis to group and apply aggregation function along.
+            0 is for index, when 1 is for columns.
+        agg_func : dict(label) -> str
+            Dictionary that maps row/column labels to the function names.
+            **Note:** specified functions have to be supported by ``modin.data_management.functions.GroupbyReduceFunction``.
+            Supported functions are listed in the ``modin.data_management.functions.GroupbyReduceFunction.groupby_reduce_functions``
+            dictionary.
+        agg_args : list
+            Serves the compatibility purpose. Does not affect the result.
+        agg_kwargs : dict
+            Arguments to pass to the aggregation functions.
+        groupby_kwargs : dict
+            GroupBy parameters in the format of ``modin.pandas.DataFrame.groupby`` signature.
+        drop : bool, default: False
+            If `by` is a QueryCompiler indicates whether or not by-data came
+            from the `self`.
+        **kwargs : dict
+            Additional parameters to pass to the ``modin.data_management.functions.GroupbyReduceFunction.register``.
+
+        Returns
+        -------
+        PandasQueryCompiler
+            New QueryCompiler containing the result of groupby dictionary aggregation.
+        """
         map_dict = {}
         reduce_dict = {}
         rename_columns = any(
@@ -2627,6 +2644,7 @@ def groupby_agg(
         drop=False,
     ):
         def is_reduce_fn(fn, deep_level=0):
+            """Check whether all functions which is defined by `fn` can be implemented via MapReduce approach."""
             if not isinstance(fn, str) and isinstance(fn, Container):
                 # `deep_level` parameter specifies the number of nested containers that was met:
                 # - if it's 0, then we're outside of container, `fn` could be either function name
@@ -2685,6 +2703,26 @@ def is_reduce_fn(fn, deep_level=0):
         not_broadcastable_by = [o for o in by if not isinstance(o, type(self))]
 
         def groupby_agg_builder(df, by=None, drop=False, partition_idx=None):
+            """
+            Compute groupby aggregation for a single partition.
+
+            Parameters
+            ----------
+            df : pandas.DataFrame
+                Partition of the self frame.
+            by : pandas.DataFrame, optional
+                Broadcasted partition which contains `by` columns.
+            drop : bool, default: False
+                Indicates whether `by` partition came from the `self` frame.
+            partition_idx : int, optional
+                Positional partition index along groupby axis.
+
+            Returns
+            -------
+            pandas.DataFrame
+                DataFrame containing the result of groupby aggregation
+                for this particular partition.
+            """
             # Set `as_index` to True to track the metadata of the grouping object
             # It is used to make sure that between phases we are constructing the
             # right index and placing columns in the correct order.
@@ -2722,6 +2760,7 @@ def groupby_agg_builder(df, by=None, drop=False, partition_idx=None):
             by += not_broadcastable_by
 
             def compute_groupby(df, drop=False, partition_idx=0):
+                """Compute groupby aggregation for a single partition."""
                 grouped_df = df.groupby(by=by, axis=axis, **groupby_kwargs)
                 try:
                     if isinstance(agg_func, dict):
@@ -2856,6 +2895,7 @@ def pivot(self, index, columns, values):
         from pandas.core.reshape.pivot import _convert_by
 
         def __convert_by(by):
+            """Convert passed value to a list."""
             if isinstance(by, pandas.Index):
                 by = list(by)
             by = _convert_by(by)
@@ -2921,6 +2961,7 @@ def pivot_table(
         from pandas.core.reshape.pivot import _convert_by
 
         def __convert_by(by):
+            """Convert passed value to a list."""
             if isinstance(by, pandas.Index):
                 return list(by)
             return _convert_by(by)
@@ -2938,6 +2979,22 @@ def __convert_by(by):
         keys_columns = self.getitem_column_array(unique_keys)
 
         def applyier(df, other):
+            """
+            Build pivot table for a single partition.
+
+            Parameters
+            ----------
+            df : pandas.DataFrame
+                Partition of the self frame.
+            other : pandas.DataFrame
+                Broadcasted partition that contains `value` columns
+                of the self frame.
+
+            Returns
+            -------
+            pandas.DataFrame
+                Pivot table for this particular partition.
+            """
             concated = pandas.concat([df, other], axis=1, copy=False)
             result = concated.pivot_table(
                 index=index,
@@ -2981,14 +3038,6 @@ def applyier(df, other):
 
     # Get_dummies
     def get_dummies(self, columns, **kwargs):
-        """Convert categorical variables to dummy variables for certain columns.
-
-        Args:
-            columns: The columns to convert.
-
-        Returns:
-            A new QueryCompiler.
-        """
         # `columns` as None does not mean all columns, by default it means only
         # non-numeric columns.
         if columns is None:
@@ -3034,6 +3083,27 @@ def view(self, index=None, columns=None):
 
     def write_items(self, row_numeric_index, col_numeric_index, broadcasted_items):
         def iloc_mut(partition, row_internal_indices, col_internal_indices, item):
+            """
+            Write `value` in a specified location in a single partition.
+
+            Parameters
+            ----------
+            partition : pandas.DataFrame
+                Partition of the self frame.
+            row_internal_indices : list of ints
+                Positional indices of rows in this particular partition
+                to write `item` to.
+            col_internal_indices : list of ints
+                Positional indices of columns in this particular partition
+                to write `item` to.
+            item : 2D-array
+                Value to write.
+
+            Returns
+            -------
+            pandas.DataFrame
+                Partition data with updated values.
+            """
             partition = partition.copy()
             partition.iloc[row_internal_indices, col_internal_indices] = item
             return partition
@@ -3051,20 +3121,6 @@ def iloc_mut(partition, row_internal_indices, col_internal_indices, item):
         return self.__constructor__(new_modin_frame)
 
     def sort_rows_by_column_values(self, columns, ascending=True, **kwargs):
-        """Reorder the rows based on the lexicographic order of the given columns.
-
-        Parameters
-        ----------
-        columns : scalar or list of scalar
-            The column or columns to sort by
-        ascending : bool
-            Sort in ascending order (True) or descending order (False)
-
-        Returns
-        -------
-        PandasQueryCompiler
-            A new query compiler that contains result of the sort
-        """
         ignore_index = kwargs.get("ignore_index", False)
         kwargs["ignore_index"] = False
         if not is_list_like(columns):
@@ -3103,20 +3159,6 @@ def sort_rows_by_column_values(self, columns, ascending=True, **kwargs):
         return result
 
     def sort_columns_by_row_values(self, rows, ascending=True, **kwargs):
-        """Reorder the columns based on the lexicographic order of the given rows.
-
-        Parameters
-        ----------
-        rows : scalar or list of scalar
-            The row or rows to sort by
-        ascending : bool
-            Sort in ascending order (True) or descending order (False)
-
-        Returns
-        -------
-        PandasQueryCompiler
-            A new query compiler that contains result of the sort
-        """
         if not is_list_like(rows):
             rows = [rows]
         ErrorMessage.default_to_pandas("sort_values")


Test patch: