Skip to content

Commit 7e66493

Browse files
authored
REF: move interpolate validation to core.missing (pandas-dev#53580)
* REF: move interpolate validation to core.missing * lint fixup
1 parent 8b6a244 commit 7e66493

File tree

3 files changed

+59
-43
lines changed

3 files changed

+59
-43
lines changed

pandas/core/generic.py

+6-42
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
arraylike,
144144
common,
145145
indexing,
146+
missing,
146147
nanops,
147148
sample,
148149
)
@@ -7907,20 +7908,7 @@ def interpolate(
79077908
"Only `method=linear` interpolation is supported on MultiIndexes."
79087909
)
79097910

7910-
# Set `limit_direction` depending on `method`
7911-
if limit_direction is None:
7912-
limit_direction = (
7913-
"backward" if method in ("backfill", "bfill") else "forward"
7914-
)
7915-
else:
7916-
if method in ("pad", "ffill") and limit_direction != "forward":
7917-
raise ValueError(
7918-
f"`limit_direction` must be 'forward' for method `{method}`"
7919-
)
7920-
if method in ("backfill", "bfill") and limit_direction != "backward":
7921-
raise ValueError(
7922-
f"`limit_direction` must be 'backward' for method `{method}`"
7923-
)
7911+
limit_direction = missing.infer_limit_direction(limit_direction, method)
79247912

79257913
if obj.ndim == 2 and np.all(obj.dtypes == np.dtype("object")):
79267914
raise TypeError(
@@ -7929,32 +7917,8 @@ def interpolate(
79297917
"column to a numeric dtype."
79307918
)
79317919

7932-
# create/use the index
7933-
if method == "linear":
7934-
# prior default
7935-
index = Index(np.arange(len(obj.index)))
7936-
else:
7937-
index = obj.index
7938-
methods = {"index", "values", "nearest", "time"}
7939-
is_numeric_or_datetime = (
7940-
is_numeric_dtype(index.dtype)
7941-
or isinstance(index.dtype, DatetimeTZDtype)
7942-
or lib.is_np_dtype(index.dtype, "mM")
7943-
)
7944-
if method not in methods and not is_numeric_or_datetime:
7945-
raise ValueError(
7946-
"Index column must be numeric or datetime type when "
7947-
f"using {method} method other than linear. "
7948-
"Try setting a numeric or datetime index column before "
7949-
"interpolating."
7950-
)
7920+
index = missing.get_interp_index(method, obj.index)
79517921

7952-
if isna(index).any():
7953-
raise NotImplementedError(
7954-
"Interpolation with NaNs in the index "
7955-
"has not been implemented. Try filling "
7956-
"those NaNs before interpolating."
7957-
)
79587922
new_data = obj._mgr.interpolate(
79597923
method=method,
79607924
axis=axis,
@@ -8140,13 +8104,13 @@ def asof(self, where, subset=None):
81408104
locs = self.index.asof_locs(where, ~(nulls._values))
81418105

81428106
# mask the missing
8143-
missing = locs == -1
8107+
mask = locs == -1
81448108
data = self.take(locs)
81458109
data.index = where
8146-
if missing.any():
8110+
if mask.any():
81478111
# GH#16063 only do this setting when necessary, otherwise
81488112
# we'd cast e.g. bools to floats
8149-
data.loc[missing] = np.nan
8113+
data.loc[mask] = np.nan
81508114
return data if is_list else data.iloc[-1]
81518115

81528116
# ----------------------------------------------------------------------

pandas/core/internals/blocks.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1350,7 +1350,7 @@ def interpolate(
13501350
index: Index | None = None,
13511351
inplace: bool = False,
13521352
limit: int | None = None,
1353-
limit_direction: str = "forward",
1353+
limit_direction: Literal["forward", "backward", "both"] = "forward",
13541354
limit_area: str | None = None,
13551355
fill_value: Any | None = None,
13561356
downcast: Literal["infer"] | None = None,

pandas/core/missing.py

+52
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
from pandas.core.dtypes.cast import infer_dtype_from
3434
from pandas.core.dtypes.common import (
3535
is_array_like,
36+
is_numeric_dtype,
3637
is_numeric_v_string_like,
3738
is_object_dtype,
3839
needs_i8_conversion,
3940
)
41+
from pandas.core.dtypes.dtypes import DatetimeTZDtype
4042
from pandas.core.dtypes.missing import (
4143
is_valid_na_for_dtype,
4244
isna,
@@ -225,6 +227,56 @@ def find_valid_index(how: str, is_valid: npt.NDArray[np.bool_]) -> int | None:
225227
return idxpos # type: ignore[return-value]
226228

227229

230+
def infer_limit_direction(limit_direction, method):
231+
# Set `limit_direction` depending on `method`
232+
if limit_direction is None:
233+
if method in ("backfill", "bfill"):
234+
limit_direction = "backward"
235+
else:
236+
limit_direction = "forward"
237+
else:
238+
if method in ("pad", "ffill") and limit_direction != "forward":
239+
raise ValueError(
240+
f"`limit_direction` must be 'forward' for method `{method}`"
241+
)
242+
if method in ("backfill", "bfill") and limit_direction != "backward":
243+
raise ValueError(
244+
f"`limit_direction` must be 'backward' for method `{method}`"
245+
)
246+
return limit_direction
247+
248+
249+
def get_interp_index(method, index: Index) -> Index:
250+
# create/use the index
251+
if method == "linear":
252+
# prior default
253+
from pandas import Index
254+
255+
index = Index(np.arange(len(index)))
256+
else:
257+
methods = {"index", "values", "nearest", "time"}
258+
is_numeric_or_datetime = (
259+
is_numeric_dtype(index.dtype)
260+
or isinstance(index.dtype, DatetimeTZDtype)
261+
or lib.is_np_dtype(index.dtype, "mM")
262+
)
263+
if method not in methods and not is_numeric_or_datetime:
264+
raise ValueError(
265+
"Index column must be numeric or datetime type when "
266+
f"using {method} method other than linear. "
267+
"Try setting a numeric or datetime index column before "
268+
"interpolating."
269+
)
270+
271+
if isna(index).any():
272+
raise NotImplementedError(
273+
"Interpolation with NaNs in the index "
274+
"has not been implemented. Try filling "
275+
"those NaNs before interpolating."
276+
)
277+
return index
278+
279+
228280
def interpolate_array_2d(
229281
data: np.ndarray,
230282
method: str = "pad",

0 commit comments

Comments
 (0)