2017-02-15 5 views
1

Рассмотрите схему данных, как показано ниже.Python Pandas groupby: фильтр в соответствии с условием на значения

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'] = [-1, 0, 2, 3, -8, 1, 0, 1, 2] 
>>> print df1 
    bar foo 
0 001 -1 
1 001 0 
2 001 2 
3 001 3 
4 002 -8 
5 002 1 
6 003 0 
7 003 1 
8 003 2 

# Lower and upper bound for desired range 
lower_bound = -5 
upper_bound = 5 

Я хотел бы использовать GroupBy в панд, чтобы вернуть dataframe, который фильтрует строки с bar что соответствует условию. В частности, я хотел бы отфильтровать строки с bar, если одно из значений foo для этого bar не находится между lower_bound и upper_bound.

В приведенном выше примере, строки с bar = 002 должны быть отфильтрованы, так как не все строки с bar = 002 содержать значение foo между -5 и 5 (а именно, когда индекс строки 4 содержит foo = -8). Желаемый результат для этого примера следующий.

# Desired output 
    bar foo 
0 001 -1 
1 001 0 
2 001 2 
3 001 3 
6 003 0 
7 003 1 
8 003 2 

Я пробовал следующий подход.

# Attempted solution 
grouped = df1.groupby('bar')['foo'] 
grouped.filter(lambda x: x < lower_bound or x > upper_bound) 

Однако это дает TypeError: the filter must return a boolean result. Кроме того, этот подход может вернуть объект groupby, когда я хочу, чтобы результат возвращал объект dataframe.

ответ

1

Скорее всего, вы не будете использовать and и or но векторизована & и | с pandas, и для Вашего случая, а затем применить all() функции в фильтре построить логическое условие, это держит bar где все соответствующие foo значения находится между lower_bound и UPPER_BOUND:

df1.groupby('bar').filter(lambda x: ((x.foo >= lower_bound) & (x.foo <= upper_bound)).all()) 

# bar foo 
#0 001 -1 
#1 001 0 
#2 001 2 
#3 001 3 
#6 003 0 
#7 003 1 
#8 003 2 
Смежные вопросы