【问题标题】:Filter out groups that do not have a sufficient number of rows meeting a condition过滤掉满足条件的行数不足的组
【发布时间】:2017-02-15 14:12:40
【问题描述】:

我有以下熊猫数据框。

import pandas as pd

# Initialize dataframe
df1 = pd.DataFrame(columns=['bar', 'foo'])
df1['bar'] = ['001', '001', '001', '001', '002', '002', '003', '003', '003']
df1['foo'] = [-4, -3, 2, 3, -3, -2, 0, 1, 2]
>>> print df1
   bar  foo
0  001   -4
1  001   -3
2  001    2
3  001    3
4  002   -3
5  002   -2
6  003    0
7  003    1
8  003    2

考虑以下阈值和参数。

# Provide threshold and number of entries above and below threshold
threshold = 0
n_below = 2
n_above = 2

我想创建一个过滤掉 bar 某些值的数据框。我要过滤掉的bar 如下:如果它没有至少n_belowfoo 小于thresholdn_abovefoo 大于threshold

对于上面的例子:

  • 不会过滤掉组bar = 001,因为对于bar = 001,至少有n_below = 2n_below = 2 条目小于threshold = 0,并且至少n_above = 2foo 条目大于@ 987654338@。
  • bar = 002 组将被过滤掉,因为对于 bar = 002foo 的至少 n_above = 2 条目不大于 threshold = 0
  • bar = 003 组将被过滤掉,因为对于bar = 003foo 的至少n_below = 2 条目不小于threshold = 0

所需的输出如下:

# Desired output
   bar  foo
0  001   -4
1  001   -3
2  001    2
3  001    3

我相信这可以通过 GroupBy 和 .count() 来完成,但是我一直无法获得有效的解决方案。我认识到编写一个分两步执行此操作的解决方案可能更简洁:1)首先过滤以满足n_below 条件; 2)然后过滤以满足n_above条件。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    您可以使用groupbyfilter 方法。

    threshold = 0
    n_below = 2
    n_above = 2
    def filter_function(g):
        '''Called by filter, g is the grouped dataframe'''
        l = g['foo']
        return  (sum([x < threshold for x in l]) >= n_below 
                and sum([x > threshold for x in l]) >= n_above)
    
    df.groupby('bar').filter(filter_function)
    
    # gives
        bar foo
    0   1   -4
    1   1   -3
    2   1   2
    3   1   3
    

    Pandas: Filtration

    【讨论】:

      【解决方案2】:

      我认为有一个解决方案:

      threshold = 1
      n_below = 2
      n_above = 2
      
      df1.set_index('bar').loc[ \
          df1.groupby('bar')\
             .apply(lambda df_sub: \
                          (df_sub['foo']<threshold).sum()>=n_below \
                      and (df_sub['foo']>threshold).sum()>=n_above)] \
      .reset_index('bar')
      

      然后它返回

          bar foo
      0   001 -4
      1   001 -3
      2   001 2
      3   001 3
      

      【讨论】:

        【解决方案3】:
        idx = df1.groupby('bar').apply(lambda x: (sum(x['foo'] < threshold) >= n_below) & (sum(x['foo'] > threshold) >= n_above))
        
        print df1.set_index('bar')[idx].reset_index()
        
           bar  foo
        0  001   -4
        1  001   -3
        2  001    2
        3  001    3
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-12-21
          • 1970-01-01
          • 2021-11-30
          • 1970-01-01
          • 2020-01-31
          • 1970-01-01
          • 2020-11-02
          相关资源
          最近更新 更多