Skip to content

BUG: DataFrame.interpolate failing to return a copy #45791

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 3, 2022
Merged
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/v1.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ Indexing
Missing
^^^^^^^
- Bug in :meth:`Series.fillna` and :meth:`DataFrame.fillna` with ``downcast`` keyword not being respected in some cases where there are no NA values present (:issue:`45423`)
- Bug in :meth:`DataFrame.interpolate` with object-dtype column not returning a copy with ``inplace=False`` (:issue:`45791`)
-

MultiIndex
Expand Down
1 change: 0 additions & 1 deletion pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -6448,7 +6448,6 @@ def fillna(
axis=axis,
limit=limit,
inplace=inplace,
coerce=True,
downcast=downcast,
)
else:
Expand Down
22 changes: 10 additions & 12 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,6 @@ def interpolate(
limit_direction: str = "forward",
limit_area: str | None = None,
fill_value: Any | None = None,
coerce: bool = False,
downcast: str | None = None,
**kwargs,
) -> list[Block]:
Expand All @@ -1034,6 +1033,16 @@ def interpolate(
# If there are no NAs, then interpolate is a no-op
return [self] if inplace else [self.copy()]

try:
m = missing.clean_fill_method(method)
except ValueError:
m = None
if m is None and self.dtype.kind != "f":
# only deal with floats
# bc we already checked that can_hold_na, we dont have int dtype here
# test_interp_basic checks that we make a copy here
return [self] if inplace else [self.copy()]

if self.is_object and self.ndim == 2 and self.shape[0] != 1 and axis == 0:
# split improves performance in ndarray.copy()
return self.split_and_operate(
Expand All @@ -1046,21 +1055,10 @@ def interpolate(
limit_direction,
limit_area,
fill_value,
coerce,
downcast,
**kwargs,
)

try:
m = missing.clean_fill_method(method)
except ValueError:
m = None
if m is None and self.dtype.kind != "f":
# only deal with floats
# bc we already checked that can_hold_na, we dont have int dtype here
# TODO: make a copy if not inplace?
return [self]

data = self.values if inplace else self.values.copy()
data = cast(np.ndarray, data) # bc overridden by ExtensionBlock

Expand Down
32 changes: 32 additions & 0 deletions pandas/tests/frame/methods/test_interpolate.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,38 @@ def test_interp_basic(self):
result = df.interpolate()
tm.assert_frame_equal(result, expected)

# check we didn't operate inplace GH#45791
cvalues = df["C"]._values
dvalues = df["D"].values
assert not np.shares_memory(cvalues, result["C"]._values)
assert not np.shares_memory(dvalues, result["D"]._values)

res = df.interpolate(inplace=True)
assert res is None
tm.assert_frame_equal(df, expected)

# check we DID operate inplace
assert np.shares_memory(df["C"]._values, cvalues)
assert np.shares_memory(df["D"]._values, dvalues)

def test_interp_basic_with_non_range_index(self):
df = DataFrame(
{
"A": [1, 2, np.nan, 4],
"B": [1, 4, 9, np.nan],
"C": [1, 2, 3, 5],
"D": list("abcd"),
}
)
expected = DataFrame(
{
"A": [1.0, 2.0, 3.0, 4.0],
"B": [1.0, 4.0, 9.0, 9.0],
"C": [1, 2, 3, 5],
"D": list("abcd"),
}
)

result = df.set_index("C").interpolate()
expected = df.set_index("C")
expected.loc[3, "A"] = 3
Expand Down