Python在数据处理,科学计算中的性能优化
怎么测定程序运行的时间复杂度
性能的优化一般从两方面来考虑,时间复杂度和空间复杂度,在如今硬件那么发达的情况下,时间复杂度的优化就显得更为重要了,有时候甚至要以空间换时间,所以这里结合自身项目的实践,就简单说一下程序运行时间上的优化。
测定程序的运行时间
要想优化程序,得先知道哪部分程序需要优化,下面是几种常用的检测程序运行时间的方法:
-
time模块
time模块用法很简单,就是在程序运行的开头和结尾分别检测一个时间,然后 (结束的时间 - 开始的时间) 就是程序运行的时间。常用的有time()和clock(),两者的区别参见:https://blog.youkuaiyun.com/wonengguwozai/article/details/80680699# 以clock()为例,两者用法完全一样 import time t_start = time.clock() # 要检测的代码块(函数等) fun() t_end = time.clock() exec_time = t_end - t_start print(exec_time)
-
timeit模块
timeit模块的用法比较灵活,有多种用法,像timeit.default_timer()与上述用法一样,这里不重复了,简单说说常见的几种用法,详细的可以看看timeit的documentation。代码行界面可以用如下命令(不包含尖括号):
python -m timeit <要执行的命令>python 界面可以如下:
import timeit def fun(): pass timeit.timeit(stmt = fun, number = 1000)
如果是在jupyter notebook中,可以直接调用%timeit:
这种操作是把代码循环跑几遍取平均值,如果代码运行时间较长,不建议采用这种方法。#要执行的代码块注意不包含两端的尖括号 %timeit <要执行的代码块>
-
profile模块
正如名字所指的这样,profile模块可以剖析你所要执行的代码块,找出每一部分所耗费的时间占比,当你不知道程序中哪一块需要优化时,用此方法先找到需要优化的部分,有目标才更有针对性。
这一部分可以用cProfile, line_profiler等,这里只简要介绍一下个人比较喜欢的line_profiler,它对程序的每一行进行分析,找出其运行时间的占比。#需要安装line_profiler from line_profiler import LineProfiler # 仅列举一个简单的例子 def fun(a,b): a * b a ** b b ** a return a + b lp = LineProfiler() lp_wrapper = lp(fun) lp_wrapper(3,5) lp.print_stats()
如果是在jupyter notebook中,可以用line_profiler 扩展
#load line_profiler扩展 %load_ext line_profiler def fun(a,b): a * b a ** b b ** a %lprun -f fun fun(3,5)
除此之外,还有其他好多方法来检测程序的运行时间,stackoverflow上面有一个问题几乎包括了所有方法,感兴趣的可以参考:
https://stackoverflow.com/questions/1557571/how-do-i-get-time-of-a-python-programs-execution
数据处理上的一些优化
前面讲了一大堆怎么测程序的运行时间,以及怎么找需要优化的地方,现在终于到正题了,这一部分只介绍我最近用到的几个方法,以后还会继续更新,仅供参考。
data analysis避不开pandas 和 numpy, 接下来就分享一下我在工作中遇到的几个方法,小白刚刚入行,与大家相互学习
首先是pandas:,numpy后续更新
1.column数量
pandas本身已经进行过优化,但是在做大数据处理的时候,column过多会影响程序的运行速度,所以能不增加column可以不增加,只对某些column做处理的话可以单独取出来处理,然后再放回去.
2.切片的取法
假设:df.columns = [‘a’,‘b’,‘c’,‘d’]
取法1:df[df.a == 1][df.b == ‘new’][df.c == False]
取法2:df[(df.a == 1)&(df.b == ‘new’)&(df.c == False)]
取法1不仅会报警告,而且速度会很慢,官方文档中也有说明,因为每一次取的条件都会生成一个新的dataframe,很浪费时间
而取法2 则是先把各种条件取交集,然后再一次取出,速度有可能是取法1的4-5倍
3. 使用map()
使用pandas的好处就是可以把大量的数据做并行处理,如果会里面的每个数据或每列数据单独操作的话会非常费时间,这个时候就要想办法能不能使用pandas里面的map()函数,或apply()进行并行化操作,速度提升到你想不到,40-50倍,甚至上百倍都有可能。