对pandas数据框进行分组和筛选。

3
OID,TYPE,ResponseType
100,mod,ok
100,mod,ok
101,mod,ok
101,mod,ok
101,mod,ok
101,mod,ok
101,mod,no
102,mod,ok
102,mod,ok2
103,mod,ok
103,mod,no2

我希望删除所有响应为no或no2的OID。

我尝试过:

dfnew = df.groupby('OID').filter(lambda x: ((x['ResponseType']=='no') | x['ResponseType']=='no2')).any() )

但我得到了SyntaxError:无效的语法

另一种方法可能是创建一个包含所有要过滤的OID的set,然后使用它们来过滤df。该df有5000000行!

期望输出

OID,TYPE,ResponseType
100,mod,ok
100,mod,ok

102,mod,ok
102,mod,ok2
2个回答

2

您需要为反转布尔掩码添加一个(~,但这样做非常缓慢:

dfnew = df.groupby('OID').filter(lambda x: ~((x['ResponseType']=='no') | 
                                             (x['ResponseType']=='no2')).any() )
                                          #here

print (dfnew)
   OID TYPE ResponseType
0  100  mod           ok
1  100  mod           ok
7  102  mod           ok
8  102  mod          ok2

另一种更快的解决方案是使用布尔索引和双重isin

oids = df.loc[df['ResponseType'].isin(['no','no2']), 'OID']
print (oids)
6     101
10    103
Name: OID, dtype: int64

dfnew = df[~df['OID'].isin(oids)]
print (dfnew)
   OID TYPE ResponseType
0  100  mod           ok
1  100  mod           ok
7  102  mod           ok
8  102  mod          ok2

使用 unique 函数的解决方案稍微慢一些:
oids = df.loc[df['ResponseType'].isin(['no','no2']), 'OID'].unique()
print (oids)
[101 103]

时间安排:

np.random.seed(123)
N = 1000000
df = pd.DataFrame({'ResponseType': np.random.choice(['ok','ok2','no2', 'no'], N),
                   'TYPE':['mod'] * N,
                   'OID':np.random.randint(100000, size=N)})
print (df)

In [285]: %timeit (df[~df['OID'].isin(df.loc[df['ResponseType'].isin(['no','no2']), 'OID'])])
10 loops, best of 3: 67.2 ms per loop

In [286]: %timeit (df[~df['OID'].isin(df.loc[df['ResponseType'].isin(['no','no2']), 'OID'].unique())])
10 loops, best of 3: 69.5 ms per loop

#zipa solution
In [287]: %timeit (df[~df['OID'].isin(df[df['ResponseType'].isin(['no', 'no2'])]['OID'])])
10 loops, best of 3: 91.5 ms per loop

#groupby solution :(
In [288]: %timeit (df.groupby('OID').filter(lambda x: ~((x['ResponseType']=='no') |  (x['ResponseType']=='no2')).any() ))
1 loop, best of 3: 1min 54s per loop

一旦我筛选出要消除的 OID,我该如何将它们从主数据框中删除?df[df['OID'] not in oids] - pythonRcpp
我认为布尔索引 - df[~df['OID'].isin(oids)] - jezrael
谢谢,所有这些过程中,我如何确保顺序没有错位。它应该保留原始数据框的顺序。 - pythonRcpp
是的,它创建布尔掩码——TrueFalse值,并通过它进行过滤。 - jezrael

0
你可以这样做:
df[~df['OID'].isin(df[df['ResponseType'].isin(['no', 'no2'])]['OID'])]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接