@@ -1165,6 +1165,27 @@ def _apply_filter(self, indices, dropna):
1165
1165
OutputFrameOrSeries = TypeVar ("OutputFrameOrSeries" , bound = NDFrame )
1166
1166
1167
1167
1168
+ def get_loc_notna (obj : "Series" , * , loc : int ):
1169
+ """Find the value in position ``loc`` after filtering ``obj`` for nan values.
1170
+
1171
+ if ``obj`` is empty or has only nan values, np.nan er returned.
1172
+
1173
+ Examples
1174
+ --------
1175
+ >>> ser = pd.Series([np.nan, np.nan, 1, 2, np.nan])
1176
+ >>> get_loc_notna(ser, loc=0) # get first non-na
1177
+ 1
1178
+ >>> get_loc_notna(ser, loc=-1) # get last non-na
1179
+ 2
1180
+ """
1181
+ x = obj .to_numpy ()
1182
+ x = x [notna (x )]
1183
+
1184
+ if len (x ) == 0 :
1185
+ return np .nan
1186
+ return x [loc ]
1187
+
1188
+
1168
1189
class GroupBy (_GroupBy [FrameOrSeries ]):
1169
1190
"""
1170
1191
Class for grouping and aggregating relational data.
@@ -1510,26 +1531,15 @@ def max(self, numeric_only: bool = False, min_count: int = -1):
1510
1531
numeric_only = numeric_only , min_count = min_count , alias = "max" , npfunc = np .max
1511
1532
)
1512
1533
1513
- @staticmethod
1514
- def _get_loc (x , axis : int = 0 , * , loc : int ):
1515
- """Helper function for first/last item that isn't NA.
1516
- """
1517
-
1518
- def get_loc_notna (x , loc : int ):
1519
- x = x .to_numpy ()
1520
- x = x [notna (x )]
1521
- if len (x ) == 0 :
1522
- return np .nan
1523
- return x [loc ]
1524
-
1525
- if isinstance (x , DataFrame ):
1526
- return x .apply (get_loc_notna , axis = axis , loc = loc )
1527
- else :
1528
- return get_loc_notna (x , loc = loc )
1529
-
1530
1534
@doc (_groupby_agg_method_template , fname = "first" , no = False , mc = - 1 )
1531
1535
def first (self , numeric_only : bool = False , min_count : int = - 1 ):
1532
- first_compat = partial (self ._get_loc , loc = 0 )
1536
+ def first_compat (x , axis : int = 0 ):
1537
+ """Helper function for first item that isn't NA.
1538
+ """
1539
+ if isinstance (x , DataFrame ):
1540
+ return x .apply (get_loc_notna , axis = axis , loc = 0 )
1541
+ else :
1542
+ return get_loc_notna (x , loc = 0 )
1533
1543
1534
1544
return self ._agg_general (
1535
1545
numeric_only = numeric_only ,
@@ -1540,7 +1550,13 @@ def first(self, numeric_only: bool = False, min_count: int = -1):
1540
1550
1541
1551
@doc (_groupby_agg_method_template , fname = "last" , no = False , mc = - 1 )
1542
1552
def last (self , numeric_only : bool = False , min_count : int = - 1 ):
1543
- last_compat = partial (self ._get_loc , loc = - 1 )
1553
+ def last_compat (x , axis : int = 0 ):
1554
+ """Helper function for last item that isn't NA.
1555
+ """
1556
+ if isinstance (x , DataFrame ):
1557
+ return x .apply (get_loc_notna , axis = axis , loc = - 1 )
1558
+ else :
1559
+ return get_loc_notna (x , loc = - 1 )
1544
1560
1545
1561
return self ._agg_general (
1546
1562
numeric_only = numeric_only ,
0 commit comments