干货

您所在的位置:网站首页 数据处理的案例 干货

干货

2023-04-25 13:14| 来源: 网络整理| 查看: 265

本文章主要给大家介绍使用pandas处理数据的技巧,即apply函数的妙用,apply函数用好了计算的速度可以成倍增加,Pandas是为一次性处理整个行或列的矢量化操作而设计的,apply会在内部尝试Cython迭代器,因此速度会提升,如果能够用矢量化的操作,那么速度将会更快。

目录

前言函数的介绍函数的简单应用func参数的理解使用reduce类型的函数result_type参数案例分析背景介绍函数确定程序实现得到输出结果结语1.前言

excel是我们在办公过程中非常常用数据存储和处理的软件,但是有些功能excel在使用的过程中,确实会不如python方便,而且尤其是涉及多个excel之间数据交互,并且需要我们实现一些Vlookup等excel自带函数无法做到的事情时。

当我们需要这样处理数据,并且数据量非常大的时候,我们就可以选择pandas,上篇我已经讲过如何处理时间类型的数据了,在此铺垫之上,本篇讲解如何巧妙的使用pandas模块中的apply函数,来大幅提高数据处理的效率。没有了解过的同学可以先点赞收藏本文章,去看下如何使用时间函数哦。有任何疑问欢迎在评论区留言或者私信我 @风翼之痕 。

https://zhuanlan.zhihu.com/p/3739374082.函数的介绍

如下图所示,apply函数常用的就是这三个参数,还有几个不是很常用。其解释也如图中所示:

其中result_type参数是从版本0.23.0开始加入的参数,只有当axis=1时,该参数才会生效。取值范围为: {'expand', 'reduce', 'broadcast', None}, 默认值为None:

expand:将列表式返回结果,按照列方向展开reduce:返回一个series序列,而不展开列表broadcast:将结果按照原始的dataframe进行展开,原始的索引和列名都会得到保留。3.函数的简单应用

该部分内容,主要参考的是pandas内的源码解析,感兴趣的小伙伴可以自己去源码中看看

3.1 func参数的理解

使用np.sqrt函数对dataframe数据求解平方根,当不对axis赋值时,默认为0,也就是列方向;apply函数会将func用到所有的数中去

