From 0fd0283a4c5ca9cc41503444a027fdc0a976a947 Mon Sep 17 00:00:00 2001 From: kjmin622 Date: Thu, 14 May 2026 08:23:07 +0900 Subject: [PATCH 1/2] BUG: DataFrame.eval inconsistently handles duplicated columns --- pandas/core/generic.py | 28 +++++++++++++++------------ pandas/tests/frame/test_query_eval.py | 11 +++++++++++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 2ad7315d84653..5933b16953284 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -575,7 +575,7 @@ def _get_index_resolvers(self) -> dict[Hashable, Series | MultiIndex]: return {clean_column_name(k): v for k, v in d.items() if not isinstance(k, int)} @final - def _get_cleaned_column_resolvers(self) -> dict[Hashable, Series]: + def _get_cleaned_column_resolvers(self) -> dict[Hashable, Series | DataFrame]: """ Return the special character free column resolvers of a DataFrame. @@ -590,17 +590,21 @@ def _get_cleaned_column_resolvers(self) -> dict[Hashable, Series]: return {clean_column_name(self.name): self} dtypes = self.dtypes - return { - clean_column_name(k): Series( - v, copy=False, index=self.index, name=k, dtype=dtype - ).__finalize__(self) - for k, v, dtype in zip( - self.columns, - self._iter_column_arrays(), - dtypes, - strict=True, - ) - } + result: dict[Hashable, Series | DataFrame] = {} + for k, v, dtype in zip( + self.columns, + self._iter_column_arrays(), + dtypes, + strict=True, + ): + clean_key = clean_column_name(k) + if clean_key in result: + result[clean_key] = self[k] + else: + result[clean_key] = Series( + v, copy=False, index=self.index, name=k, dtype=dtype + ).__finalize__(self) + return result @final @property diff --git a/pandas/tests/frame/test_query_eval.py b/pandas/tests/frame/test_query_eval.py index cfa463f76ff93..ba84cd3565de9 100644 --- a/pandas/tests/frame/test_query_eval.py +++ b/pandas/tests/frame/test_query_eval.py @@ -170,6 +170,17 @@ def test_query_duplicate_column_name(self, engine, parser): tm.assert_frame_equal(res, expect) + def test_eval_duplicate_column_name(self, engine, parser): + # GH#65588 + df = DataFrame({"a": range(3), "b": range(10, 13), "c": range(3)}).rename( + columns={"b": "a"} + ) + + result = df.eval("a == 1", engine=engine, parser=parser) + expected = pd.eval("a == 1", resolvers=(df,), engine=engine, parser=parser) + + tm.assert_frame_equal(result, expected) + def test_eval_resolvers_as_list(self): # GH 14095 df = DataFrame( From 9c6bac3d35cb98ae1e8ab03be530acab1445dfad Mon Sep 17 00:00:00 2001 From: kjmin622 Date: Sat, 16 May 2026 14:12:12 +0900 Subject: [PATCH 2/2] add whatsnew --- doc/source/whatsnew/v3.1.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v3.1.0.rst b/doc/source/whatsnew/v3.1.0.rst index e0023c83cc0df..7014676c60332 100644 --- a/doc/source/whatsnew/v3.1.0.rst +++ b/doc/source/whatsnew/v3.1.0.rst @@ -393,6 +393,7 @@ Styler Other ^^^^^ +- Bug in :meth:`DataFrame.eval` where a column name appearing on multiple columns was resolved to a single column (yielding a :class:`Series`), inconsistent with :func:`pandas.eval` using ``resolvers=(df,)`` and with :meth:`DataFrame.__getitem__`, which include every column with that label (:issue:`65588`) - Bug in :meth:`Series.transform` and :meth:`DataFrame.transform` where passing a list of duplicate function names did not raise :class:`errors.SpecificationError` (:issue:`54929`) .. ***DO NOT USE THIS SECTION***