社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

1000+倍!超强Python『向量化』数据处理提速攻略

量化投资与机器学习 • 4 年前 • 530 次点击  


标星★置顶公众号     爱你们   
作者:Cheever
编译:1+1=6 


今天公众号给大家好好讲讲基于Pandas和NumPy,如何高速进行数据处理!


1

向量化

1000倍的速度听起来很夸张。Python并不以速度著称。这是真的吗?当然有可能 ,关键在于你如何操作!


如果在数据上使用for循环,则完成所需的时间将与数据的大小成比例。但是还有另一种方法可以在很短的时间内得到相同的结果,那就是向量化。



这意味着要花费15秒的时间来编写代码,并且在15毫秒的时间内跑出结果。


当然,根据数据集的不同,库文件、硬件版本的不同,所以实际结果可能会有所不同。


公众号也多次发过相关文章:

1、30倍!使用Cython加速Python代码

2、71803倍!超强Pandas循环提速攻略

3、CuPy:将Numpy提速700倍!

4、10个提高工作效率的Pandas小技巧

5、高逼格使用Pandas加速代码,向for循环说拜拜!


那么什么是向量化?


简而言之,向量化是一种同时操作整个数组而不是一次操作一个元素的方法,这也得益于Numpy数组。


我们先导入测试数据:



第一次向量化测试:


以这个函数为例。这是一个非常基本的条件逻辑,我们需要为lead status创建一个新列。


我们使用Pandas的优化循环函数apply(),但它对我们来说太慢了。



或者使用如下方法:



接下来,我们尝试一下使用向量化。将整个Series作为参数传递到函数中,而不是对每一行。




但没有成功。if语句试图确定Series作为一个整体的真实性,而不是比较Series中的每个元素,所以这是错误的


2

numpy.where()

语法很简单,就像Excel的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年第9篇文章


量化投资与机器学习微信公众号,是业内垂直于Quant、MFE、Fintech、AI、ML等领域的量化类主流自媒体。公众号拥有来自公募、私募、券商、期货、银行、保险资管、海外等众多圈内18W+关注者。每日发布行业前沿研究成果和最新量化资讯。

你点的每个“在看”,都是对我们最大的鼓励
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/52787
 
530 次点击