From 4bdb7e9428f4d95560f6318e01b09f50bea5960f Mon Sep 17 00:00:00 2001 From: phofl Date: Wed, 25 Nov 2020 23:30:50 +0100 Subject: [PATCH 1/4] Fix at bug --- pandas/core/indexes/multi.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 4b67deb2d102c..bcb25d24bdebe 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2527,6 +2527,9 @@ def _get_values_for_loc(self, series: "Series", loc, key): if is_scalar(loc): return new_values + if len(new_values) == 1: + return new_values[0] + new_index = self[loc] new_index = maybe_droplevels(new_index, key) new_ser = series._constructor(new_values, index=new_index, name=series.name) From ce8eb8d58218cba373140f8ba98dbec91613c190 Mon Sep 17 00:00:00 2001 From: phofl Date: Thu, 26 Nov 2020 22:40:30 +0100 Subject: [PATCH 2/4] Add test and whatsnew --- doc/source/whatsnew/v1.2.0.rst | 1 + pandas/tests/indexing/test_scalar.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 27511c96faa5a..36bb5af24fc7a 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -625,6 +625,7 @@ Indexing - Bug in :meth:`DataFrame.iloc` and :meth:`Series.iloc` aligning objects in ``__setitem__`` (:issue:`22046`) - Bug in :meth:`DataFrame.loc` did not raise ``KeyError`` when missing combination was given with ``slice(None)`` for remaining levels (:issue:`19556`) - Bug in :meth:`DataFrame.loc` raising ``TypeError`` when non-integer slice was given to select values from :class:`MultiIndex` (:issue:`25165`, :issue:`24263`) +- Bug in :meth:`Series.at` returning :class:`Series` with one element instead of scalar (:issue:`38053`) - Bug in :meth:`DataFrame.loc` returning and assigning elements in wrong order when indexer is differently ordered than the :class:`MultiIndex` to filter (:issue:`31330`, :issue:`34603`) - Bug in :meth:`DataFrame.loc` and :meth:`DataFrame.__getitem__` raising ``KeyError`` when columns were :class:`MultiIndex` with only one level (:issue:`29749`) diff --git a/pandas/tests/indexing/test_scalar.py b/pandas/tests/indexing/test_scalar.py index dd01f4e6a4f49..40a4d1c2edae0 100644 --- a/pandas/tests/indexing/test_scalar.py +++ b/pandas/tests/indexing/test_scalar.py @@ -300,3 +300,10 @@ def test_multiindex_at_set(): assert series.at[1, 3] == 5 series.loc[1, 3] = 6 assert series.loc[1, 3] == 6 + + +def test_at_get_multiindex_one_level(): + # GH#38053 + s2 = Series((0, 1), index=[[False, True]]) + result = s2.at[False] + assert result == 0 From a6cf297199840751e44c815a0da23b079474c53a Mon Sep 17 00:00:00 2001 From: phofl Date: Fri, 27 Nov 2020 00:07:44 +0100 Subject: [PATCH 3/4] Refactor tests --- doc/source/whatsnew/v1.2.0.rst | 2 +- pandas/tests/indexing/test_scalar.py | 77 ++++++++++++++-------------- 2 files changed, 39 insertions(+), 40 deletions(-) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 36bb5af24fc7a..8491d939f27ac 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -625,7 +625,7 @@ Indexing - Bug in :meth:`DataFrame.iloc` and :meth:`Series.iloc` aligning objects in ``__setitem__`` (:issue:`22046`) - Bug in :meth:`DataFrame.loc` did not raise ``KeyError`` when missing combination was given with ``slice(None)`` for remaining levels (:issue:`19556`) - Bug in :meth:`DataFrame.loc` raising ``TypeError`` when non-integer slice was given to select values from :class:`MultiIndex` (:issue:`25165`, :issue:`24263`) -- Bug in :meth:`Series.at` returning :class:`Series` with one element instead of scalar (:issue:`38053`) +- Bug in :meth:`Series.at` returning :class:`Series` with one element instead of scalar when index is a :class:`MultiIndex` with one level (:issue:`38053`) - Bug in :meth:`DataFrame.loc` returning and assigning elements in wrong order when indexer is differently ordered than the :class:`MultiIndex` to filter (:issue:`31330`, :issue:`34603`) - Bug in :meth:`DataFrame.loc` and :meth:`DataFrame.__getitem__` raising ``KeyError`` when columns were :class:`MultiIndex` with only one level (:issue:`29749`) diff --git a/pandas/tests/indexing/test_scalar.py b/pandas/tests/indexing/test_scalar.py index 40a4d1c2edae0..ce48fd1e5c905 100644 --- a/pandas/tests/indexing/test_scalar.py +++ b/pandas/tests/indexing/test_scalar.py @@ -268,42 +268,41 @@ def test_at_with_tuple_index_set(): assert series.at[1, 2] == 3 -def test_multiindex_at_get(): - # GH 26989 - # DataFrame.at and DataFrame.loc getter works with MultiIndex - df = DataFrame({"a": [1, 2]}, index=[[1, 2], [3, 4]]) - assert df.index.nlevels == 2 - assert df.at[(1, 3), "a"] == 1 - assert df.loc[(1, 3), "a"] == 1 - - # Series.at and Series.loc getter works with MultiIndex - series = df["a"] - assert series.index.nlevels == 2 - assert series.at[1, 3] == 1 - assert series.loc[1, 3] == 1 - - -def test_multiindex_at_set(): - # GH 26989 - # DataFrame.at and DataFrame.loc setter works with MultiIndex - df = DataFrame({"a": [1, 2]}, index=[[1, 2], [3, 4]]) - assert df.index.nlevels == 2 - df.at[(1, 3), "a"] = 3 - assert df.at[(1, 3), "a"] == 3 - df.loc[(1, 3), "a"] = 4 - assert df.loc[(1, 3), "a"] == 4 - - # Series.at and Series.loc setter works with MultiIndex - series = df["a"] - assert series.index.nlevels == 2 - series.at[1, 3] = 5 - assert series.at[1, 3] == 5 - series.loc[1, 3] = 6 - assert series.loc[1, 3] == 6 - - -def test_at_get_multiindex_one_level(): - # GH#38053 - s2 = Series((0, 1), index=[[False, True]]) - result = s2.at[False] - assert result == 0 +class TestMultiIndexScalar: + def test_multiindex_at_get(self): + # GH 26989 + # DataFrame.at and DataFrame.loc getter works with MultiIndex + df = DataFrame({"a": [1, 2]}, index=[[1, 2], [3, 4]]) + assert df.index.nlevels == 2 + assert df.at[(1, 3), "a"] == 1 + assert df.loc[(1, 3), "a"] == 1 + + # Series.at and Series.loc getter works with MultiIndex + series = df["a"] + assert series.index.nlevels == 2 + assert series.at[1, 3] == 1 + assert series.loc[1, 3] == 1 + + def test_multiindex_at_set(self): + # GH 26989 + # DataFrame.at and DataFrame.loc setter works with MultiIndex + df = DataFrame({"a": [1, 2]}, index=[[1, 2], [3, 4]]) + assert df.index.nlevels == 2 + df.at[(1, 3), "a"] = 3 + assert df.at[(1, 3), "a"] == 3 + df.loc[(1, 3), "a"] = 4 + assert df.loc[(1, 3), "a"] == 4 + + # Series.at and Series.loc setter works with MultiIndex + series = df["a"] + assert series.index.nlevels == 2 + series.at[1, 3] = 5 + assert series.at[1, 3] == 5 + series.loc[1, 3] = 6 + assert series.loc[1, 3] == 6 + + def test_multiindex_at_get_one_level(self): + # GH#38053 + s2 = Series((0, 1), index=[[False, True]]) + result = s2.at[False] + assert result == 0 From f887f6a79f7e7b100f317d7186738641032be253 Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 28 Nov 2020 19:13:12 +0100 Subject: [PATCH 4/4] Fix bug --- pandas/core/indexes/multi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index bcb25d24bdebe..cc29c310aa7a2 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2527,7 +2527,8 @@ def _get_values_for_loc(self, series: "Series", loc, key): if is_scalar(loc): return new_values - if len(new_values) == 1: + if len(new_values) == 1 and not self.nlevels > 1: + # If more than one level left, we can not return a scalar return new_values[0] new_index = self[loc]