如何分组并删除包含“-inf”或 "inf" 的行以及之前的所有行

How to groupby and drop rows that include "-inf" or "inf" and all the previous rows

我有以下 df,我想按“分组”进行分组并删除 1) 不仅包括 NaN 的行,还包括所有前面的值或 2) 最后一个之前的行NaN.

group  date     value    
  1    jan2019    NaN
  1    jan2019    3
  1    jan2019    NaN
  1    feb2019    3        
  1    mar2019    4       
  1    mar2019    5        
  2    feb2019    0        
  2    feb2019    NaN       
  2    mar2019    7        
  2    mar2019    4        
  2    apr2019    5        

所需的 df 版本 1。

group  date     value    
  1    feb2019    3        
  1    mar2019    4       
  1    mar2019    5                  
  2    mar2019    7        
  2    mar2019    4        
  2    apr2019    5        

需要 df 版本 2。

group  date     value    
  1    jan2019    NaN
  1    feb2019    3        
  1    mar2019    4       
  1    mar2019    5        
  2    feb2019    NaN            
  2    mar2019    7        
  2    mar2019    4        
  2    apr2019    5        

您可以使用 abs+eq 标记 inf 值。然后也标记它之前的所有值,您可以颠倒系列的顺序并使用 cummax。既然你想跨组做这个工作,你可以使用groupby.cummax。最后,使用布尔掩码通过 loc:

过滤所需的输出
out = df.loc[~df['value'].abs().eq(float('inf'))[::-1].groupby(df['group']).cummax()]

如果要标记的值是 NaN(而不是 inf),那么我们可以改用 isna

out = df.loc[~df['value'].isna()[::-1].groupby(df['group']).cummax()]

输出:

   group     date  value
2      1  feb2019    3.0
3      1  mar2019    4.0
4      1  mar2019    5.0
7      2  mar2019    7.0
8      2  mar2019    4.0
9      2  apr2019    5.0

对于第三个输出,可以使用groupby.shift:

out = df.loc[(~df['value'].isna()[::-1].groupby(df['group']).cummax()).groupby(df['group']).shift().fillna(True)]

输出:

    group     date  value
2       1  jan2019    NaN
3       1  feb2019    3.0
4       1  mar2019    4.0
5       1  mar2019    5.0
7       2  feb2019    NaN
8       2  mar2019    7.0
9       2  mar2019    4.0
10      2  apr2019    5.0

一种更冗长但可能更易读的方法。 .isin 适用于 NaN 和 infs。

def filter_preceding(df, search_values=[np.nan, np.inf, -np.inf]):        
    ind = np.where(df['values'].isin(search_values))[0]
    if len(ind) == 0:
        return df
    max_ind = ind.max()
    return df.iloc[max_ind + 1:, :]

df.groupby('group').apply(filter_preceding).reset_index(drop=True)