Skip to content

Commit 013df9d

Browse files
committed
BUG: Fixed first last valid index (#20499)
Removed old methods from Series and DF Added new methods into NDFrame Created new convenient method _find_first_valid
1 parent 2eefe5a commit 013df9d

File tree

3 files changed

+31
-51
lines changed

3 files changed

+31
-51
lines changed

pandas/core/frame.py

-25
Original file line numberDiff line numberDiff line change
@@ -5015,31 +5015,6 @@ def update(self, other, join='left', overwrite=True, filter_func=None,
50155015

50165016
self[col] = expressions.where(mask, this, that)
50175017

5018-
# ----------------------------------------------------------------------
5019-
# Misc methods
5020-
5021-
def _get_valid_indices(self):
5022-
is_valid = self.count(1) > 0
5023-
return self.index[is_valid]
5024-
5025-
@Appender(_shared_docs['valid_index'] % {
5026-
'position': 'first', 'klass': 'DataFrame'})
5027-
def first_valid_index(self):
5028-
if len(self) == 0:
5029-
return None
5030-
5031-
valid_indices = self._get_valid_indices()
5032-
return valid_indices[0] if len(valid_indices) else None
5033-
5034-
@Appender(_shared_docs['valid_index'] % {
5035-
'position': 'last', 'klass': 'DataFrame'})
5036-
def last_valid_index(self):
5037-
if len(self) == 0:
5038-
return None
5039-
5040-
valid_indices = self._get_valid_indices()
5041-
return valid_indices[-1] if len(valid_indices) else None
5042-
50435018
# ----------------------------------------------------------------------
50445019
# Data reshaping
50455020

pandas/core/generic.py

+31
Original file line numberDiff line numberDiff line change
@@ -8763,6 +8763,37 @@ def transform(self, func, *args, **kwargs):
87638763
scalar : type of index
87648764
"""
87658765

8766+
def _find_first_valid(self, direction=1):
8767+
if len(self) == 0: # early stop
8768+
return None
8769+
is_valid = ~self.isna()
8770+
8771+
if self.ndim == 2:
8772+
is_valid = is_valid.any(1) # reduce axis 1
8773+
8774+
if direction == 1:
8775+
i = is_valid.idxmax()
8776+
if not is_valid[i]:
8777+
return None
8778+
else:
8779+
return i
8780+
elif direction == -1:
8781+
i = is_valid.values[::-1].argmax()
8782+
if not is_valid.iat[len(self) - i - 1]:
8783+
return None
8784+
else:
8785+
return self.index[len(self) - i - 1]
8786+
8787+
@Appender(_shared_docs['valid_index'] % {'position': 'first',
8788+
'klass': 'NDFrame'})
8789+
def first_valid_index(self):
8790+
return self._find_first_valid(1)
8791+
8792+
@Appender(_shared_docs['valid_index'] % {'position': 'last',
8793+
'klass': 'NDFrame'})
8794+
def last_valid_index(self):
8795+
return self._find_first_valid(-1)
8796+
87668797

87678798
def _doc_parms(cls):
87688799
"""Return a tuple of the doc parms."""

pandas/core/series.py

-26
Original file line numberDiff line numberDiff line change
@@ -3887,32 +3887,6 @@ def valid(self, inplace=False, **kwargs):
38873887
"Use .dropna instead.", FutureWarning, stacklevel=2)
38883888
return self.dropna(inplace=inplace, **kwargs)
38893889

3890-
@Appender(generic._shared_docs['valid_index'] % {
3891-
'position': 'first', 'klass': 'Series'})
3892-
def first_valid_index(self):
3893-
if len(self) == 0:
3894-
return None
3895-
3896-
mask = isna(self._values)
3897-
i = mask.argmin()
3898-
if mask[i]:
3899-
return None
3900-
else:
3901-
return self.index[i]
3902-
3903-
@Appender(generic._shared_docs['valid_index'] % {
3904-
'position': 'last', 'klass': 'Series'})
3905-
def last_valid_index(self):
3906-
if len(self) == 0:
3907-
return None
3908-
3909-
mask = isna(self._values[::-1])
3910-
i = mask.argmin()
3911-
if mask[i]:
3912-
return None
3913-
else:
3914-
return self.index[len(self) - i - 1]
3915-
39163890
# ----------------------------------------------------------------------
39173891
# Time series-oriented methods
39183892

0 commit comments

Comments
 (0)