diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst index 039a86da0541e..8bb924f4003a2 100644 --- a/doc/source/whatsnew/v1.5.0.rst +++ b/doc/source/whatsnew/v1.5.0.rst @@ -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 diff --git a/pandas/core/generic.py b/pandas/core/generic.py index a497475ebd182..fcc7e915e2b57 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -6448,7 +6448,6 @@ def fillna( axis=axis, limit=limit, inplace=inplace, - coerce=True, downcast=downcast, ) else: diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 2c1724adf0300..15aa97b065446 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -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]: @@ -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( @@ -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 diff --git a/pandas/tests/frame/methods/test_interpolate.py b/pandas/tests/frame/methods/test_interpolate.py index 6566d426d9a6b..98f9d2670074d 100644 --- a/pandas/tests/frame/methods/test_interpolate.py +++ b/pandas/tests/frame/methods/test_interpolate.py @@ -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