Skip to content

Commit a1e4987

Browse files
authored
REF: avoid FutureWarning about using deprecates loc.__setitem__ non-inplace usage (#48254)
* REF: avoid FutureWarning about using deprecates loc.__setitem__ non-inplace usage * fix ArrayManager tests * fix test with CoW
1 parent 003f125 commit a1e4987

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

pandas/core/generic.py

+42-8
Original file line numberDiff line numberDiff line change
@@ -6885,14 +6885,48 @@ def fillna(
68856885
if not is_dict
68866886
else downcast.get(k) # type: ignore[union-attr]
68876887
)
6888-
# GH47649
6889-
result.loc[:, k] = (
6890-
result[k].fillna(v, limit=limit, downcast=downcast_k).values
6891-
)
6892-
# TODO: result.loc[:, k] = result.loc[:, k].fillna(
6893-
# v, limit=limit, downcast=downcast_k
6894-
# )
6895-
# Revert when GH45751 is fixed
6888+
6889+
res_k = result[k].fillna(v, limit=limit, downcast=downcast_k)
6890+
6891+
if not inplace:
6892+
result[k] = res_k
6893+
else:
6894+
# We can write into our existing column(s) iff dtype
6895+
# was preserved.
6896+
if isinstance(res_k, ABCSeries):
6897+
# i.e. 'k' only shows up once in self.columns
6898+
if res_k.dtype == result[k].dtype:
6899+
result.loc[:, k] = res_k
6900+
else:
6901+
# Different dtype -> no way to do inplace.
6902+
result[k] = res_k
6903+
else:
6904+
# see test_fillna_dict_inplace_nonunique_columns
6905+
locs = result.columns.get_loc(k)
6906+
if isinstance(locs, slice):
6907+
locs = np.arange(self.shape[1])[locs]
6908+
elif (
6909+
isinstance(locs, np.ndarray) and locs.dtype.kind == "b"
6910+
):
6911+
locs = locs.nonzero()[0]
6912+
elif not (
6913+
isinstance(locs, np.ndarray) and locs.dtype.kind == "i"
6914+
):
6915+
# Should never be reached, but let's cover our bases
6916+
raise NotImplementedError(
6917+
"Unexpected get_loc result, please report a bug at "
6918+
"https://github.com/pandas-dev/pandas"
6919+
)
6920+
6921+
for i, loc in enumerate(locs):
6922+
res_loc = res_k.iloc[:, i]
6923+
target = self.iloc[:, loc]
6924+
6925+
if res_loc.dtype == target.dtype:
6926+
result.iloc[:, loc] = res_loc
6927+
else:
6928+
result.isetitem(loc, res_loc)
6929+
68966930
return result if not inplace else None
68976931

68986932
elif not is_list_like(value):

pandas/tests/frame/methods/test_fillna.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,30 @@
1919

2020

2121
class TestFillNA:
22+
@td.skip_array_manager_not_yet_implemented
23+
def test_fillna_dict_inplace_nonunique_columns(self, using_copy_on_write):
24+
df = DataFrame(
25+
{"A": [np.nan] * 3, "B": [NaT, Timestamp(1), NaT], "C": [np.nan, "foo", 2]}
26+
)
27+
df.columns = ["A", "A", "A"]
28+
orig = df[:]
29+
30+
df.fillna({"A": 2}, inplace=True)
31+
# The first and third columns can be set inplace, while the second cannot.
32+
33+
expected = DataFrame(
34+
{"A": [2.0] * 3, "B": [2, Timestamp(1), 2], "C": [2, "foo", 2]}
35+
)
36+
expected.columns = ["A", "A", "A"]
37+
tm.assert_frame_equal(df, expected)
38+
39+
# TODO: what's the expected/desired behavior with CoW?
40+
if not using_copy_on_write:
41+
assert tm.shares_memory(df.iloc[:, 0], orig.iloc[:, 0])
42+
assert not tm.shares_memory(df.iloc[:, 1], orig.iloc[:, 1])
43+
if not using_copy_on_write:
44+
assert tm.shares_memory(df.iloc[:, 2], orig.iloc[:, 2])
45+
2246
@td.skip_array_manager_not_yet_implemented
2347
def test_fillna_on_column_view(self, using_copy_on_write):
2448
# GH#46149 avoid unnecessary copies
@@ -287,7 +311,6 @@ def test_fillna_downcast_noop(self, frame_or_series):
287311
res3 = obj2.fillna("foo", downcast=np.dtype(np.int32))
288312
tm.assert_equal(res3, expected)
289313

290-
@td.skip_array_manager_not_yet_implemented
291314
@pytest.mark.parametrize("columns", [["A", "A", "B"], ["A", "A"]])
292315
def test_fillna_dictlike_value_duplicate_colnames(self, columns):
293316
# GH#43476

0 commit comments

Comments
 (0)