Skip to content

Commit 6c49da7

Browse files
jbrockmendelmeeseeksmachine
authored andcommitted
Backport PR pandas-dev#48254: REF: avoid FutureWarning about using deprecates loc.__setitem__ non-inplace usage
1 parent 5987b63 commit 6c49da7

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
@@ -6869,14 +6869,48 @@ def fillna(
68696869
if not is_dict
68706870
else downcast.get(k) # type: ignore[union-attr]
68716871
)
6872-
# GH47649
6873-
result.loc[:, k] = (
6874-
result[k].fillna(v, limit=limit, downcast=downcast_k).values
6875-
)
6876-
# TODO: result.loc[:, k] = result.loc[:, k].fillna(
6877-
# v, limit=limit, downcast=downcast_k
6878-
# )
6879-
# Revert when GH45751 is fixed
6872+
6873+
res_k = result[k].fillna(v, limit=limit, downcast=downcast_k)
6874+
6875+
if not inplace:
6876+
result[k] = res_k
6877+
else:
6878+
# We can write into our existing column(s) iff dtype
6879+
# was preserved.
6880+
if isinstance(res_k, ABCSeries):
6881+
# i.e. 'k' only shows up once in self.columns
6882+
if res_k.dtype == result[k].dtype:
6883+
result.loc[:, k] = res_k
6884+
else:
6885+
# Different dtype -> no way to do inplace.
6886+
result[k] = res_k
6887+
else:
6888+
# see test_fillna_dict_inplace_nonunique_columns
6889+
locs = result.columns.get_loc(k)
6890+
if isinstance(locs, slice):
6891+
locs = np.arange(self.shape[1])[locs]
6892+
elif (
6893+
isinstance(locs, np.ndarray) and locs.dtype.kind == "b"
6894+
):
6895+
locs = locs.nonzero()[0]
6896+
elif not (
6897+
isinstance(locs, np.ndarray) and locs.dtype.kind == "i"
6898+
):
6899+
# Should never be reached, but let's cover our bases
6900+
raise NotImplementedError(
6901+
"Unexpected get_loc result, please report a bug at "
6902+
"https://github.com/pandas-dev/pandas"
6903+
)
6904+
6905+
for i, loc in enumerate(locs):
6906+
res_loc = res_k.iloc[:, i]
6907+
target = self.iloc[:, loc]
6908+
6909+
if res_loc.dtype == target.dtype:
6910+
result.iloc[:, loc] = res_loc
6911+
else:
6912+
result.isetitem(loc, res_loc)
6913+
68806914
return result if not inplace else None
68816915

68826916
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)