Skip to content

Commit 29c6252

Browse files
jbrockmendelim-vinicius
authored and
im-vinicius
committed
REF: implement PandasArray.pad_or_backfill (pandas-dev#53827)
1 parent 8a2d647 commit 29c6252

File tree

5 files changed

+75
-78
lines changed

5 files changed

+75
-78
lines changed

pandas/core/arrays/datetimelike.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,7 +2235,7 @@ def interpolate(
22352235
*,
22362236
method,
22372237
axis: int,
2238-
index: Index | None,
2238+
index: Index,
22392239
limit,
22402240
limit_direction,
22412241
limit_area,
@@ -2255,7 +2255,7 @@ def interpolate(
22552255
else:
22562256
out_data = self._ndarray.copy()
22572257

2258-
missing.interpolate_array_2d(
2258+
missing.interpolate_2d_inplace(
22592259
out_data,
22602260
method=method,
22612261
axis=axis,

pandas/core/arrays/numpy_.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING
3+
from typing import (
4+
TYPE_CHECKING,
5+
Literal,
6+
)
47

58
import numpy as np
69

@@ -32,6 +35,7 @@
3235
from pandas._typing import (
3336
AxisInt,
3437
Dtype,
38+
FillnaOptions,
3539
NpDtype,
3640
Scalar,
3741
Self,
@@ -224,12 +228,42 @@ def _values_for_factorize(self) -> tuple[np.ndarray, float | None]:
224228
fv = np.nan
225229
return self._ndarray, fv
226230

231+
def pad_or_backfill(
232+
self,
233+
*,
234+
method: FillnaOptions,
235+
axis: int,
236+
limit: int | None,
237+
limit_area: Literal["inside", "outside"] | None = None,
238+
copy: bool = True,
239+
) -> Self:
240+
"""
241+
ffill or bfill
242+
"""
243+
if copy:
244+
out_data = self._ndarray.copy()
245+
else:
246+
out_data = self._ndarray
247+
248+
meth = missing.clean_fill_method(method)
249+
missing.pad_or_backfill_inplace(
250+
out_data,
251+
method=meth,
252+
axis=axis,
253+
limit=limit,
254+
limit_area=limit_area,
255+
)
256+
257+
if not copy:
258+
return self
259+
return type(self)._simple_new(out_data, dtype=self.dtype)
260+
227261
def interpolate(
228262
self,
229263
*,
230264
method,
231265
axis: int,
232-
index: Index | None,
266+
index: Index,
233267
limit,
234268
limit_direction,
235269
limit_area,
@@ -246,7 +280,8 @@ def interpolate(
246280
else:
247281
out_data = self._ndarray.copy()
248282

249-
missing.interpolate_array_2d(
283+
# TODO: assert we have floating dtype?
284+
missing.interpolate_2d_inplace(
250285
out_data,
251286
method=method,
252287
axis=axis,

pandas/core/arrays/sparse/array.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
check_array_indexer,
8080
unpack_tuple_and_ellipses,
8181
)
82-
from pandas.core.missing import interpolate_2d
82+
from pandas.core.missing import pad_or_backfill_inplace
8383
from pandas.core.nanops import check_below_min_count
8484

8585
from pandas.io.formats import printing
@@ -764,11 +764,11 @@ def fillna(
764764
stacklevel=find_stack_level(),
765765
)
766766
new_values = np.asarray(self)
767-
# interpolate_2d modifies new_values inplace
768-
# error: Argument "method" to "interpolate_2d" has incompatible type
769-
# "Literal['backfill', 'bfill', 'ffill', 'pad']"; expected
767+
# pad_or_backfill_inplace modifies new_values inplace
768+
# error: Argument "method" to "pad_or_backfill_inplace" has incompatible
769+
# type "Literal['backfill', 'bfill', 'ffill', 'pad']"; expected
770770
# "Literal['pad', 'backfill']"
771-
interpolate_2d(
771+
pad_or_backfill_inplace(
772772
new_values, method=method, limit=limit # type: ignore[arg-type]
773773
)
774774
return type(self)(new_values, fill_value=self.fill_value)

pandas/core/internals/blocks.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,7 @@ def interpolate(
13811381
inplace: bool = False,
13821382
limit: int | None = None,
13831383
limit_direction: Literal["forward", "backward", "both"] = "forward",
1384-
limit_area: str | None = None,
1384+
limit_area: Literal["inside", "outside"] | None = None,
13851385
fill_value: Any | None = None,
13861386
downcast: Literal["infer"] | None = None,
13871387
using_cow: bool = False,
@@ -1439,17 +1439,32 @@ def interpolate(
14391439

14401440
# Dispatch to the PandasArray method.
14411441
# We know self.array_values is a PandasArray bc EABlock overrides
1442-
new_values = cast(PandasArray, self.array_values).interpolate(
1443-
method=method,
1444-
axis=axis,
1445-
index=index,
1446-
limit=limit,
1447-
limit_direction=limit_direction,
1448-
limit_area=limit_area,
1449-
fill_value=fill_value,
1450-
inplace=arr_inplace,
1451-
**kwargs,
1452-
)
1442+
if m is not None:
1443+
if fill_value is not None:
1444+
# similar to validate_fillna_kwargs
1445+
raise ValueError("Cannot pass both fill_value and method")
1446+
1447+
# TODO: warn about ignored kwargs, limit_direction, index...?
1448+
new_values = cast(PandasArray, self.array_values).pad_or_backfill(
1449+
method=method,
1450+
axis=axis,
1451+
limit=limit,
1452+
limit_area=limit_area,
1453+
copy=not arr_inplace,
1454+
)
1455+
else:
1456+
assert index is not None # for mypy
1457+
new_values = cast(PandasArray, self.array_values).interpolate(
1458+
method=method,
1459+
axis=axis,
1460+
index=index,
1461+
limit=limit,
1462+
limit_direction=limit_direction,
1463+
limit_area=limit_area,
1464+
fill_value=fill_value,
1465+
inplace=arr_inplace,
1466+
**kwargs,
1467+
)
14531468
data = new_values._ndarray
14541469

14551470
nb = self.make_block_same_class(data, refs=refs)

pandas/core/missing.py

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -302,60 +302,7 @@ def get_interp_index(method, index: Index) -> Index:
302302
return index
303303

304304

305-
def interpolate_array_2d(
306-
data: np.ndarray,
307-
method: str = "pad",
308-
axis: AxisInt = 0,
309-
index: Index | None = None,
310-
limit: int | None = None,
311-
limit_direction: str = "forward",
312-
limit_area: str | None = None,
313-
fill_value: Any | None = None,
314-
**kwargs,
315-
) -> None:
316-
"""
317-
Wrapper to dispatch to either interpolate_2d or _interpolate_2d_with_fill.
318-
319-
Notes
320-
-----
321-
Alters 'data' in-place.
322-
"""
323-
try:
324-
m = clean_fill_method(method)
325-
except ValueError:
326-
m = None
327-
328-
if m is not None:
329-
if fill_value is not None:
330-
# similar to validate_fillna_kwargs
331-
raise ValueError("Cannot pass both fill_value and method")
332-
333-
interpolate_2d(
334-
data,
335-
method=m,
336-
axis=axis,
337-
limit=limit,
338-
# error: Argument "limit_area" to "interpolate_2d" has incompatible
339-
# type "Optional[str]"; expected "Optional[Literal['inside', 'outside']]"
340-
limit_area=limit_area, # type: ignore[arg-type]
341-
)
342-
else:
343-
assert index is not None # for mypy
344-
345-
_interpolate_2d_with_fill(
346-
data=data,
347-
index=index,
348-
axis=axis,
349-
method=method,
350-
limit=limit,
351-
limit_direction=limit_direction,
352-
limit_area=limit_area,
353-
fill_value=fill_value,
354-
**kwargs,
355-
)
356-
357-
358-
def _interpolate_2d_with_fill(
305+
def interpolate_2d_inplace(
359306
data: np.ndarray, # floating dtype
360307
index: Index,
361308
axis: AxisInt,
@@ -845,7 +792,7 @@ def _interpolate_with_limit_area(
845792
if last is None:
846793
last = len(values)
847794

848-
interpolate_2d(
795+
pad_or_backfill_inplace(
849796
values,
850797
method=method,
851798
limit=limit,
@@ -861,7 +808,7 @@ def _interpolate_with_limit_area(
861808
values[invalid] = np.nan
862809

863810

864-
def interpolate_2d(
811+
def pad_or_backfill_inplace(
865812
values: np.ndarray,
866813
method: Literal["pad", "backfill"] = "pad",
867814
axis: AxisInt = 0,

0 commit comments

Comments
 (0)