Repository: modin-project/modin

Issue:
REFACTOR: Support rolling.{rank,quantile,sem}
- https://github.com/ponder-org/modin-public/commit/e70ad4c783d66b42b1709966dc3d73c9d25088e7
- https://github.com/ponder-org/modin-public/commit/3c10b00db493aceb5f9e57572530f1777ce01018



Discussion:

Resolving patch:
diff --git a/modin/core/storage_formats/base/query_compiler.py b/modin/core/storage_formats/base/query_compiler.py
--- a/modin/core/storage_formats/base/query_compiler.py
+++ b/modin/core/storage_formats/base/query_compiler.py
@@ -5054,6 +5054,19 @@ def rolling_sum(self, fold_axis, rolling_args, *args, **kwargs):
             self, rolling_args, *args, **kwargs
         )
 
+    @doc_utils.doc_window_method(
+        window_cls_name="Rolling",
+        result="sem",
+        refer_to="sem",
+        params="""
+        *args : iterable
+        **kwargs : dict""",
+    )
+    def rolling_sem(self, fold_axis, rolling_args, *args, **kwargs):
+        return RollingDefault.register(pandas.core.window.rolling.Rolling.sem)(
+            self, rolling_args, *args, **kwargs
+        )
+
     @doc_utils.doc_window_method(
         window_cls_name="Rolling",
         result="variance",
@@ -5068,6 +5081,40 @@ def rolling_var(self, fold_axis, rolling_args, ddof=1, *args, **kwargs):
             self, rolling_args, ddof, *args, **kwargs
         )
 
+    @doc_utils.doc_window_method(
+        window_cls_name="Rolling",
+        result="rank",
+        refer_to="rank",
+        params="""
+        method : {'average', 'min', 'max'}, default: 'average'
+        ascending : bool, default: True
+        pct : bool, default: False
+        numeric_only : bool, default: False
+        *args : iterable
+        **kwargs : dict""",
+    )
+    def rolling_rank(
+        self,
+        fold_axis,
+        rolling_args,
+        method="average",
+        ascending=True,
+        pct=False,
+        numeric_only=False,
+        *args,
+        **kwargs,
+    ):
+        return RollingDefault.register(pandas.core.window.rolling.Rolling.rank)(
+            self,
+            rolling_args,
+            method=method,
+            ascending=ascending,
+            pct=pct,
+            numeric_only=numeric_only,
+            *args,
+            **kwargs,
+        )
+
     # End of Rolling methods
 
     # Begin Expanding methods
@@ -5190,6 +5237,23 @@ def expanding_count(self, fold_axis, expanding_args, ddof=1, *args, **kwargs):
             self, expanding_args, *args, **kwargs
         )
 
+    @doc_utils.doc_window_method(
+        window_cls_name="Expanding",
+        result="quantile",
+        refer_to="quantile",
+        win_type="expanding window",
+        params="""
+        quantile : float
+        interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'}, default: 'linear'
+        **kwargs : dict""",
+    )
+    def expanding_quantile(
+        self, fold_axis, expanding_args, quantile, interpolation, **kwargs
+    ):
+        return ExpandingDefault.register(pandas.core.window.rolling.Expanding.quantile)(
+            self, expanding_args, quantile, interpolation, **kwargs
+        )
+
     @doc_utils.doc_window_method(
         window_cls_name="Expanding",
         result="unbiased standard error mean",
@@ -5208,6 +5272,41 @@ def expanding_sem(
             self, expanding_args, ddof=ddof, numeric_only=numeric_only, *args, **kwargs
         )
 
+    @doc_utils.doc_window_method(
+        window_cls_name="Expanding",
+        result="rank",
+        refer_to="rank",
+        win_type="expanding window",
+        params="""
+        method : {'average', 'min', 'max'}, default: 'average'
+        ascending : bool, default: True
+        pct : bool, default: False
+        numeric_only : bool, default: False
+        *args : iterable
+        **kwargs : dict""",
+    )
+    def expanding_rank(
+        self,
+        fold_axis,
+        expanding_args,
+        method="average",
+        ascending=True,
+        pct=False,
+        numeric_only=False,
+        *args,
+        **kwargs,
+    ):
+        return ExpandingDefault.register(pandas.core.window.rolling.Expanding.rank)(
+            self,
+            expanding_args,
+            method=method,
+            ascending=ascending,
+            pct=pct,
+            numeric_only=numeric_only,
+            *args,
+            **kwargs,
+        )
+
     # End of Expanding methods
 
     # Window methods
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
@@ -1213,12 +1213,24 @@ def expanding_aggregate(self, axis, expanding_args, func, *args, **kwargs):
         )
     )
 
