【pandas】如何百倍加速实现nlargest同样功能

之前在项目中遇到一个需求,提取出每天多笔数据中的最新一笔数据作为当天的数据呈现出来。例如有如下数据:

     date           tile clus   type  col_type   level  value
2019-05-13 10:39:49	 t2	  ME	ALL	  total      csim   1296
2019-05-13 11:21:41	 t2	  ME	ALL	  total	     csim	1051
2019-05-13 13:19:33	 t2   ME	ALL   total      csim	1051
2019-05-13 17:41:30	 t2   CC	ALL   total	     csim	655
2019-05-13 13:49:11	 t2   CC	ALL	  total      csim   415
2019-05-13 21:55:22	 t2   CC	ALL	  total	     csim   955
2019-05-13 08:43:30	 t2   CC	ALL	  total      csim   304
2019-05-13 01:21:12	 t2   CC 	ALL	  total      csim	415

那么应该选出如下两行,作为2019-05-13的最新数据输出给可视化平台。

     date                clus   type  col_type   level  value
2019-05-13 13:19:33	 t2   ME	ALL   total      csim	1051
2019-05-13 21:55:22	 t2   CC	ALL	  total	     csim   955

可是这个筛选怎么实现呢?插入一列只有日期信息的“date_new”,再用上pandas的nlargest方法即可。代码如下:

     date            date_new     tile clus   type   col_type   level  value    
2019-05-13 21:55:22	 2019-05-13   t2   CC	  ALL	  total	     csim   955     
2019-05-13 17:41:30	 2019-05-13   t2   CC	  ALL     total	     csim	655     
2019-05-13 13:49:11	 2019-05-13   t2   CC	  ALL	  total      csim   415     
2019-05-13 13:19:33	 2019-05-13   t2   ME	  ALL     total      csim	1051    
2019-05-13 11:21:41	 2019-05-13   t2   ME	  ALL	  total	     csim	1051    
2019-05-13 10:39:49	 2019-05-13   t2   ME	  ALL	  total      csim   1296    
2019-05-13 08:43:30	 2019-05-13   t2   CC	  ALL	  total      csim   304     
2019-05-13 01:21:12	 2019-05-13   t2   CC 	  ALL	  total      csim	415     

df = df.groupby(["tile", "clus", "type", "col_type", "level""date_new"], as_index=False).apply(lambda x: x.nlargest(1, "date"))

这样做确实可以达到目标,但是performance会比较差。测试了一下,在不到30W的数据集上需要两分钟多一些。经过深入思考做了第一次的优化,pandas操作的慢在很大程度上是因为太多的group组合,所以就尝试把原先的dataframe按“level”的字段拆分开,每一部分的df操作完再append在一起。为什么选择level字段,是因为level栏的种类一共只有三种,而其他的种类多。
经过这一改进,速度可以提升20%,runtime降到一分半钟左右,这个结果似乎并不能令人十分满意。如果有两百万行的数据估计还得需要十几分钟,无法忍受。

因此我们能不能换个角度,绕开group分组,哪怕不再用nlargest了?答案是肯定的。我们的目标是要取每一天最新更新的数据,那么就可以先按date进行排序,然后直接忽略“date”一栏,是不是就变成了只需要保留[“date_new”, “tile”, “clus”, “type”, “col_type”, “level”]最先出现的那一行?实现这一操作非常简单,去重即可:

df.sort_values(by="date", ascending=False, inplace=True)
df.drop_duplicates(subset=["date_new", "tile", "clus", "type", "col_type", "level"], keep="first", inplace=True)

运行时间不到两秒,实现了超过100倍的加速。类似的需求,譬如选择每天最早一笔数据的话,设置keep=“last”就好。

利用简单排序后去重的方法变相实现nlargest的功能,达到了我们想要的performance。很多时候,如果对performance不满意,就可以思考下瓶颈在哪里,如何避开这些瓶颈?换个方式实现,也许会有意想不到的效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值