2016-05-22 3 views
2

Я хотел сделать условный подсчет после groupby; например, группой по значениям столбца A, а затем подсчитывать в каждой группе, как часто значение 5 появляется в столбце B.Условный подсчет внутри групп

Если бы я делал это для всего DataFrame, это всего лишь len(df[df['B']==5]). Поэтому я надеялся, что смогу сделать df.groupby('A')[df['B']==5].size(). Но я думаю, что логическое индексирование не работает в пределах GroupBy объектов.

Пример:

import pandas as pd 
df = pd.DataFrame({'A': [0, 4, 0, 4, 4, 6], 'B': [5, 10, 10, 5, 5, 10]}) 
groups = df.groupby('A') 
# some more code 
# in the end, I want to get pd.Series({0: 1, 1: 2, 6: 0}) 

ответ

5

Выберите все строки, в которых B равняется 5, а затем применить groupby/size:

In [43]: df.loc[df['B']==5].groupby('A').size() 
Out[43]: 
A 
0 1 
4 2 
dtype: int64 

В качестве альтернативы, вы можете использовать groupby/agg с пользовательской функции:

In [44]: df.groupby('A')['B'].agg(lambda ser: (ser==5).sum()) 
Out[44]: 
A 
0 1 
4 2 
Name: B, dtype: int64 

Обратите внимание, что, вообще говоря, используя agg с пользовательской функцией будет медленнее, чем с использованием groupby с встроенным методом, таким как size. Поэтому предпочитайте первый вариант над вторым.

In [45]: %timeit df.groupby('A')['B'].agg(lambda ser: (ser==5).sum()) 
1000 loops, best of 3: 927 µs per loop 

In [46]: %timeit df.loc[df['B']==5].groupby('A').size() 
1000 loops, best of 3: 649 µs per loop 

Для включения A значения, где размер равен нулю, вы могли бы проиндексировать результат:

import pandas as pd 
df = pd.DataFrame({'A': [0, 4, 0, 4, 4, 6], 'B': [5, 10, 10, 5, 5, 10]}) 
result = df.loc[df['B'] == 5].groupby('A').size() 
result = result.reindex(df['A'].unique()) 

урожаи

A 
0 1.0 
4 2.0 
6 NaN 
dtype: float64 
+0

При первом подходе, я теряю в группах, где условное число равно нулю (я обновил пример в вопросе, чтобы уточнить). Я не знаю, легко ли изменить его, чтобы справиться с этим. Второй подход работает отлично. – max

+0

uh .. с моей DataFrame, первый подход занимает 41 мс, второй занимает 10 с! Я предполагаю, что это первый подход в конце концов, просто как-то обрабатывать нули отдельно. – max

+0

@max Я предполагаю, что разница во времени возрастает, поскольку 'df [df ['B'] == 5]' становится меньшим подмножеством во всей области данных. Чтобы иметь дело с нулями, вы можете получить уникальные элементы из столбца A с помощью 'a = df [" A "]. Unique()', а затем использовать карту с первым подходом: 'pd.Series (a, index = a) .map (df.loc [df ['B'] == 5] .groupby ('A'). size()). fillna (0) 'Конечно, это не так быстро, как первый подход, но он должен все еще намного быстрее, чем agg/lambda. – ayhan

Смежные вопросы