过滤掉没有足够数量的行符合条件的组

时间:2017-02-15 04:53:42

标签: python pandas

我有以下pandas数据帧。

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_below的值foo的{​​{1}}值小于threshold且值n_above大于foo的{​​{1}}。

对于上面的例子:

  • 小组threshold不会被过滤掉,因为对于bar = 001,至少有bar = 001n_below = 2小于foo且至少threshold = 0条{1}} n_above = 2大于foo的条目。
  • 群组threshold = 0将被过滤掉,因为对于bar = 002bar = 002n_above = 2个条目至少不超过foo
  • 小组threshold = 0将被过滤掉,因为对于bar = 003,至少有bar = 003n_below = 2小于foo

所需的输出如下:

threshold = 0

我相信这可以通过GroupBy和# Desired output bar foo 0 001 -4 1 001 -3 2 001 2 3 001 3 完成,但是我无法获得有效的解决方案。我认识到编写一个可以分两步完成此操作的解决方案可能更清晰:1)首先满足.count()条件的过滤器; 2)然后过滤以满足n_below条件。

3 个答案:

答案 0 :(得分:3)

您可以使用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

答案 1 :(得分: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

答案 2 :(得分:1)

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