From 6f27b9a25d8045d6f3701c9ec8d304d14cb9c3e3 Mon Sep 17 00:00:00 2001 From: jschendel Date: Wed, 20 Sep 2017 12:05:41 -0600 Subject: [PATCH 1/3] PERF: RangeIndex min/max Implemented RangeIndex min/max in terms of RangeIndex properties. --- asv_bench/benchmarks/index_object.py | 20 ++++++++++++++++++++ doc/source/whatsnew/v0.21.0.txt | 1 + pandas/core/indexes/range.py | 18 ++++++++++++++++++ pandas/tests/indexes/test_range.py | 21 ++++++++++++++++++++- 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/asv_bench/benchmarks/index_object.py b/asv_bench/benchmarks/index_object.py index 3fb53ce9b3c98..454d9ccdda102 100644 --- a/asv_bench/benchmarks/index_object.py +++ b/asv_bench/benchmarks/index_object.py @@ -199,3 +199,23 @@ def time_datetime_level_values_full(self): def time_datetime_level_values_sliced(self): self.mi[:10].values + + +class Range(object): + goal_time = 0.2 + + def setup(self): + self.idx_inc = RangeIndex(start=0, stop=10**7, step=3) + self.idx_dec = RangeIndex(start=10**7, stop=-1, step=-3) + + def time_max(self): + self.idx_inc.max() + + def time_max_trivial(self): + self.idx_dec.max() + + def time_min(self): + self.idx_dec.min() + + def time_min_trivial(self): + self.idx_inc.min() diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 8bc9834ebef09..badf14871ab2d 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -473,6 +473,7 @@ Performance Improvements - Improved performance of :meth:`Categorical.set_categories` by not materializing the values (:issue:`17508`) - :attr:`Timestamp.microsecond` no longer re-computes on attribute access (:issue:`17331`) - Improved performance of the :class:`CategoricalIndex` for data that is already categorical dtype (:issue:`17513`) +- Improved performance of ``RangeIndex.min`` and ``RangeIndex.max`` by using ``RangeIndex`` properties to perform the computations (:issue:`17607`) .. _whatsnew_0210.bug_fixes: diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index b759abaed4e56..16523257c2f77 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -269,6 +269,24 @@ def copy(self, name=None, deep=False, dtype=None, **kwargs): return RangeIndex(name=name, fastpath=True, **dict(self._get_data_as_items())) + def _minmax(self, meth): + no_steps = len(self) - 1 + if no_steps == -1: + return np.nan + elif ((meth == 'min' and self._step > 0) or + (meth == 'max' and self._step < 0)): + return self._start + + return self._start + self._step * no_steps + + def min(self): + """The minimum value of the RangeIndex""" + return self._minmax('min') + + def max(self): + """The maximum value of the RangeIndex""" + return self._minmax('max') + def argsort(self, *args, **kwargs): """ Returns the indices that would sort the index and its diff --git a/pandas/tests/indexes/test_range.py b/pandas/tests/indexes/test_range.py index d206c36ee51c9..ff30dbc955788 100644 --- a/pandas/tests/indexes/test_range.py +++ b/pandas/tests/indexes/test_range.py @@ -10,7 +10,7 @@ import numpy as np -from pandas import (notna, Series, Index, Float64Index, +from pandas import (isna, notna, Series, Index, Float64Index, Int64Index, RangeIndex) import pandas.util.testing as tm @@ -994,3 +994,22 @@ def test_append(self): # Append single item rather than list result2 = indices[0].append(indices[1]) tm.assert_index_equal(result2, expected, exact=True) + + def test_max_min(self): + params = [(0, 400, 3), (500, 0, -6), (-10**6, 10**6, 4), + (10**6, -10**6, -4), (0, 10, 20)] + for start, stop, step in params: + idx = RangeIndex(start, stop, step) + + expected = idx._int64index.max() + result = idx.max() + assert result == expected + + expected = idx._int64index.min() + result = idx.min() + assert result == expected + + # empty + idx = RangeIndex(0, 1, -1) + assert isna(idx.max()) + assert isna(idx.min()) From 8aa59c3a31f846a8d452215766591a0db2b54b4f Mon Sep 17 00:00:00 2001 From: jschendel Date: Thu, 21 Sep 2017 17:13:07 -0600 Subject: [PATCH 2/3] parametrize test and update docs --- doc/source/api.rst | 44 ++++++++++++++++++++++++++++++ doc/source/whatsnew/v0.21.0.txt | 2 +- pandas/tests/indexes/test_range.py | 26 +++++++++--------- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index 6b3e6bedcb24b..447d4f0940bfb 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1416,6 +1416,50 @@ Selecting Index.slice_indexer Index.slice_locs +.. _api.int64index: + +Int64Index +---------- + +.. autosummary:: + :toctree: generated/ + :template: autosummary/class_without_autosummary.rst + + Int64Index + +.. _api.uint64index: + +UInt64Index +----------- + +.. autosummary:: + :toctree: generated/ + :template: autosummary/class_without_autosummary.rst + + UInt64Index + +.. _api.float64index: + +Float64Index +------------ + +.. autosummary:: + :toctree: generated/ + :template: autosummary/class_without_autosummary.rst + + Float64Index + +.. _api.rangeindex: + +RangeIndex +---------- + +.. autosummary:: + :toctree: generated/ + :template: autosummary/class_without_autosummary.rst + + RangeIndex + .. _api.categoricalindex: CategoricalIndex diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index badf14871ab2d..6157d73a76b31 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -473,7 +473,7 @@ Performance Improvements - Improved performance of :meth:`Categorical.set_categories` by not materializing the values (:issue:`17508`) - :attr:`Timestamp.microsecond` no longer re-computes on attribute access (:issue:`17331`) - Improved performance of the :class:`CategoricalIndex` for data that is already categorical dtype (:issue:`17513`) -- Improved performance of ``RangeIndex.min`` and ``RangeIndex.max`` by using ``RangeIndex`` properties to perform the computations (:issue:`17607`) +- Improved performance of :meth:`RangeIndex.min` and :meth:`RangeIndex.max` by using ``RangeIndex`` properties to perform the computations (:issue:`17607`) .. _whatsnew_0210.bug_fixes: diff --git a/pandas/tests/indexes/test_range.py b/pandas/tests/indexes/test_range.py index ff30dbc955788..8dc5a40ced4bf 100644 --- a/pandas/tests/indexes/test_range.py +++ b/pandas/tests/indexes/test_range.py @@ -995,21 +995,21 @@ def test_append(self): result2 = indices[0].append(indices[1]) tm.assert_index_equal(result2, expected, exact=True) - def test_max_min(self): - params = [(0, 400, 3), (500, 0, -6), (-10**6, 10**6, 4), - (10**6, -10**6, -4), (0, 10, 20)] - for start, stop, step in params: - idx = RangeIndex(start, stop, step) - - expected = idx._int64index.max() - result = idx.max() - assert result == expected + @pytest.mark.parametrize('start,stop,step', + [(0, 400, 3), (500, 0, -6), (-10**6, 10**6, 4), + (10**6, -10**6, -4), (0, 10, 20)]) + def test_max_min(self, start, stop, step): + # GH17607 + idx = RangeIndex(start, stop, step) + expected = idx._int64index.max() + result = idx.max() + assert result == expected - expected = idx._int64index.min() - result = idx.min() - assert result == expected + expected = idx._int64index.min() + result = idx.min() + assert result == expected # empty - idx = RangeIndex(0, 1, -1) + idx = RangeIndex(start, stop, -step) assert isna(idx.max()) assert isna(idx.min()) From 5379fc29e139db8f76f59e874528df170ebde4e9 Mon Sep 17 00:00:00 2001 From: jschendel Date: Fri, 22 Sep 2017 02:26:28 -0600 Subject: [PATCH 3/3] consolidate docs --- doc/source/api.rst | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index 447d4f0940bfb..96c7f68f57aaa 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1416,50 +1416,20 @@ Selecting Index.slice_indexer Index.slice_locs -.. _api.int64index: +.. _api.numericindex: -Int64Index ----------- +Numeric Index +------------- .. autosummary:: :toctree: generated/ :template: autosummary/class_without_autosummary.rst + RangeIndex Int64Index - -.. _api.uint64index: - -UInt64Index ------------ - -.. autosummary:: - :toctree: generated/ - :template: autosummary/class_without_autosummary.rst - UInt64Index - -.. _api.float64index: - -Float64Index ------------- - -.. autosummary:: - :toctree: generated/ - :template: autosummary/class_without_autosummary.rst - Float64Index -.. _api.rangeindex: - -RangeIndex ----------- - -.. autosummary:: - :toctree: generated/ - :template: autosummary/class_without_autosummary.rst - - RangeIndex - .. _api.categoricalindex: CategoricalIndex