+    expanding_quantile = Fold.register(
+        lambda df, expanding_args, *args, **kwargs: pandas.DataFrame(
+            df.expanding(*expanding_args).quantile(*args, **kwargs)
+        )
+    )
+
     expanding_sem = Fold.register(
         lambda df, expanding_args, *args, **kwargs: pandas.DataFrame(
             df.expanding(*expanding_args).sem(*args, **kwargs)
         )
     )
 
+    expanding_rank = Fold.register(
+        lambda df, expanding_args, *args, **kwargs: pandas.DataFrame(
+            df.expanding(*expanding_args).rank(*args, **kwargs)
+        )
+    )
+
     window_mean = Fold.register(
         lambda df, rolling_args, *args, **kwargs: pandas.DataFrame(
             df.rolling(*rolling_args).mean(*args, **kwargs)
@@ -1247,6 +1259,11 @@ def expanding_aggregate(self, axis, expanding_args, func, *args, **kwargs):
             df.rolling(*rolling_args).sum(*args, **kwargs)
         )
     )
+    rolling_sem = Fold.register(
+        lambda df, rolling_args, *args, **kwargs: pandas.DataFrame(
+            df.rolling(*rolling_args).sem(*args, **kwargs)
+        )
+    )
     rolling_mean = Fold.register(
         lambda df, rolling_args, *args, **kwargs: pandas.DataFrame(
             df.rolling(*rolling_args).mean(*args, **kwargs)
@@ -1306,6 +1323,17 @@ def expanding_aggregate(self, axis, expanding_args, func, *args, **kwargs):
             )
         )
     )
+    rolling_rank = Fold.register(
+        lambda df, rolling_args, method, ascending, pct, numeric_only, **kwargs: pandas.DataFrame(
+            df.rolling(*rolling_args).rank(
+                method=method,
+                ascending=ascending,
+                pct=pct,
+                numeric_only=numeric_only,
+                **kwargs,
+            )
+        )
+    )
 
     def rolling_corr(self, axis, rolling_args, other, pairwise, *args, **kwargs):
         if len(self.columns) > 1:
diff --git a/modin/pandas/window.py b/modin/pandas/window.py
--- a/modin/pandas/window.py
+++ b/modin/pandas/window.py
@@ -123,6 +123,13 @@ def count(self):
             )
         )
 
+    def sem(self, *args, **kwargs):
+        return self._dataframe.__constructor__(
+            query_compiler=self._query_compiler.rolling_sem(
+                self.axis, self.rolling_args, *args, **kwargs
+            )
+        )
+
     def sum(self, *args, **kwargs):
         return self._dataframe.__constructor__(
             query_compiler=self._query_compiler.rolling_sum(
@@ -273,6 +280,21 @@ def quantile(self, quantile, interpolation="linear", **kwargs):
             )
         )
 
+    def rank(
+        self, method="average", ascending=True, pct=False, numeric_only=False, **kwargs
+    ):
+        return self._dataframe.__constructor__(
+            query_compiler=self._query_compiler.rolling_rank(
+                self.axis,
+                self.rolling_args,
+                method,
+                ascending,
+                pct,
+                numeric_only,
+                **kwargs,
+            )
+        )
+
 
 @_inherit_docstrings(
     pandas.core.window.expanding.Expanding,


Test patch:
diff --git a/modin/pandas/test/test_expanding.py b/modin/pandas/test/test_expanding.py
--- a/modin/pandas/test/test_expanding.py
+++ b/modin/pandas/test/test_expanding.py
@@ -51,6 +51,9 @@ def create_test_series(vals):
         ("std", {"ddof": 0}),
         ("min", {}),
         ("max", {}),
+        ("rank", {}),
+        ("sem", {"ddof": 0}),
+        ("quantile", {"q": 0.1}),
     ],
 )
 def test_dataframe(data, min_periods, axis, method, kwargs):
