From ed59fa725f1b358bc70ec2a1328e9af69cd6958b Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 4 Nov 2019 11:44:19 -0800 Subject: [PATCH] REF: avoid core.missing dependency on Series --- pandas/core/generic.py | 23 ++++----------------- pandas/core/missing.py | 45 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index cbeee88d75b51..bafc37d478fdb 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -83,6 +83,7 @@ from pandas.core.indexes.period import Period, PeriodIndex import pandas.core.indexing as indexing from pandas.core.internals import BlockManager +from pandas.core.missing import find_valid_index from pandas.core.ops import _align_method_FRAME from pandas.io.formats import format as fmt @@ -10870,27 +10871,11 @@ def _find_valid_index(self, how: str): ------- idx_first_valid : type of index """ - assert how in ["first", "last"] - if len(self) == 0: # early stop + idxpos = find_valid_index(self._values, how) + if idxpos is None: return None - is_valid = ~self.isna() - - if self.ndim == 2: - is_valid = is_valid.any(1) # reduce axis 1 - - if how == "first": - idxpos = is_valid.values[::].argmax() - - if how == "last": - idxpos = len(self) - 1 - is_valid.values[::-1].argmax() - - chk_notna = is_valid.iat[idxpos] - idx = self.index[idxpos] - - if not chk_notna: - return None - return idx + return self.index[idxpos] @Appender( _shared_docs["valid_index"] % {"position": "first", "klass": "Series/DataFrame"} diff --git a/pandas/core/missing.py b/pandas/core/missing.py index 5a1bf6d37b081..c1e63a49a0f0a 100644 --- a/pandas/core/missing.py +++ b/pandas/core/missing.py @@ -128,6 +128,43 @@ def clean_interp_method(method, **kwargs): return method +def find_valid_index(values, how: str): + """ + Retrieves the index of the first valid value. + + Parameters + ---------- + values : ndarray or ExtensionArray + how : {'first', 'last'} + Use this parameter to change between the first or last valid index. + + Returns + ------- + int or None + """ + assert how in ["first", "last"] + + if len(values) == 0: # early stop + return None + + is_valid = ~isna(values) + + if values.ndim == 2: + is_valid = is_valid.any(1) # reduce axis 1 + + if how == "first": + idxpos = is_valid[::].argmax() + + if how == "last": + idxpos = len(values) - 1 - is_valid[::-1].argmax() + + chk_notna = is_valid[idxpos] + + if not chk_notna: + return None + return idxpos + + def interpolate_1d( xvalues, yvalues, @@ -192,14 +229,10 @@ def interpolate_1d( # default limit is unlimited GH #16282 limit = algos._validate_limit(nobs=None, limit=limit) - from pandas import Series - - ys = Series(yvalues) - # These are sets of index pointers to invalid values... i.e. {0, 1, etc... all_nans = set(np.flatnonzero(invalid)) - start_nans = set(range(ys.first_valid_index())) - end_nans = set(range(1 + ys.last_valid_index(), len(valid))) + start_nans = set(range(find_valid_index(yvalues, "first"))) + end_nans = set(range(1 + find_valid_index(yvalues, "last"), len(valid))) mid_nans = all_nans - start_nans - end_nans # Like the sets above, preserve_nans contains indices of invalid values,