From e0c4b544a23ffaf532adc11927009d29c916419b Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 29 Jan 2019 15:43:07 -0600 Subject: [PATCH] REGR: Preserve order by default in Index.difference (#24967) Closes https://github.com/pandas-dev/pandas/issues/24959 --- doc/source/whatsnew/v0.24.1.rst | 1 + pandas/core/indexes/base.py | 8 ++++++-- pandas/core/indexes/datetimes.py | 10 +++++++++- pandas/core/indexes/interval.py | 6 +++--- pandas/core/indexes/multi.py | 6 +++++- pandas/core/indexes/range.py | 6 +++++- pandas/tests/indexes/test_base.py | 22 +++++++++++++++++----- 7 files changed, 46 insertions(+), 13 deletions(-) diff --git a/doc/source/whatsnew/v0.24.1.rst b/doc/source/whatsnew/v0.24.1.rst index 8f4c3982c745f1..828c35c10e958b 100644 --- a/doc/source/whatsnew/v0.24.1.rst +++ b/doc/source/whatsnew/v0.24.1.rst @@ -22,6 +22,7 @@ Fixed Regressions - Bug in :meth:`DataFrame.itertuples` with ``records`` orient raising an ``AttributeError`` when the ``DataFrame`` contained more than 255 columns (:issue:`24939`) - Bug in :meth:`DataFrame.itertuples` orient converting integer column names to strings prepended with an underscore (:issue:`24940`) +- Fixed regression in :class:`Index.intersection` incorrectly sorting the values by default (:issue:`24959`). .. _whatsnew_0241.enhancements: diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 767da81c5c43a3..3d176012df22be 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -2333,7 +2333,7 @@ def union(self, other, sort=True): def _wrap_setop_result(self, other, result): return self._constructor(result, name=get_op_result_name(self, other)) - def intersection(self, other, sort=True): + def intersection(self, other, sort=False): """ Form the intersection of two Index objects. @@ -2342,11 +2342,15 @@ def intersection(self, other, sort=True): Parameters ---------- other : Index or array-like - sort : bool, default True + sort : bool, default False Sort the resulting index if possible .. versionadded:: 0.24.0 + .. versionchanged:: 0.24.1 + + Changed the default from ``True`` to ``False``. + Returns ------- intersection : Index diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index cc373c06efcc9c..ef941ab87ba124 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -594,7 +594,7 @@ def _wrap_setop_result(self, other, result): name = get_op_result_name(self, other) return self._shallow_copy(result, name=name, freq=None, tz=self.tz) - def intersection(self, other, sort=True): + def intersection(self, other, sort=False): """ Specialized intersection for DatetimeIndex objects. May be much faster than Index.intersection @@ -602,6 +602,14 @@ def intersection(self, other, sort=True): Parameters ---------- other : DatetimeIndex or array-like + sort : bool, default True + Sort the resulting index if possible. + + .. versionadded:: 0.24.0 + + .. versionchanged:: 0.24.1 + + Changed the default from ``True`` to ``False``. Returns ------- diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 0210560aaa21f4..736de94991181f 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -1093,8 +1093,8 @@ def equals(self, other): def overlaps(self, other): return self._data.overlaps(other) - def _setop(op_name): - def func(self, other, sort=True): + def _setop(op_name, sort=True): + def func(self, other, sort=sort): other = self._as_like_interval_index(other) # GH 19016: ensure set op will not return a prohibited dtype @@ -1128,7 +1128,7 @@ def is_all_dates(self): return False union = _setop('union') - intersection = _setop('intersection') + intersection = _setop('intersection', sort=False) difference = _setop('difference') symmetric_difference = _setop('symmetric_difference') diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index e4d01a40bd1814..16af3fe8eef26f 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2910,7 +2910,7 @@ def union(self, other, sort=True): return MultiIndex.from_arrays(lzip(*uniq_tuples), sortorder=0, names=result_names) - def intersection(self, other, sort=True): + def intersection(self, other, sort=False): """ Form the intersection of two MultiIndex objects. @@ -2922,6 +2922,10 @@ def intersection(self, other, sort=True): .. versionadded:: 0.24.0 + .. versionchanged:: 0.24.1 + + Changed the default from ``True`` to ``False``. + Returns ------- Index diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index ebf5b279563cf6..e17a6a682af40c 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -343,7 +343,7 @@ def equals(self, other): return super(RangeIndex, self).equals(other) - def intersection(self, other, sort=True): + def intersection(self, other, sort=False): """ Form the intersection of two Index objects. @@ -355,6 +355,10 @@ def intersection(self, other, sort=True): .. versionadded:: 0.24.0 + .. versionchanged:: 0.24.1 + + Changed the default from ``True`` to ``False``. + Returns ------- intersection : Index diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index f3e9d835c7391d..20e439de46bde3 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -765,6 +765,11 @@ def test_intersect_str_dates(self, sort): assert len(result) == 0 + def test_intersect_nosort(self): + result = pd.Index(['c', 'b', 'a']).intersection(['b', 'a']) + expected = pd.Index(['b', 'a']) + tm.assert_index_equal(result, expected) + @pytest.mark.parametrize("sort", [True, False]) def test_chained_union(self, sort): # Chained unions handles names correctly @@ -1595,20 +1600,27 @@ def test_drop_tuple(self, values, to_drop): for drop_me in to_drop[1], [to_drop[1]]: pytest.raises(KeyError, removed.drop, drop_me) - @pytest.mark.parametrize("method,expected", [ + @pytest.mark.parametrize("method,expected,sort", [ + ('intersection', np.array([(1, 'A'), (2, 'A'), (1, 'B'), (2, 'B')], + dtype=[('num', int), ('let', 'a1')]), + False), + ('intersection', np.array([(1, 'A'), (1, 'B'), (2, 'A'), (2, 'B')], - dtype=[('num', int), ('let', 'a1')])), + dtype=[('num', int), ('let', 'a1')]), + True), + ('union', np.array([(1, 'A'), (1, 'B'), (1, 'C'), (2, 'A'), (2, 'B'), - (2, 'C')], dtype=[('num', int), ('let', 'a1')])) + (2, 'C')], dtype=[('num', int), ('let', 'a1')]), + True) ]) - def test_tuple_union_bug(self, method, expected): + def test_tuple_union_bug(self, method, expected, sort): index1 = Index(np.array([(1, 'A'), (2, 'A'), (1, 'B'), (2, 'B')], dtype=[('num', int), ('let', 'a1')])) index2 = Index(np.array([(1, 'A'), (2, 'A'), (1, 'B'), (2, 'B'), (1, 'C'), (2, 'C')], dtype=[('num', int), ('let', 'a1')])) - result = getattr(index1, method)(index2) + result = getattr(index1, method)(index2, sort=sort) assert result.ndim == 1 expected = Index(expected)