由于组太多,Pandas过滤器执行缓慢

时间:2016-07-07 15:55:50

标签: python pandas

我有一个很大的df我需要改变。对于一个计算,我想将数据分组到pborderid上,然后只保留to_wpadr中具有重复值的行。

这是我的df的一个例子。

     pborderid   pbcarid wsid  to_wpadr  colli pk_end_time            
10   76079450  61838497  hp1  523-369p      1 2016-07-01 00:00:38     
11   76079450  61838504  hp1  523-370p      1 2016-07-01 00:00:47     
12   76079450  61838110  hp1  523-372p      1 2016-07-01 00:01:05     
13   76079450  61838225  hp1  523-372p      2 2016-07-01 00:01:13      
14   76079450  61838504  hp1  523-372p      3 2016-07-01 00:01:30     
15   76079450  61838497  hp1  523-373p      1 2016-07-01 00:01:45      
16   76079450  61838504  hp1  523-377p      1 2016-07-01 00:01:55      
17   76079450  61838110  hp1  523-376p      5 2016-07-01 00:02:26      
18   76079450  61838225  hp1  523-376p      1 2016-07-01 00:02:33     
19   76079450  61838497  hp1  523-376p      6 2016-07-01 00:02:55  

使用以下代码可以正常工作,但是当组数增加时,性能会显着降低,最多需要20秒。我认为应该只使用pborderid作为组然后过滤/应用。

ap=ot.groupby(["pborderid","to_wpadr"],sort=False).filter(lambda x: len(x) >1)  

任何人都有任何建议我怎么只能使用一个组列或者我如何才能提高性能呢?

这是想要的结果:

    pborderid   pbcarid wsid  to_wpadr  colli         pk_end_time 
12   76079450  61838110  hp1  523-372p      1 2016-07-01 00:01:05      
13   76079450  61838225  hp1  523-372p      2 2016-07-01 00:01:13        
14   76079450  61838504  hp1  523-372p      3 2016-07-01 00:01:30       
17   76079450  61838110  hp1  523-376p      5 2016-07-01 00:02:26        
18   76079450  61838225  hp1  523-376p      1 2016-07-01 00:02:33        
19   76079450  61838497  hp1  523-376p      6 2016-07-01 00:02:55        

2 个答案:

答案 0 :(得分:2)

我不知道它是否会更快,但您可以尝试使用DataFrame.duplicated仅过滤重复项。

ap = ot[ot.duplicated(subset=['pborderid', 'to_wpadr'], keep=False)]

针对1M行的时间DF:

In [244]: df = pd.concat([df] * 10**5, ignore_index=True)

In [245]: %timeit df.groupby(["pborderid","to_wpadr"],sort=False).filter(lambda x: len(x) >1)
1 loop, best of 3: 313 ms per loop

In [246]: %timeit df[df.duplicated(subset=['pborderid', 'to_wpadr'], keep=False)]
10 loops, best of 3: 129 ms per loop

In [247]: df.shape
Out[247]: (1000000, 6)

答案 1 :(得分:0)

this solution的启发,我们也可以在这种情况下替换groupby操作。实现看起来像这样 -

# Create numerical IDs for relevant columns and a combined one
ID1 = np.unique(df['pborderid'],return_inverse=True)[1]
ID2 = np.unique(df['to_wpadr'],return_inverse=True)[1]
ID = np.column_stack((ID1,ID2))

# Convert to linear indices
lidx = np.ravel_multi_index(ID.T,ID.max(0)+1)

# Get unique IDs for each element based on grouped uniqueness and group counts
_,ID,count = np.unique(lidx,return_inverse=True,return_counts=True)

# Look for counts>1 and collect respective IDs and thus respective rows off df
df_out = df[np.in1d(ID,np.where(count>1)[0])]

示例运行 -

In [233]: df
Out[233]: 
  pborderid to_wpadr  values
0       ID0     John       3
1       ID1    Erick       8
2       ID1     John       3
3       ID1    Mandy       5
4       ID0    Erick       9
5       ID1    Mandy       4
6       ID0     John       6
7       ID1     John       1

In [234]: df_out
Out[234]: 
  pborderid to_wpadr  values
0       ID0     John       3
2       ID1     John       3
3       ID1    Mandy       5
5       ID1    Mandy       4
6       ID0     John       6
7       ID1     John       1

我的运行时测试似乎没有表明这种方法比其他解决方案中列出的groupby方法有任何改进。所以,似乎df.groupby似乎是首选方式!