@@ -97,6 +100,9 @@ def test_dataframe_agg(data, min_periods):
         ("std", {"ddof": 0}),
         ("min", {}),
         ("max", {}),
+        ("rank", {}),
+        ("sem", {"ddof": 0}),
+        ("quantile", {"q": 0.1}),
     ],
 )
 def test_series(data, min_periods, method, kwargs):
diff --git a/modin/pandas/test/test_rolling.py b/modin/pandas/test/test_rolling.py
--- a/modin/pandas/test/test_rolling.py
+++ b/modin/pandas/test/test_rolling.py
@@ -20,6 +20,7 @@
     df_equals,
     test_data_values,
     test_data_keys,
+    eval_general,
     create_test_dfs,
     default_to_pandas_ignore_string,
 )
@@ -48,56 +49,104 @@ def create_test_series(vals):
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
 @pytest.mark.parametrize("window", [5, 100])
 @pytest.mark.parametrize("min_periods", [None, 5])
-@pytest.mark.parametrize("win_type", [None, "triang"])
 @pytest.mark.parametrize("axis", [0, 1])
-def test_dataframe(data, window, min_periods, win_type, axis):
-    modin_df = pd.DataFrame(data)
-    pandas_df = pandas.DataFrame(data)
+@pytest.mark.parametrize(
+    "method, kwargs",
+    [
+        ("count", {}),
+        ("sum", {}),
+        ("mean", {}),
+        ("var", {"ddof": 0}),
+        ("std", {"ddof": 0}),
+        ("min", {}),
+        ("max", {}),
+        ("skew", {}),
+        ("kurt", {}),
+        ("apply", {"func": np.sum}),
+        ("rank", {}),
+        ("sem", {"ddof": 0}),
+        ("quantile", {"q": 0.1}),
+        ("median", {}),
+    ],
+)
+def test_dataframe_rolling(data, window, min_periods, axis, method, kwargs):
+    # Testing of Rolling class
+    modin_df, pandas_df = create_test_dfs(data)
     if window > len(pandas_df):
         window = len(pandas_df)
