炼数成金 门户 大数据 Python 查看内容

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

2020-1-10 17:00| 发布者: 炼数成金_小数| 查看: 9484| 评论: 0|原作者: Cheever|来自: 量化投资与机器学习

摘要: 1000倍的速度听起来很夸张。Python并不以速度著称。这是真的吗?当然有可能 ,关键在于你如何操作!如果在数据上使用for循环,则完成所需的时间将与数据的大小成比例。但是还有另一种方法可以在很短的时间内得到相同 ...
1、向量化
1000倍的速度听起来很夸张。Python并不以速度著称。这是真的吗?当然有可能 ,关键在于你如何操作!

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


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

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

那么什么是向量化?
简而言之,向量化是一种同时操作整个数组而不是一次操作一个元素的方法,这也得益于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这样的东西可以帮你实现。

最后,在优化之前一定要确保逻辑是合理的。

不成熟的优化是万恶之源!

声明:文章收集于网络,版权归原作者所有,为传播信息而发,如有侵权,请联系小编删除,谢谢!

欢迎加入本站公开兴趣群
软件开发技术群
兴趣范围包括:Java,C/C++,Python,PHP,Ruby,shell等各种语言开发经验交流,各种框架使用,外包项目机会,学习、培训、跳槽等交流
QQ群:26931708

Hadoop源代码研究群
兴趣范围包括:Hadoop源代码解读,改进,优化,分布式系统场景定制,与Hadoop有关的各种开源项目,总之就是玩转Hadoop
QQ群:288410967 

鲜花

握手

雷人

路过

鸡蛋

相关阅读

最新评论

热门频道

  • 大数据
  • 商业智能
  • 量化投资
  • 科学探索
  • 创业

即将开课

 

GMT+8, 2020-1-26 00:43 , Processed in 0.166966 second(s), 25 queries .