Skip to content

Commit f485df0

Browse files
jbrockmendelim-vinicius
authored and
im-vinicius
committed
BUG: allow DataFrame[mask]=value with mixed non-numeric dtypes (pandas-dev#53291)
* DEPR: allow DataFrame[mask]=value with mixed non-numeric dtypes * Change deprecation to bugfix
1 parent 8410a67 commit f485df0

File tree

6 files changed

+17
-29
lines changed

6 files changed

+17
-29
lines changed

doc/source/whatsnew/v2.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ Interval
370370
Indexing
371371
^^^^^^^^
372372
- Bug in :meth:`DataFrame.__setitem__` losing dtype when setting a :class:`DataFrame` into duplicated columns (:issue:`53143`)
373+
- Bug in :meth:`DataFrame.__setitem__` with a boolean mask and :meth:`DataFrame.putmask` with mixed non-numeric dtypes and a value other than ``NaN`` incorrectly raising ``TypeError`` (:issue:`53291`)
373374
-
374375

375376
Missing

pandas/core/frame.py

-1
Original file line numberDiff line numberDiff line change
@@ -4074,7 +4074,6 @@ def _setitem_frame(self, key, value):
40744074
"Must pass DataFrame or 2-d ndarray with boolean values only"
40754075
)
40764076

4077-
self._check_inplace_setting(value)
40784077
self._check_setitem_copy()
40794078
self._where(-key, value, inplace=True)
40804079

pandas/core/generic.py

-17
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@
114114
is_bool_dtype,
115115
is_dict_like,
116116
is_extension_array_dtype,
117-
is_float,
118117
is_list_like,
119118
is_number,
120119
is_numeric_dtype,
@@ -6201,21 +6200,6 @@ def _is_mixed_type(self) -> bool_t:
62016200

62026201
return self.dtypes.nunique() > 1
62036202

6204-
@final
6205-
def _check_inplace_setting(self, value) -> bool_t:
6206-
"""check whether we allow in-place setting with this type of value"""
6207-
if self._is_mixed_type and not self._mgr.is_numeric_mixed_type:
6208-
# allow an actual np.nan through
6209-
if (is_float(value) and np.isnan(value)) or value is lib.no_default:
6210-
return True
6211-
6212-
raise TypeError(
6213-
"Cannot do inplace boolean setting on "
6214-
"mixed-types with a non np.nan value"
6215-
)
6216-
6217-
return True
6218-
62196203
@final
62206204
def _get_numeric_data(self) -> Self:
62216205
return self._constructor(self._mgr.get_numeric_data()).__finalize__(self)
@@ -10036,7 +10020,6 @@ def _where(
1003610020
# we may have different type blocks come out of putmask, so
1003710021
# reconstruct the block manager
1003810022

10039-
self._check_inplace_setting(other)
1004010023
new_data = self._mgr.putmask(mask=cond, new=other, align=align)
1004110024
result = self._constructor(new_data)
1004210025
return self._update_inplace(result)

pandas/core/internals/array_manager.py

-4
Original file line numberDiff line numberDiff line change
@@ -443,10 +443,6 @@ def to_native_types(self, **kwargs) -> Self:
443443
def is_mixed_type(self) -> bool:
444444
return True
445445

446-
@property
447-
def is_numeric_mixed_type(self) -> bool:
448-
return all(is_numeric_dtype(t) for t in self.get_dtypes())
449-
450446
@property
451447
def any_extension_types(self) -> bool:
452448
"""Whether any of the blocks in this manager are extension blocks"""

pandas/core/internals/managers.py

-4
Original file line numberDiff line numberDiff line change
@@ -514,10 +514,6 @@ def to_native_types(self, **kwargs) -> Self:
514514
"""
515515
return self.apply("to_native_types", **kwargs)
516516

517-
@property
518-
def is_numeric_mixed_type(self) -> bool:
519-
return all(block.is_numeric for block in self.blocks)
520-
521517
@property
522518
def any_extension_types(self) -> bool:
523519
"""Whether any of the blocks in this manager are extension blocks"""

pandas/tests/frame/indexing/test_where.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -401,10 +401,23 @@ def test_where_none(self):
401401
{"A": np.nan, "B": "Test", "C": np.nan},
402402
]
403403
)
404-
msg = "boolean setting on mixed-type"
405404

406-
with pytest.raises(TypeError, match=msg):
407-
df.where(~isna(df), None, inplace=True)
405+
orig = df.copy()
406+
407+
mask = ~isna(df)
408+
df.where(mask, None, inplace=True)
409+
expected = DataFrame(
410+
{
411+
"A": [1.0, np.nan],
412+
"B": [None, "Test"],
413+
"C": ["Test", None],
414+
}
415+
)
416+
tm.assert_frame_equal(df, expected)
417+
418+
df = orig.copy()
419+
df[~mask] = None
420+
tm.assert_frame_equal(df, expected)
408421

409422
def test_where_empty_df_and_empty_cond_having_non_bool_dtypes(self):
410423
# see gh-21947

0 commit comments

Comments
 (0)