2016-06-02 5 views
3

У меня есть dataframe с различными столбцами и хотел бы вычислить средние значения групп при условии, что каждая группа имеет минимальное количество действительных членов. Я попробовал следующее, используя groupby, filter и mean. Кажется, это работает, но мне интересно, есть ли более эффективное решение?pandas groupby: эффективная условная агрегация?

import pandas as pd 
import numpy as np 

df = pd.DataFrame({'id' : ['one', 'one', 'two', 'three', 'two', 
          'two', 'two', 'one', 'three', 'one'], 
        'idprop' : [1., 1., 2., 3., 2., # property corresponding to id 
           2., 2., 1., 3., 1.], 
        'x' : np.random.randn(10), 
        'y' : np.random.randn(10)}) 

# set a couple of x values to nan 
s = df['x'].values 
s[s < -0.6] = np.nan 
df['x'] = s 

g = df.groupby('id', sort=False) 
# filter out small group(s) with less than 3 valid values in x 
# result is a new dataframe 
dff = g.filter(lambda d: d['x'].count() >= 3) 

# this means we must group again to obtain the mean value of each filtered group 
result = dff.groupby('id').mean() 
print result 
print type(result) 

Существует связанный вопрос на how to get multiple conditional operations after a Pandas groupby?, который, однако, только «фильтры» по значениям строк не по числу элементов группы. Переустроенные в мой код, это будет:

res2 = g.agg({'x': lambda d: df.loc[d.index, 'x'][d >= -0.6].sum()}) 

В качестве побочного вопроса: существует ли более эффективный способ, чтобы установить значения выше или ниже заданного порогового значения для NaN? Мой мозг искривился, когда я попробовал это, используя loc.

+1

Ответьте на свой вопрос: 'df.loc [df ['x'] <-0.6, 'x'] = np.nan' – IanS

+0

У меня возникает соблазн сказать, что' df.filter (...) .groupby ('id'). mean() '- самый эффективный способ получить то, что вы хотите. – jonchar

ответ

1

Вы можете добиться этого с помощью функции GroupBy apply:

def mean_cond(dfg): 
    if dfg['x'].count() >= 3: 
     return dfg.mean() 
    return None 

print df.groupby('id').apply(mean_cond).dropna() 

Преимущество здесь состоит в том, что процесс группирования выполняется только один раз, что может быть более эффективным, чем при запуске другой GroupBy после фильтра. Возможно, единственная проблема заключается в том, что это вызывает группы, которые не соответствуют критериям, которые должны быть представлены как NaN в результирующей таблице. Это легко решить, добавив команду dropna в конец.