Repository: modin-project/modin

Issue:
kurt function implementation



Discussion:

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
@@ -355,6 +355,7 @@ def transpose(self, *args, **kwargs):
     nsmallest = ReductionFunction.register(pandas.DataFrame.nsmallest)
     nlargest = ReductionFunction.register(pandas.DataFrame.nlargest)
     skew = ReductionFunction.register(pandas.DataFrame.skew)
+    kurt = ReductionFunction.register(pandas.DataFrame.kurt)
     std = ReductionFunction.register(pandas.DataFrame.std)
     var = ReductionFunction.register(pandas.DataFrame.var)
     sum_min_count = ReductionFunction.register(pandas.DataFrame.sum)
diff --git a/modin/pandas/base.py b/modin/pandas/base.py
--- a/modin/pandas/base.py
+++ b/modin/pandas/base.py
@@ -1459,25 +1459,45 @@ def iloc(self):
         return _iLocIndexer(self)
 
     def kurt(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs):
-        return self._default_to_pandas(
-            "kurt",
-            axis=axis,
-            skipna=skipna,
-            level=level,
-            numeric_only=numeric_only,
-            **kwargs
-        )
+        """Return unbiased kurtosis over requested axis. Normalized by N-1
 
-    def kurtosis(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs):
-        return self._default_to_pandas(
-            "kurtosis",
-            axis=axis,
-            skipna=skipna,
-            level=level,
-            numeric_only=numeric_only,
-            **kwargs
+        Kurtosis obtained using Fisher’s definition of kurtosis (kurtosis of normal == 0.0).
+
+        Args:
+            axis : {index (0), columns (1)}
+            skipna : boolean, default True
+                Exclude NA/null values when computing the result.
+            level : int or level name, default None
+            numeric_only : boolean, default None
+
+        Returns:
+            kurtosis : Series or DataFrame (if level specified)
+        """
+        if level is not None:
+            return self._default_to_pandas(
+                "kurt",
+                axis=axis,
+                skipna=skipna,
+                level=level,
+                numeric_only=numeric_only,
+                **kwargs
+            )
+
+        axis = self._get_axis_number(axis)
+        if numeric_only:
+            self._validate_dtypes(numeric_only=True)
+        return self._reduce_dimension(
+            self._query_compiler.kurt(
+                axis=axis,
+                skipna=skipna,
+                level=level,
+                numeric_only=numeric_only,
+                **kwargs
+            )
         )
 
+    kurtosis = kurt
+
     def last(self, offset):
         return self.loc[pandas.Series(index=self.index).last(offset).index]
 


Test patch:
diff --git a/modin/pandas/test/test_dataframe.py b/modin/pandas/test/test_dataframe.py
--- a/modin/pandas/test/test_dataframe.py
+++ b/modin/pandas/test/test_dataframe.py
@@ -2390,15 +2390,26 @@ def test_interpolate(self):
         with pytest.warns(UserWarning):
             pd.DataFrame(data).interpolate()
 
-    def test_kurt(self):
-        data = test_data_values[0]
-        with pytest.warns(UserWarning):
-            pd.DataFrame(data).kurt()
-
-    def test_kurtosis(self):
+    @pytest.mark.parametrize("axis", axis_values, ids=axis_keys)
+    @pytest.mark.parametrize("skipna", bool_arg_values, ids=bool_arg_keys)
+    @pytest.mark.parametrize("level", [None, -1, 0, 1])
+    @pytest.mark.parametrize("numeric_only", bool_arg_values, ids=bool_arg_keys)
+    @pytest.mark.parametrize("method", ["kurtosis", "kurt"])
+    def test_kurt_kurtosis(self, axis, skipna, level, numeric_only, method):
         data = test_data_values[0]
-        with pytest.warns(UserWarning):
-            pd.DataFrame(data).kurtosis()
+        modin_df, pandas_df = pd.DataFrame(data), pandas.DataFrame(data)
+        try:
+            pandas_result = getattr(pandas_df, method)(
+                axis, skipna, level, numeric_only
+            )
+        except Exception as e:
+            with pytest.raises(type(e)):
+                repr(
+                    getattr(modin_df, method)(axis, skipna, level, numeric_only)
+                )  # repr to force materialization
+        else:
+            modin_result = getattr(modin_df, method)(axis, skipna, level, numeric_only)
+            df_equals(modin_result, pandas_result)
 
     def test_last(self):
         modin_index = pd.date_range("2010-04-09", periods=400, freq="2D")
diff --git a/modin/pandas/test/test_series.py b/modin/pandas/test/test_series.py
--- a/modin/pandas/test/test_series.py
+++ b/modin/pandas/test/test_series.py
@@ -45,6 +45,8 @@
     numeric_agg_funcs,
     quantiles_keys,
     quantiles_values,
+    axis_keys,
+    axis_values,
     bool_arg_keys,
     bool_arg_values,
     int_arg_keys,
@@ -1663,17 +1665,37 @@ def test_keys(data):
 
 
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
-def test_kurt(data):
-    modin_series, pandas_series = create_test_series(data)
-    with pytest.warns(UserWarning):
-        modin_series.kurt()
-
-
-@pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
-def test_kurtosis(data):
+@pytest.mark.parametrize("axis", axis_values, ids=axis_keys)
+@pytest.mark.parametrize("skipna", bool_arg_values, ids=bool_arg_keys)
+@pytest.mark.parametrize("level", [None, -1, 0, 1])
+@pytest.mark.parametrize(
+    "numeric_only",
+    [
+        pytest.param(
+            True,
+            marks=pytest.mark.xfail(
+                reason="Modin - DID NOT RAISE <class 'NotImplementedError'>"
+            ),
+        ),
+        False,
+        None,
+    ],
+)
+@pytest.mark.parametrize("method", ["kurtosis", "kurt"])
+def test_kurt_kurtosis(data, axis, skipna, level, numeric_only, method):
     modin_series, pandas_series = create_test_series(data)
-    with pytest.warns(UserWarning):
-        modin_series.kurtosis()
+    try:
+        pandas_result = getattr(pandas_series, method)(
+            axis, skipna, level, numeric_only
+        )
+    except Exception as e:
+        with pytest.raises(type(e)):
+            repr(
+                getattr(modin_series, method)(axis, skipna, level, numeric_only)
+            )  # repr to force materialization
+    else:
+        modin_result = getattr(modin_series, method)(axis, skipna, level, numeric_only)
+        df_equals(modin_result, pandas_result)
 
 
 def test_last():
diff --git a/modin/pandas/test/utils.py b/modin/pandas/test/utils.py
--- a/modin/pandas/test/utils.py
+++ b/modin/pandas/test/utils.py
@@ -293,10 +293,10 @@
 
 # Parametrizations of common kwargs
 axis = {
-    "over rows int": 0,
-    "over rows str": "rows",
-    "over columns int": 1,
-    "over columns str": "columns",
+    "over_rows_int": 0,
+    "over_rows_str": "rows",
+    "over_columns_int": 1,
+    "over_columns_str": "columns",
 }
 axis_keys = list(axis.keys())
 axis_values = list(axis.values())