1000+倍!超强Python『向量化』数据处理提速攻略
1、向量化
1000倍的速度听起来很夸张。Python并不以速度著称。这是真的吗?当然有可能 ,关键在于你如何操作!
如果在数据上使用for循环,则完成所需的时间将与数据的大小成比例。但是还有另一种方法可以在很短的时间内得到相同的结果,那就是向量化。
这意味着要花费15秒的时间来编写代码,并且在15毫秒的时间内跑出结果。
当然,根据数据集的不同,库文件、硬件版本的不同,所以实际结果可能会有所不同。
那么什么是向量化?
简而言之,向量化是一种同时操作整个数组而不是一次操作一个元素的方法,这也得益于Numpy数组。
我们先导入测试数据:
第一次向量化测试:
以这个函数为例。这是一个非常基本的条件逻辑,我们需要为lead status创建一个新列。
我们使用Pandas的优化循环函数apply(),但它对我们来说太慢了。
或者使用如下方法:
接下来,我们尝试一下使用向量化。将整个Series作为参数传递到函数中,而不是对每一行。
但没有成功。if语句试图确定Series作为一个整体的真实性,而不是比较Series中的每个元素,所以这是错误的。
2、numpy.where()
语法很简单,就像的IF()。
第一个参数是逻辑条件Numpy,它将为数组中的每个元素计算一个布尔数组。当条件满足且为True时,将返回第二个参数,否则返回第三个参数。
看下面的例子:
numpy.where()它从我们的条件中创建一个布尔数组,并在条件为真或假时返回两个参数,它对每个元素都这样做。这对于在Dataframe中创建新列非常有用。
比apply函数快344倍!
如果我们在Series添加了.values ,它的作用是返回一个NumPy数组,里面是我的级数中的数据。
现在的numpy.where(),只查看数组中的原始数据,而不必负责Pandas Series带来的内容,如index或其他属性。这个小的变化通常会在时间上产生巨大的差异。
各位!一开始,我们应用的if/else函数的时间超过了8秒,现在我们已经将其缩短到不到9毫秒,这几乎是一个1000倍的转换!
3、numpy.vectorize()
这个函数将把Python函数转换成NumPy ufunc,这样它就可以处理向量化的方法。它向量化了你的函数,而不一定是这个函数如何应用于你的数据,这有很大的不同!
例子如下:
vectorize()将常规的Python函数转换成Numpy ufunc(通用函数),这样它就可以接收Numpy数组并生成Numpy数组。vectorize()主要是为了方便,而不是为了性能。实质上是一个for loop。
我们可以使用它的一种方式,包装我们之前的函数,在我们传递列时不起作用的函数,并向量化它。它比.apply()快得多,但也比.where()慢了17倍。所以在这种情况下,将坚持使用np.where()!
一些人认为这更快:使用index设置,但事实证明它实际上不是向量化!
代码如下:
4、Multiple conditions
类似这样的多个if/elif/elifs,如何向量化呢?
你可以调用np.where在任何情况下,代码长了就变得有点难读了
实际上有一个函数专门可以做多重条件的向量化,是什么呢?
5、numpy.select()
向量化if...elif...else。更简洁(甚至更快)和做多重嵌套np.where。
np.select()的一个优点是它的layout。
你可以用你想要检查的顺序来表达你想要检查的条件。np.select将按从前到后的顺序对每个数组求值,当数据集中的某个给定元素的第一个数组为True时,将返回相应的选择。所以操作的顺序很重要!像np.where。其中,你的选择可以是标量,也可以是数组。只要它符合你的条件。
这是我们第一次尝试将多个条件从.apply()方法转换为向量化的解决方案。向量化选项将在0.1秒多一点的时间内返回列,.apply()将花费12.5秒。嵌套的np.where()解决方案工具179ms。
那么嵌套的多个条件,我们可以向量化吗?可以!
代码:
基本上,当使用np.select()时。根据经验,你需要为每个return语句设置n个条件,这样就可以将所有布尔数组打包到一个条件中,以返回一个选项。
代码如下:
如果添加了.values:
4、更复杂的
有时必须使用字符串,有条件地从字典中查找内容,比较日期,有时甚至需要比较其他行的值。我们来看看!
1、字符串
假设你需要在一系列文本中搜索特定的模式,如果匹配,则创建一个新的series。这是一种.apply方法。
用np.vectorize()时:
同时,当使用向量化方法处理字符串时,Pandas为我们提供了向量化字符串操作的.str()。contains基本上和re.search做的是一样的,它会给我们相同的结果。
为什么.str向量化这么慢?
字符串操作很难并行化,所以.str方法是向量化的,这样就不必为它们编写for循环。使用.apply执行基本的Python是更快的选择。
一般来说,我们还建议你使用str方法来避免循环,但是如果你的速度变慢了,这会让你很痛苦,试试循环是否能帮你节省一些时间。
2、字典lookups
对于进行字典查找,我们可能会遇到这样的情况,如果为真,我们希望从字典中获取该series键的值并返回它,就像下面代码中的下划线一样。
你可以使用.map()在向量化方法中执行相同的操作。
3、日期
有时你可能需要做一些日期计算(确保你的列已经转换为datetime对象)。这是一个计算周数的函数。以天为单位的两个日期之差除以7得到过去的周数。下面是使用.apply()的方法。
有两种向量化方法。第一种方法是使用pandas .dt series datetime访问器。除了改变语法以适应np.where。我们要做的就是在.dt之前加上.days ,效果很好。
完成此计算的另一种更加Numpy向量化的方法是将Numpy数组转换为timedeltas,获得day值,然后除以7。这和最终结果是一样的,只是下面的那个代码更长。
4、使用来自其他行的值
在这个例子中,我们从Excel中重新创建了一个公式:
其中A列表示id,L列表示日期。
向量化所需要的所有函数都是在同一行上比较的值,这可以使用pandas.shift()实现!
确保你的数据正确排序,否则你的结果就没有意义!
很慢!
为了解决这个问题,我们对Pandas中的一个series使用.shift()将前一行移到相同的级别。一旦它们被转移到相同的级别,我就可以使用np.select()执行相同的条件向量化方法了!
5、其他
一种选择是使用apply跨CPU核并行化操作。因此,如果你有一个4核的i7,你可以将你的数据集分成4块,将你的函数应用到每一块,然后将结果合并在一起。注意:这不是一个很好的选择!
Dask是在Pandas API中工作的一个不错的选择。能够跨集群扩展到TB级的数据,或者甚至能够更有效地在一台机器上处理多核数据。
6、总结
向量化可以极大地加快速度!
np.where →一个逻辑条件
np.select →2+逻辑条件
如果你正在处理字符串/正则表达式函数,那么较好还是使用Python。或者如果你的逻辑重写起来很麻烦或者你不想重写,你可以考虑并行化应用函数或者像Dask这样的东西可以帮你实现。
最后,在优化之前一定要确保逻辑是合理的。
不成熟的优化是万恶之源!
声明:文章收集于网络,版权归原作者所有,为传播信息而发,如有侵权,请联系小编删除,谢谢!
时间:2020-02-06 21:26 来源: 转发量:次
声明:本站部分作品是由网友自主投稿和发布、编辑整理上传,对此类作品本站仅提供交流平台,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,不为其版权负责。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。
相关文章:
相关推荐:
网友评论:
最新文章
热门文章