Pandas:当组中的值满足所需条件时,从数据中删除组

时间:2016-01-09 07:09:45

标签: python pandas dataframe grouping

我在数据和每个组中都有值的分组,我想检查组中的值是否低于8。如果满足此条件,则从数据集中删除整个组。

请注意我所指的值位于分组列的另一列。

示例输入:

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

输出:

Groups Count
  2      12
  2      15
  2      21 

3 个答案:

答案 0 :(得分:15)

根据您在问题中描述的内容,只要组内至少有一个值低于8,就应删除该组。因此,等效声明是,只要该组中的最小值低于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

答案 1 :(得分:4)

您可以使用isinlocunique通过反转掩码选择子集。最后你可以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

答案 2 :(得分:0)

根据条件创建布尔系列,然后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)