diff --git a/pandas/core/generic.py b/pandas/core/generic.py index c20b2840a40ab..2e34bc0563210 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -11143,7 +11143,7 @@ def __ixor__(self, other): # Misc methods @final - def _find_valid_index(self, how: str): + def _find_valid_index(self, *, how: str) -> Optional[Hashable]: """ Retrieves the index of the first valid value. @@ -11156,16 +11156,16 @@ def _find_valid_index(self, how: str): ------- idx_first_valid : type of index """ - idxpos = find_valid_index(self._values, how) + idxpos = find_valid_index(self._values, how=how) if idxpos is None: return None return self.index[idxpos] @final @doc(position="first", klass=_shared_doc_kwargs["klass"]) - def first_valid_index(self): + def first_valid_index(self) -> Optional[Hashable]: """ - Return index for {position} non-NA/null value. + Return index for {position} non-NA value or None, if no NA value is found. Returns ------- @@ -11176,12 +11176,12 @@ def first_valid_index(self): If all elements are non-NA/null, returns None. Also returns None for empty {klass}. """ - return self._find_valid_index("first") + return self._find_valid_index(how="first") @final @doc(first_valid_index, position="last", klass=_shared_doc_kwargs["klass"]) - def last_valid_index(self): - return self._find_valid_index("last") + def last_valid_index(self) -> Optional[Hashable]: + return self._find_valid_index(how="last") def _doc_params(cls): diff --git a/pandas/core/missing.py b/pandas/core/missing.py index c2193056cc974..41d7fed66469d 100644 --- a/pandas/core/missing.py +++ b/pandas/core/missing.py @@ -158,7 +158,7 @@ def clean_interp_method(method: str, **kwargs) -> str: return method -def find_valid_index(values, how: str): +def find_valid_index(values, *, how: str) -> Optional[int]: """ Retrieves the index of the first valid value. @@ -256,8 +256,17 @@ def interpolate_1d( # These are sets of index pointers to invalid values... i.e. {0, 1, etc... all_nans = set(np.flatnonzero(invalid)) - start_nans = set(range(find_valid_index(yvalues, "first"))) - end_nans = set(range(1 + find_valid_index(yvalues, "last"), len(valid))) + + first_valid_index = find_valid_index(yvalues, how="first") + if first_valid_index is None: # no nan found in start + first_valid_index = 0 + start_nans = set(range(first_valid_index)) + + last_valid_index = find_valid_index(yvalues, how="last") + if last_valid_index is None: # no nan found in end + last_valid_index = len(yvalues) + end_nans = set(range(1 + last_valid_index, len(valid))) + mid_nans = all_nans - start_nans - end_nans # Like the sets above, preserve_nans contains indices of invalid values, @@ -595,8 +604,12 @@ def _interpolate_with_limit_area( invalid = isna(values) if not invalid.all(): - first = find_valid_index(values, "first") - last = find_valid_index(values, "last") + first = find_valid_index(values, how="first") + if first is None: + first = 0 + last = find_valid_index(values, how="last") + if last is None: + last = len(values) values = interpolate_2d( values,