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

У меня есть группы значений в данных и внутри каждой группы, я хотел бы проверить, находится ли значение внутри группы ниже 8. Если это условие выполнено, вся группа удаляется из набора данных.

Обратите внимание, что значение, которое я имею в виду, лежит в другом столбце в столбце группировки.

Пример ввода:

Groups Count
  1      7
  1      11
  1      9 
  2      12
  2      15
  2      21 

Вывод:

Groups Count
  2      12
  2      15
  2      21 

Ответ 1

Основываясь на том, что вы описали в вопросе, если в группе есть хотя бы одно значение, то эта группа должна быть отброшена. Таким образом, эквивалентный оператор состоит в том, что если минимальное значение в этой группе меньше 8, эту группу следует отбросить.

Используя функцию фильтра, фактический код можно свести только к одной строке, пожалуйста, обратитесь к Filtration, вы можете использовать следующий код:

dfnew = df.groupby('Groups').filter(lambda x: x['Count'].min()>8 )
dfnew.reset_index(drop=True, inplace=True) # reset index
dfnew = dfnew[['Groups','Count']] # rearrange the column sequence
print(dfnew)

Output:
   Groups  Count
0       2     12
1       2     15
2       2     21

Ответ 2

Вы можете использовать isin, loc и unique с выбором подмножества с помощью инвертированной маски. Последнее, что вы можете reset_index:

print df

  Groups  Count
0       1      7
1       1     11
2       1      9
3       2     12
4       2     15
5       2     21

print df.loc[df['Count'] < 8, 'Groups'].unique()
[1]

print ~df['Groups'].isin(df.loc[df['Count'] < 8, 'Groups'].unique())

0    False
1    False
2    False
3     True
4     True
5     True
Name: Groups, dtype: bool

df1 = df[~df['Groups'].isin(df.loc[df['Count'] < 8, 'Groups'].unique())]
print df1.reset_index(drop=True)

   Groups  Count
0       2     12
1       2     15
2       2     21

Ответ 3

Создайте логическую серию с вашим условием, затем groupby + transform('any'), чтобы сформировать маску для исходного DataFrame. Это позволяет просто нарезать оригинальный DataFrame.

df[~df.Count.lt(8).groupby(df.Groups).transform('any')]
#   Groups  Count
#3       2     12
#4       2     15
#5       2     21

Хотя синтаксис groupby + filter более прост, он работает намного хуже для большого числа групп, поэтому создание логической маски с transform является предпочтительным. В этом примере улучшение более 1000 раз. Метод .isin работает очень быстро для одного столбца, но при группировании по нескольким столбцам потребуется переключение на объединение.

import pandas as pd
import numpy as np

np.random.seed(123)
N = 50000
df = pd.DataFrame({'Groups': [*range(N//2)]*2,
                   'Count': np.random.randint(0, 1000, N)})

# Double check both are equivalent
(df.groupby('Groups').filter(lambda x: x['Count'].min() >= 8)
  == df[~df.Count.lt(8).groupby(df.Groups).transform('any')]).all().all()
#True

%timeit df.groupby('Groups').filter(lambda x: x['Count'].min() >= 8)
#8.15 s ± 80.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df[~df.Count.lt(8).groupby(df.Groups).transform('any')]
#6.54 ms ± 143 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df[~df['Groups'].isin(df.loc[df['Count'] < 8, 'Groups'].unique())]
#2.88 ms ± 24 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)