-    pandas_rolled = pandas_df.rolling(
-        window=window,
-        min_periods=min_periods,
-        win_type=win_type,
-        center=True,
-        axis=axis,
+    eval_general(
+        modin_df,
+        pandas_df,
+        lambda df: getattr(
+            df.rolling(
+                window=window,
+                min_periods=min_periods,
+                win_type=None,
+                center=True,
+                axis=axis,
+            ),
+            method,
+        )(**kwargs),
     )
+
+
+@pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
+@pytest.mark.parametrize("window", [5, 100])
+@pytest.mark.parametrize("min_periods", [None, 5])
+@pytest.mark.parametrize("axis", [0, 1])
+def test_dataframe_agg(data, window, min_periods, axis):
+    modin_df, pandas_df = create_test_dfs(data)
+    if window > len(pandas_df):
+        window = len(pandas_df)
     modin_rolled = modin_df.rolling(
-        window=window,
-        min_periods=min_periods,
-        win_type=win_type,
-        center=True,
-        axis=axis,
+        window=window, min_periods=min_periods, win_type=None, center=True, axis=axis
+    )
+    pandas_rolled = pandas_df.rolling(
+        window=window, min_periods=min_periods, win_type=None, center=True, axis=axis
     )
+    df_equals(pandas_rolled.aggregate(np.sum), modin_rolled.aggregate(np.sum))
+    # TODO(https://github.com/modin-project/modin/issues/4260): Once pandas
+    # allows us to rolling aggregate a list of functions over axis 1, test
+    # that, too.
+    if axis != 1:
+        df_equals(
+            pandas_rolled.aggregate([np.sum, np.mean]),
+            modin_rolled.aggregate([np.sum, np.mean]),
+        )
+
+
+@pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
+@pytest.mark.parametrize("window", [5, 100])
+@pytest.mark.parametrize("min_periods", [None, 5])
+@pytest.mark.parametrize("axis", [0, 1])
+@pytest.mark.parametrize(
+    "method, kwargs",
+    [
+        ("sum", {}),
+        ("mean", {}),
+        ("var", {"ddof": 0}),
+        ("std", {"ddof": 0}),
+    ],
+)
+def test_dataframe_window(data, window, min_periods, axis, method, kwargs):
     # Testing of Window class
-    if win_type is not None:
-        df_equals(pandas_rolled.mean(), modin_rolled.mean())
-        df_equals(modin_rolled.sum(), pandas_rolled.sum())
-        df_equals(modin_rolled.var(ddof=0), pandas_rolled.var(ddof=0))
-        df_equals(modin_rolled.std(ddof=0), pandas_rolled.std(ddof=0))
-    # Testing of Rolling class
-    else:
-        df_equals(modin_rolled.count(), pandas_rolled.count())
-        df_equals(modin_rolled.sum(), pandas_rolled.sum())
-        df_equals(modin_rolled.mean(), pandas_rolled.mean())
-        df_equals(modin_rolled.median(), pandas_rolled.median())
-        df_equals(modin_rolled.var(ddof=0), pandas_rolled.var(ddof=0))
-        df_equals(modin_rolled.std(ddof=0), pandas_rolled.std(ddof=0))
-        df_equals(modin_rolled.min(), pandas_rolled.min())
-        df_equals(modin_rolled.max(), pandas_rolled.max())
-        df_equals(modin_rolled.skew(), pandas_rolled.skew())
-        df_equals(modin_rolled.kurt(), pandas_rolled.kurt())
-        df_equals(modin_rolled.apply(np.sum), pandas_rolled.apply(np.sum))
-        df_equals(modin_rolled.aggregate(np.sum), pandas_rolled.aggregate(np.sum))
-        # TODO(https://github.com/modin-project/modin/issues/4260): Once pandas
-        # allows us to rolling aggregate a list of functions over axis 1, test
-        # that, too.
-        if axis != 1:
-            df_equals(
-                pandas_rolled.aggregate([np.sum, np.mean]),
-                modin_rolled.aggregate([np.sum, np.mean]),
-            )
-        df_equals(modin_rolled.quantile(0.1), pandas_rolled.quantile(0.1))
+    modin_df, pandas_df = create_test_dfs(data)
+    if window > len(pandas_df):
+        window = len(pandas_df)
+    eval_general(
+        modin_df,
+        pandas_df,
+        lambda df: getattr(
+            df.rolling(
+                window=window,
+                min_periods=min_periods,
+                win_type="triang",
+                center=True,
+                axis=axis,
+            ),
+            method,
+        )(**kwargs),
+    )
 
 
 @pytest.mark.parametrize("axis", [0, "columns"])
@@ -154,59 +203,99 @@ def test_dataframe_dt_index(axis, on, closed, window):
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
 @pytest.mark.parametrize("window", [5, 100])
 @pytest.mark.parametrize("min_periods", [None, 5])
-@pytest.mark.parametrize("win_type", [None, "triang"])
-def test_series(data, window, min_periods, win_type):
+@pytest.mark.parametrize(
+    "method, kwargs",
+    [
+        ("count", {}),
+        ("sum", {}),
+        ("mean", {}),
+        ("var", {"ddof": 0}),
+        ("std", {"ddof": 0}),
+        ("min", {}),
+        ("max", {}),
+        ("skew", {}),
+        ("kurt", {}),
+        ("apply", {"func": np.sum}),
+        ("rank", {}),
+        ("sem", {"ddof": 0}),
+        ("aggregate", {"func": np.sum}),
+        ("agg", {"func": [np.sum, np.mean]}),
+        ("quantile", {"q": 0.1}),
+        ("median", {}),
+    ],
+)
+def test_series_rolling(data, window, min_periods, method, kwargs):
+    # Test of Rolling class
     modin_series, pandas_series = create_test_series(data)
     if window > len(pandas_series):
         window = len(pandas_series)
-    pandas_rolled = pandas_series.rolling(
-        window=window,
-        min_periods=min_periods,
-        win_type=win_type,
-        center=True,
+    eval_general(
+        modin_series,
+        pandas_series,
+        lambda series: getattr(
+            series.rolling(
+                window=window,
+                min_periods=min_periods,
+                win_type=None,
+                center=True,
+            ),
+            method,
+        )(**kwargs),
     )
+
+
+@pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
+@pytest.mark.parametrize("window", [5, 100])
+@pytest.mark.parametrize("min_periods", [None, 5])
+def test_series_corr_cov(data, window, min_periods):
+    modin_series, pandas_series = create_test_series(data)
+    if window > len(pandas_series):
+        window = len(pandas_series)
     modin_rolled = modin_series.rolling(
-        window=window,
-        min_periods=min_periods,
-        win_type=win_type,
-        center=True,
+        window=window, min_periods=min_periods, win_type=None, center=True
+    )
+    pandas_rolled = pandas_series.rolling(
+        window=window, min_periods=min_periods, win_type=None, center=True
+    )
+    df_equals(modin_rolled.corr(modin_series), pandas_rolled.corr(pandas_series))
+    df_equals(
+        modin_rolled.cov(modin_series, True), pandas_rolled.cov(pandas_series, True)
+    )
+    df_equals(
+        modin_rolled.cov(modin_series, False), pandas_rolled.cov(pandas_series, False)
+    )
+
+
+@pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
+@pytest.mark.parametrize("window", [5, 100])
+@pytest.mark.parametrize("min_periods", [None, 5])
+@pytest.mark.parametrize(
+    "method, kwargs",
+    [
+        ("sum", {}),
+        ("mean", {}),
+        ("var", {"ddof": 0}),
+        ("std", {"ddof": 0}),
+    ],
+)
+def test_series_window(data, window, min_periods, method, kwargs):
+    # Test of Window class
+    modin_series, pandas_series = create_test_series(data)
+    if window > len(pandas_series):
+        window = len(pandas_series)
+    eval_general(
+        modin_series,
+        pandas_series,
+        lambda series: getattr(
+            series.rolling(
+                window=window,
+                min_periods=min_periods,
+                win_type="triang",
+                center=True,
+            ),
+            method,
+        )(**kwargs),
     )
-    # Testing of Window class
-    if win_type is not None:
-        df_equals(modin_rolled.mean(), pandas_rolled.mean())
-        df_equals(modin_rolled.sum(), pandas_rolled.sum())
-        df_equals(modin_rolled.var(ddof=0), pandas_rolled.var(ddof=0))
-        df_equals(modin_rolled.std(ddof=0), pandas_rolled.std(ddof=0))
-    # Testing of Rolling class
-    else:
-        df_equals(modin_rolled.count(), pandas_rolled.count())
-        df_equals(modin_rolled.sum(), pandas_rolled.sum())
-        df_equals(modin_rolled.mean(), pandas_rolled.mean())
-        df_equals(modin_rolled.median(), pandas_rolled.median())
-        df_equals(modin_rolled.var(ddof=0), pandas_rolled.var(ddof=0))
-        df_equals(modin_rolled.std(ddof=0), pandas_rolled.std(ddof=0))
-        df_equals(modin_rolled.min(), pandas_rolled.min())
-        df_equals(modin_rolled.max(), pandas_rolled.max())
-        df_equals(
-            modin_rolled.corr(modin_series),
-            pandas_rolled.corr(pandas_series),
-        )
-        df_equals(
-            modin_rolled.cov(modin_series, True), pandas_rolled.cov(pandas_series, True)
-        )
-        df_equals(
-            modin_rolled.cov(modin_series, False),
-            pandas_rolled.cov(pandas_series, False),
-        )
-        df_equals(modin_rolled.skew(), pandas_rolled.skew())
-        df_equals(modin_rolled.kurt(), pandas_rolled.kurt())
-        df_equals(modin_rolled.apply(np.sum), pandas_rolled.apply(np.sum))
-        df_equals(modin_rolled.aggregate(np.sum), pandas_rolled.aggregate(np.sum))
-        df_equals(
-            modin_rolled.agg([np.sum, np.mean]),
-            pandas_rolled.agg([np.sum, np.mean]),
-        )
-        df_equals(modin_rolled.quantile(0.1), pandas_rolled.quantile(0.1))
 
 
 @pytest.mark.parametrize("closed", ["both", "right"])