Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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***
Expand Down
28 changes: 16 additions & 12 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Expand Down
11 changes: 11 additions & 0 deletions pandas/tests/frame/test_query_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading