2015-01-09 3 views
5

У меня есть большой набор данных со следующей структуройКак подмножить фрейм данных с использованием Pandas на основе групповых критериев?

User  X 
1  0 
1  0 
2  0 
2  0 
2  1 
3  0 
3  0 

Я хотел бы взять подмножество данных таким образом, что сумма столбца X для каждого пользователя 0. С учетом приведенного выше примера, подмножество должно включают только наблюдения для пользователей 1 и 3 следующим образом

User  X 
1  0 
1  0 
3  0 
3  0 

есть ли способ сделать это с помощью функции GroupBy без группировки данных? Я хочу, чтобы подмножество включало отдельные наблюдения.

+0

Знаем ли мы, что все 'X'> = 0, или вам нужно беспокоиться о' -1, + 1'? – DSM

+0

все значения X> = 0 – roland

ответ

5

DSM's answer, который выбирает строки с использованием булевой маски, хорошо работает, даже если DataFrame имеет не уникальный индекс. Мой метод, который выбирает строки с использованием значений индекса, немного медленнее, когда индекс уникален, а значительно медленнее, когда индекс содержит повторяющиеся значения.

@roland: Пожалуйста, подумайте о принятии ответа DSM.


Вы можете использовать groupby-filter:

In [16]: df.loc[df.groupby('User')['X'].filter(lambda x: x.sum() == 0).index] 
Out[16]: 
    User X 
0  1 0 
1  1 0 
5  3 0 
6  3 0 

Сама по себе GroupBy фильтр просто возвращает это:

In [29]: df.groupby('User')['X'].filter(lambda x: x.sum() == 0) 
Out[29]: 
0 0 
1 0 
5 0 
6 0 
Name: X, dtype: int64 

но вы можете использовать свой индекс,

In [30]: df.groupby('User')['X'].filter(lambda x: x.sum() == 0).index 
Out[30]: Int64Index([0, 1, 5, 6], dtype='int64') 

, чтобы выбрать нужные строки, используя df.loc.


Вот тест я использовал:

In [49]: df2 = pd.concat([df]*10000) # df2 has a non-unique index 

Я Ctrl - C «d это, потому что она занимает слишком много времени, чтобы закончить:

In [50]: %timeit df2.loc[df2.groupby('User')['X'].filter(lambda x: x.sum() == 0).index] 

Когда Я осознал свою ошибку, я создал DataFrame с уникальным индексом:

In [51]: df3 = df2.reset_index()  # this gives df3 a unique index 

In [52]: %timeit df3.loc[df3.groupby('User')['X'].filter(lambda x: x.sum() == 0).index] 
100 loops, best of 3: 13 ms per loop 

In [53]: %timeit df3.loc[df3.groupby("User")["X"].transform(sum) == 0] 
100 loops, best of 3: 11.4 ms per loop 

Это показывает метод в DSM хорошо выполняет даже с не уникальным индексом:

In [54]: %timeit df2.loc[df2.groupby("User")["X"].transform(sum) == 0] 
100 loops, best of 3: 11.2 ms per loop 
8

В качестве альтернативы @ unutbu отвечают, есть также

>>> df.loc[df.groupby("User")["X"].transform(sum) == 0] 
    User X 
0  1 0 
1  1 0 
5  3 0 
6  3 0 

Это создает df -длине логическое Серии для использования в качестве селектора:

>>> df.groupby("User")["X"].transform(sum) == 0 
0  True 
1  True 
2 False 
3 False 
4 False 
5  True 
6  True 
dtype: bool 

transform используется, когда вы хотите «транслировать» результат операции по сокращению группы, поддерживая все элементы каждой группы. Это пригодится.

+0

Можно ли сделать запрос на растяжение, чтобы добавить это в поваренную книгу? (может быть, и в SQL-разделе) - это в основном оператор-оператор – Jeff

+0

Это значительно лучший ответ, чем мой, поскольку он хорошо работает, даже если DataFrame имеет уникальный код. В этом случае мой метод может быть довольно медленным. Выбор с использованием полной булевой маски более устойчив, чем выбор значений индекса. – unutbu