diff --git a/examples/series/rolling/series_rolling_kurt.py b/examples/series/rolling/series_rolling_kurt.py new file mode 100644 index 000000000..5010ae1f6 --- /dev/null +++ b/examples/series/rolling/series_rolling_kurt.py @@ -0,0 +1,39 @@ +# ***************************************************************************** +# Copyright (c) 2019, Intel Corporation All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ***************************************************************************** + +import pandas as pd +from numba import njit + + +@njit +def series_rolling_kurt(): + series = pd.Series([4, 3, 5, 2, 6]) # Series of 4, 3, 5, 2, 6 + out_series = series.rolling(4).kurt() + + return out_series # Expect series of NaN, NaN, NaN, -1.2, -3.3 + + +print(series_rolling_kurt()) diff --git a/sdc/datatypes/hpat_pandas_series_rolling_functions.py b/sdc/datatypes/hpat_pandas_series_rolling_functions.py index 26188405f..23adc8f11 100644 --- a/sdc/datatypes/hpat_pandas_series_rolling_functions.py +++ b/sdc/datatypes/hpat_pandas_series_rolling_functions.py @@ -114,6 +114,31 @@ def arr_cov(x, y, ddof): return numpy.cov(x, y, ddof=ddof)[0, 1] +@register_jitable +def _moment(arr, moment): + mn = numpy.mean(arr) + s = numpy.power((arr - mn), moment) + + return numpy.mean(s) + + +@register_jitable +def arr_kurt(arr): + """Calculate unbiased kurtosis of values""" + n = len(arr) + if n < 4: + return numpy.nan + + m2 = _moment(arr, 2) + m4 = _moment(arr, 4) + val = 0 if m2 == 0 else m4 / m2 ** 2.0 + + if (n > 2) & (m2 > 0): + val = 1.0/(n-2)/(n-3) * ((n**2-1.0)*m4/m2**2.0 - 3*(n-1)**2.0) + + return val + + @register_jitable def arr_max(arr): """Calculate maximum of values""" @@ -270,6 +295,8 @@ def impl(self): hpat_pandas_rolling_series_count_impl = register_jitable( gen_hpat_pandas_series_rolling_zerominp_impl(arr_nonnan_count, float64)) +hpat_pandas_rolling_series_kurt_impl = register_jitable( + gen_hpat_pandas_series_rolling_impl(arr_kurt, float64)) hpat_pandas_rolling_series_max_impl = register_jitable( gen_hpat_pandas_series_rolling_impl(arr_max, float64)) hpat_pandas_rolling_series_mean_impl = register_jitable( @@ -504,6 +531,15 @@ def calc_cov(main, other, ddof, minp): return hpat_pandas_rolling_series_cov_impl +@sdc_overload_method(SeriesRollingType, 'kurt') +def hpat_pandas_series_rolling_kurt(self): + + ty_checker = TypeChecker('Method rolling.kurt().') + ty_checker.check(self, SeriesRollingType) + + return hpat_pandas_rolling_series_kurt_impl + + @sdc_overload_method(SeriesRollingType, 'max') def hpat_pandas_series_rolling_max(self): """ @@ -883,6 +919,13 @@ def culc_var(arr, ddof, minp): """ }) +hpat_pandas_series_rolling_kurt.__doc__ = hpat_pandas_series_rolling_docstring_tmpl.format(**{ + 'method_name': 'kurt', + 'example_caption': 'Calculate unbiased rolling kurtosis.', + 'limitations_block': '', + 'extra_params': '' +}) + hpat_pandas_series_rolling_mean.__doc__ = hpat_pandas_series_rolling_docstring_tmpl.format(**{ 'method_name': 'mean', 'example_caption': 'Calculate the rolling mean of the values.', diff --git a/sdc/tests/test_rolling.py b/sdc/tests/test_rolling.py index e0685e3d3..0c564c18f 100644 --- a/sdc/tests/test_rolling.py +++ b/sdc/tests/test_rolling.py @@ -730,6 +730,25 @@ def test_impl(pairwise, ddof): msg = msg_tmpl.format('ddof', 'unicode_type', 'int') self.assertIn(msg, str(raises.exception)) + @skip_sdc_jit('Series.rolling.kurt() unsupported Series index') + def test_series_rolling_kurt(self): + def test_impl(series, window, min_periods): + return series.rolling(window, min_periods).kurt() + + hpat_func = self.jit(test_impl) + + all_data = test_global_input_data_float64 + indices = [list(range(len(data)))[::-1] for data in all_data] + for data, index in zip(all_data, indices): + series = pd.Series(data, index, name='A') + for window in range(4, len(series) + 1): + for min_periods in range(window + 1): + with self.subTest(series=series, window=window, + min_periods=min_periods): + ref_result = test_impl(series, window, min_periods) + jit_result = hpat_func(series, window, min_periods) + pd.testing.assert_series_equal(jit_result, ref_result) + @skip_sdc_jit('Series.rolling.max() unsupported Series index') def test_series_rolling_max(self): def test_impl(series, window, min_periods):