df = pd.DataFrame([[4, 9],] * 3, columns=['A', 'B'] print(df) A B 0 4 9 1 4 9 2 4 9 print(df.apply(np.sqrt)) A B 0 2.0 3.0 1 2.0 3.0 2 2.0 3.03.2 使用reduce类型函数

该类型的函数,应用完成之后,会返回一个series序列,而不会再返回一个dataframe.

#按照列方向进行求和 print(df.apply(np.sum, axis=0)) A 12 B 27 dtype: int64 #按照索引方向进行求和 print(df.apply(np.sum, axis=1)) 0 13 1 13 2 13 dtype: int643.3result_type参数

该参数主要涉及reduce和expand,broadcast这三个参数,主要是用于函数返回值不是单一数值,是一个列表的时候使用的。

#使用lambda函数,返回列表[1,2],相当于reduce,列表长度要和列的个数一致 print(df.apply(lambda x: [1, 2], axis=1)) 0 [1, 2] 1 [1, 2] 2 [1, 2] dtype: object #将列表沿着列的方向展开 print(df.apply(lambda x: [1, 2], axis=1, result_type='expand')) 0 1 0 1 2 1 1 2 2 1 2 #expand参数跟下面这个结果是一致的 print(df.apply(lambda x: pd.Series([1, 2], index=['foo', 'bar']), axis=1)) foo bar 0 1 2 1 1 2 2 1 2 #最后broadcast参数,会保留原来的dataframe结构,包括index和columns。 print(df.apply(lambda x: [1, 2], axis=1, result_type='broadcast')) A B 0 1 2 1 1 2 2 1 4.案例分析

下面这个是我在工作中实际处理问题中总结出来的案例。该案例数据量不算很大,大约是2.5万条数据吧,如果累积的时间再长些,会更多。

不使用apply函数时,使用我的台式机计算时间约为96.6秒

使用apply函数,同样的机子,跑完需要22.5秒

计算效率大约提升了4倍多。

4.1背景介绍

本人主要从事物流领域,就从自己领域出发,图1为货物订单的主要信息,包含货物实际出库时间和计划出库时间,另个主要信息。

首先明确一个概念:因为仓储库房是接近24小时在出库,所以每天的8:00开始到第二天的6:00算作同一个出库日,即算作一天。因此需要对已有的数据进行处理,尤其是要用到时间处理函数。(如5月26日8:00-5月27日6:00,这段时间内出库的货物,都算作5月26日出库的,依据此来考核KPI)

意义:主要是考核订单出库的准确率,以此来衡量物流秩序的稳定性。

4.2函数确定

依据计划出库时间-实际出库时间=订单出库日差值公式计算,正常有如下图所示,订单实际未出库、延迟出库、准时出库和提前出库四种情况。

但是存在图中标橙色的四种特殊情况,这四种情况考虑过后,就可以直接返回实际差值了。其中订单实际未交付时,出库时间就会为0,这样订单出库日差值就为空,对于这样的情况,返回差值为404.

4.3程序实现

根据上面的分析,通过自定义函数,可以实现对时间的分情况处理。函数的逻辑,如下所示:

首先判断差值为空,——>返回404天判断差值为-1天,且实际出库时间为6点之前——>返回0判断差值为1天,且计划出库时间为6点之前——>返回0判断差值为0,计划时间小于6点,实际时间大于6点——>返回1判断差值为0,计划时间大于6点,实际时间小于6点——>返回1# 构造订单出库日处理函数 def daypro(dataframe, plan, real): value = dataframe[plan].date()-dataframe[real].date() zero = pd.to_timedelta(0, unit='D') # 天数差值为空,返回404 if pd.isnull(value): return pd.to_timedelta(404, unit='D') # 天数差值-1,实际时间在6点之前,是准时上线 elif(value == pd.to_timedelta(-1, unit='D')) and (dataframe[real].hour < 6): return zero # 天数差值1,计划时间在6点之前,是准时上线 elif (value == pd.to_timedelta(1, unit='D')) and (dataframe[plan].hour < 6): return zero # 天数差值为0,计划时间小于6点,实际时间大于6点,延迟一天 elif (value == zero) and (dataframe[plan].hour < 6 and dataframe[real].hour > 6): return pd.to_timedelta(-1, unit='D') # 天数差值为0,计划时间大于6点,实际时间小于6点,提前一天 elif (value == zero) and (dataframe[plan].hour > 6 and dataframe[real].hour < 6): return pd.to_timedelta(1, unit='D')、 #否者直接返回差值即可 else: return value

定义好上面的函数之后,就可以读取excel中的数据,并对引用daypro函数对数据进行处理了。

# 导入pandas模块 import pandas as pd # 读取订单记录表 order = pd.read_excel(r'订单记录表.xlsx') # 使用apply+自定义函数计算订单出库日差值 order['天数差值']=order.apply(daypro,axis=1,args=('订单计划出库时间','订单实际出库时间'))

接着对实际出库时间进行处理,得到实际的订单出库时间:

函数逻辑:提取订单实际出库时间的小时,若大于6点,返回当前日期,否则返回当前日期-1天。

#使用lambda定义函数 order['订单实际出库日'] = order['订单实际出库时间'].apply( lambda x: pd.to_datetime(x).date() if pd.to_datetime(x).hour > 6 else pd.to_datetime(x).date()-pd.to_timedelta(1, unit='D')) #导出表格 order.to_excel('订单记录表-处理后.xlsx')4.4得到输出结果

最后可以将表格输出,其中蓝色部分为得到的结果,可以得到天数差值和订单实际出库日这两列的信息,得到了想要的结果。

5.结语

关于apply函数的应用就讲这么多,在使用pandas进行数据处理的时候,一定要避免使用for循环从dataframe中一个个取值,然后计算,然后返回列表,再转为dataframe,这样的话计算的速度会很低,效率很低。所以一定要使用apply函数,提高计算速度。即使百万数据又何惧。如果本文对你有用,欢迎点赞收藏支持下,有任何疑问,欢迎在评论区交流,或者直接私信我 @风翼之痕

最后,大家一定要重视Python基础的学习,不积跬步,无以至千里。基础掌握的好,很多程序都可以更简洁,运行更快。你可以到盐选会员专区学习下,里面有许多Live课程讲的还不错,并且专栏也收录了许多优质的问题和回答,还有丰富的电子书,可以直接阅读。对开拓眼界,提高编程技巧很有助益。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3