From 28e4a51684ae18f1ab6830ea4414cb798ae3c6c0 Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Wed, 9 Sep 2020 01:01:18 +0800 Subject: [PATCH 01/10] Remove attempt to get self.name --- pandas/core/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index 1926803d8f04b..700c06349ac04 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -472,7 +472,7 @@ def is_any_frame() -> bool: except ValueError: # we have a dict of scalars - result = Series(result, name=getattr(self, "name", None)) + result = Series(result) return result, True elif is_list_like(arg): From 0d3c8532f7dfb05fb2d762a5db49a63f7da33c3c Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Wed, 9 Sep 2020 21:59:35 +0800 Subject: [PATCH 02/10] Add back get self.name --- pandas/core/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index 700c06349ac04..1926803d8f04b 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -472,7 +472,7 @@ def is_any_frame() -> bool: except ValueError: # we have a dict of scalars - result = Series(result) + result = Series(result, name=getattr(self, "name", None)) return result, True elif is_list_like(arg): From 189fc6191aff18f3788f3cf3bf96d7af1c0d0efa Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Wed, 9 Sep 2020 22:28:51 +0800 Subject: [PATCH 03/10] Add test_agg_with_unhashable_name_colum_value (should fail) --- pandas/tests/frame/apply/test_frame_apply.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pandas/tests/frame/apply/test_frame_apply.py b/pandas/tests/frame/apply/test_frame_apply.py index 1662f9e2fff56..5d32c713068de 100644 --- a/pandas/tests/frame/apply/test_frame_apply.py +++ b/pandas/tests/frame/apply/test_frame_apply.py @@ -1147,6 +1147,22 @@ def test_demo(self): ) tm.assert_frame_equal(result.reindex_like(expected), expected) + def test_agg_with_unhashable_name_column_value(self): + #GH 36212 - Column name is "name" + data = {'name': ['foo', 'bar']} + df = pd.DataFrame(data) + + #result's name should be None + result = df.agg({'name': 'count'}) + expected = pd.Series({'name':2}) + tm.assert_series_equal(result, expected) + + #Check if name is preserved when aggregating series instead + result = df['name'].agg({'name':'count'}) + expected = pd.Series({'name':2}, name='name') + tm.assert_series_equal(result, expected) + + def test_agg_multiple_mixed_no_warning(self): # GH 20909 mdf = pd.DataFrame( From 0500d976e8649dfe560d28d05630c56873ea731e Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Wed, 9 Sep 2020 22:32:23 +0800 Subject: [PATCH 04/10] Catch unhashable name --- pandas/core/base.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index 1926803d8f04b..a6b2c37d73b7c 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -472,7 +472,11 @@ def is_any_frame() -> bool: except ValueError: # we have a dict of scalars - result = Series(result, name=getattr(self, "name", None)) + + name = getattr(self, "name", None) + name = name if is_hashable(name) else None + # GH#36212 + result = Series(result, name=name) return result, True elif is_list_like(arg): From 3e8b84aef0a909ad622cd550d0e76f174ddab0a0 Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Wed, 9 Sep 2020 22:36:51 +0800 Subject: [PATCH 05/10] Reformat to comply with PEP8 --- pandas/core/base.py | 3 ++- pandas/tests/frame/apply/test_frame_apply.py | 17 ++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index a6b2c37d73b7c..122f623db43b5 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -19,6 +19,7 @@ is_categorical_dtype, is_dict_like, is_extension_array_dtype, + is_hashable, is_list_like, is_object_dtype, is_scalar, @@ -472,7 +473,7 @@ def is_any_frame() -> bool: except ValueError: # we have a dict of scalars - + name = getattr(self, "name", None) name = name if is_hashable(name) else None # GH#36212 diff --git a/pandas/tests/frame/apply/test_frame_apply.py b/pandas/tests/frame/apply/test_frame_apply.py index 5d32c713068de..24bc16662f7c3 100644 --- a/pandas/tests/frame/apply/test_frame_apply.py +++ b/pandas/tests/frame/apply/test_frame_apply.py @@ -1148,21 +1148,20 @@ def test_demo(self): tm.assert_frame_equal(result.reindex_like(expected), expected) def test_agg_with_unhashable_name_column_value(self): - #GH 36212 - Column name is "name" - data = {'name': ['foo', 'bar']} + # GH 36212 - Column name is "name" + data = {"name": ["foo", "bar"]} df = pd.DataFrame(data) - #result's name should be None - result = df.agg({'name': 'count'}) - expected = pd.Series({'name':2}) + # result's name should be None + result = df.agg({"name": "count"}) + expected = pd.Series({"name": 2}) tm.assert_series_equal(result, expected) - #Check if name is preserved when aggregating series instead - result = df['name'].agg({'name':'count'}) - expected = pd.Series({'name':2}, name='name') + # Check if name is preserved when aggregating series instead + result = df["name"].agg({"name": "count"}) + expected = pd.Series({"name": 2}, name="name") tm.assert_series_equal(result, expected) - def test_agg_multiple_mixed_no_warning(self): # GH 20909 mdf = pd.DataFrame( From 1fb756480082c5f4669a77340df89d2ddb2fd31e Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Wed, 9 Sep 2020 22:50:41 +0800 Subject: [PATCH 06/10] Fix comment typo --- pandas/core/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index 122f623db43b5..68fb28e0c5efb 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -476,7 +476,7 @@ def is_any_frame() -> bool: name = getattr(self, "name", None) name = name if is_hashable(name) else None - # GH#36212 + # GH 36212 result = Series(result, name=name) return result, True From a863e0d6bdb6f4f41e9d934a4caed3fe0eb5b51c Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Sat, 12 Sep 2020 05:24:41 +0800 Subject: [PATCH 07/10] Check ndim instead of hashable --- pandas/core/base.py | 7 +++---- pandas/tests/frame/apply/test_frame_apply.py | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index 68fb28e0c5efb..8b5cd7688fe32 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -471,12 +471,11 @@ def is_any_frame() -> bool: try: result = DataFrame(result) except ValueError: - # we have a dict of scalars - name = getattr(self, "name", None) - name = name if is_hashable(name) else None - # GH 36212 + # GH 36212 use name only if self is a series + name = getattr(self, "name", None) if (self.ndim == 1) else None + result = Series(result, name=name) return result, True diff --git a/pandas/tests/frame/apply/test_frame_apply.py b/pandas/tests/frame/apply/test_frame_apply.py index 24bc16662f7c3..f75d7c13665f9 100644 --- a/pandas/tests/frame/apply/test_frame_apply.py +++ b/pandas/tests/frame/apply/test_frame_apply.py @@ -1147,7 +1147,7 @@ def test_demo(self): ) tm.assert_frame_equal(result.reindex_like(expected), expected) - def test_agg_with_unhashable_name_column_value(self): + def test_agg_with_name_as_column_name(self): # GH 36212 - Column name is "name" data = {"name": ["foo", "bar"]} df = pd.DataFrame(data) @@ -1157,7 +1157,7 @@ def test_agg_with_unhashable_name_column_value(self): expected = pd.Series({"name": 2}) tm.assert_series_equal(result, expected) - # Check if name is preserved when aggregating series instead + # Check if name is still preserved when aggregating series instead result = df["name"].agg({"name": "count"}) expected = pd.Series({"name": 2}, name="name") tm.assert_series_equal(result, expected) From 214f2629bbbd544d3db86f4eb511e7cad3bbed32 Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Sat, 12 Sep 2020 11:15:50 +0800 Subject: [PATCH 08/10] Remove unused import --- pandas/core/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index 8b5cd7688fe32..a8edeba311976 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -19,7 +19,6 @@ is_categorical_dtype, is_dict_like, is_extension_array_dtype, - is_hashable, is_list_like, is_object_dtype, is_scalar, From c5648a6fa64e92f2dd914ec04109e3b411ba3008 Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Sun, 13 Sep 2020 05:38:16 +0800 Subject: [PATCH 09/10] Change getattr to access self.name directly --- pandas/core/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index a8edeba311976..7bcce695d999e 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -473,7 +473,7 @@ def is_any_frame() -> bool: # we have a dict of scalars # GH 36212 use name only if self is a series - name = getattr(self, "name", None) if (self.ndim == 1) else None + name = self.name if (self.ndim == 1) else None result = Series(result, name=name) From bbcd703158d26d9e78ce3d4adc0f7a776fe70794 Mon Sep 17 00:00:00 2001 From: leonarduschen Date: Sun, 13 Sep 2020 05:56:33 +0800 Subject: [PATCH 10/10] Add whatsnew note --- doc/source/whatsnew/v1.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index bce6a735b7b07..fdc7a5b796685 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -323,6 +323,7 @@ Reshaping - Bug in :meth:`DataFrame.pivot_table` with ``aggfunc='count'`` or ``aggfunc='sum'`` returning ``NaN`` for missing categories when pivoted on a ``Categorical``. Now returning ``0`` (:issue:`31422`) - Bug in :func:`union_indexes` where input index names are not preserved in some cases. Affects :func:`concat` and :class:`DataFrame` constructor (:issue:`13475`) - Bug in func :meth:`crosstab` when using multiple columns with ``margins=True`` and ``normalize=True`` (:issue:`35144`) +- Bug in :meth:`DataFrame.agg` with ``func={'name':}`` incorrectly raising ``TypeError`` when ``DataFrame.columns==['Name']`` (:issue:`36212`) - Sparse