Skip to content

Commit a30c891

Browse files
jbrockmendelim-vinicius
authored and
im-vinicius
committed
REF: separate Block.pad_or_backfill from interpolate (pandas-dev#53918)
* REF: separate Block.pad_or_backfill from interpolate * fix interp test * mypy fixup
1 parent 6b60a27 commit a30c891

File tree

1 file changed

+50
-74
lines changed

1 file changed

+50
-74
lines changed

pandas/core/internals/blocks.py

+50-74
Original file line numberDiff line numberDiff line change
@@ -1346,32 +1346,44 @@ def fillna(
13461346
def pad_or_backfill(
13471347
self,
13481348
*,
1349-
method: FillnaOptions = "pad",
1349+
method: FillnaOptions,
13501350
axis: AxisInt = 0,
13511351
inplace: bool = False,
13521352
limit: int | None = None,
13531353
limit_area: Literal["inside", "outside"] | None = None,
13541354
downcast: Literal["infer"] | None = None,
13551355
using_cow: bool = False,
1356-
**kwargs,
13571356
) -> list[Block]:
1358-
return self.interpolate(
1357+
if not self._can_hold_na:
1358+
# If there are no NAs, then interpolate is a no-op
1359+
if using_cow:
1360+
return [self.copy(deep=False)]
1361+
return [self] if inplace else [self.copy()]
1362+
1363+
copy, refs = self._get_refs_and_copy(using_cow, inplace)
1364+
1365+
# Dispatch to the PandasArray method.
1366+
# We know self.array_values is a PandasArray bc EABlock overrides
1367+
new_values = cast(PandasArray, self.array_values).pad_or_backfill(
13591368
method=method,
13601369
axis=axis,
1361-
inplace=inplace,
13621370
limit=limit,
13631371
limit_area=limit_area,
1364-
downcast=downcast,
1365-
using_cow=using_cow,
1366-
**kwargs,
1372+
copy=copy,
13671373
)
13681374

1375+
data = extract_array(new_values, extract_numpy=True)
1376+
1377+
nb = self.make_block_same_class(data, refs=refs)
1378+
return nb._maybe_downcast([nb], downcast, using_cow)
1379+
1380+
@final
13691381
def interpolate(
13701382
self,
13711383
*,
1372-
method: FillnaOptions | InterpolateOptions = "pad",
1373-
axis: AxisInt = 0,
1374-
index: Index | None = None,
1384+
method: InterpolateOptions,
1385+
axis: AxisInt,
1386+
index: Index,
13751387
inplace: bool = False,
13761388
limit: int | None = None,
13771389
limit_direction: Literal["forward", "backward", "both"] = "forward",
@@ -1381,6 +1393,10 @@ def interpolate(
13811393
**kwargs,
13821394
) -> list[Block]:
13831395
inplace = validate_bool_kwarg(inplace, "inplace")
1396+
# error: Non-overlapping equality check [...]
1397+
if method == "asfreq": # type: ignore[comparison-overlap]
1398+
# clean_fill_method used to allow this
1399+
missing.clean_fill_method(method)
13841400

13851401
if not self._can_hold_na:
13861402
# If there are no NAs, then interpolate is a no-op
@@ -1389,7 +1405,7 @@ def interpolate(
13891405
return [self] if inplace else [self.copy()]
13901406

13911407
# TODO(3.0): this case will not be reachable once GH#53638 is enforced
1392-
if not _interp_method_is_pad_or_backfill(method) and self.dtype == _dtype_obj:
1408+
if self.dtype == _dtype_obj:
13931409
# only deal with floats
13941410
# bc we already checked that can_hold_na, we don't have int dtype here
13951411
# test_interp_basic checks that we make a copy here
@@ -1414,29 +1430,17 @@ def interpolate(
14141430

14151431
copy, refs = self._get_refs_and_copy(using_cow, inplace)
14161432

1417-
# Dispatch to the PandasArray method.
1418-
# We know self.array_values is a PandasArray bc EABlock overrides
1419-
if _interp_method_is_pad_or_backfill(method):
1420-
# TODO: warn about ignored kwargs, limit_direction, index...?
1421-
new_values = cast(PandasArray, self.array_values).pad_or_backfill(
1422-
method=cast(FillnaOptions, method),
1423-
axis=axis,
1424-
limit=limit,
1425-
limit_area=limit_area,
1426-
copy=copy,
1427-
)
1428-
else:
1429-
assert index is not None # for mypy
1430-
new_values = cast(PandasArray, self.array_values).interpolate(
1431-
method=cast(InterpolateOptions, method),
1432-
axis=axis,
1433-
index=index,
1434-
limit=limit,
1435-
limit_direction=limit_direction,
1436-
limit_area=limit_area,
1437-
copy=copy,
1438-
**kwargs,
1439-
)
1433+
# Dispatch to the EA method.
1434+
new_values = self.array_values.interpolate(
1435+
method=method,
1436+
axis=axis,
1437+
index=index,
1438+
limit=limit,
1439+
limit_direction=limit_direction,
1440+
limit_area=limit_area,
1441+
copy=copy,
1442+
**kwargs,
1443+
)
14401444
data = extract_array(new_values, extract_numpy=True)
14411445

14421446
nb = self.make_block_same_class(data, refs=refs)
@@ -1863,42 +1867,25 @@ def get_values(self, dtype: DtypeObj | None = None) -> np.ndarray:
18631867
def values_for_json(self) -> np.ndarray:
18641868
return np.asarray(self.values)
18651869

1866-
def interpolate(
1870+
@final
1871+
def pad_or_backfill(
18671872
self,
18681873
*,
1869-
method: FillnaOptions | InterpolateOptions = "pad",
1870-
index: Index | None = None,
1871-
axis: int = 0,
1874+
method: FillnaOptions,
1875+
axis: AxisInt = 0,
18721876
inplace: bool = False,
18731877
limit: int | None = None,
1874-
fill_value=None,
1878+
limit_area: Literal["inside", "outside"] | None = None,
1879+
downcast: Literal["infer"] | None = None,
18751880
using_cow: bool = False,
1876-
**kwargs,
1877-
):
1881+
) -> list[Block]:
18781882
values = self.values
1879-
1880-
if not _interp_method_is_pad_or_backfill(method):
1881-
imeth = cast(InterpolateOptions, method)
1882-
return super().interpolate(
1883-
method=imeth,
1884-
index=index,
1885-
axis=axis,
1886-
inplace=inplace,
1887-
limit=limit,
1888-
fill_value=fill_value,
1889-
using_cow=using_cow,
1890-
**kwargs,
1891-
)
1883+
if values.ndim == 2 and axis == 0:
1884+
# NDArrayBackedExtensionArray.fillna assumes axis=1
1885+
new_values = values.T.fillna(method=method, limit=limit).T
18921886
else:
1893-
meth = cast(FillnaOptions, method)
1894-
if values.ndim == 2 and axis == 0:
1895-
# NDArrayBackedExtensionArray.fillna assumes axis=1
1896-
new_values = values.T.fillna(
1897-
value=fill_value, method=meth, limit=limit
1898-
).T
1899-
else:
1900-
new_values = values.fillna(value=fill_value, method=meth, limit=limit)
1901-
return self.make_block_same_class(new_values)
1887+
new_values = values.fillna(method=method, limit=limit)
1888+
return [self.make_block_same_class(new_values)]
19021889

19031890

19041891
class ExtensionBlock(libinternals.Block, EABackedBlock):
@@ -2553,14 +2540,3 @@ def external_values(values: ArrayLike) -> ArrayLike:
25532540
# TODO(CoW) we should also mark our ExtensionArrays as read-only
25542541

25552542
return values
2556-
2557-
2558-
def _interp_method_is_pad_or_backfill(method: str) -> bool:
2559-
try:
2560-
m = missing.clean_fill_method(method)
2561-
except ValueError:
2562-
m = None
2563-
if method == "asfreq":
2564-
# clean_fill_method used to allow this
2565-
raise
2566-
return m is not None

0 commit comments

Comments
 (0)