Python相比于C++来说有着十分用户友好的编程方式与众多的机器学习和深度学习库,入门快、学习轻松,但其性能劣势一直为人诟病。因此,很多工程师致力于提高python代码性能。本文记录下目前我所知道的Python代码加速方法!
Numba Numba 是一个开源的 JIT 编译器可以纯Python和Numpy代码转为快速地机器码执行,但其不能加速Pandas代码而且在多线程的任务出容易出错!
numba可以将python变为C的性能,并且所有代码的改动点只需要加一行代码!
参考官网地址:https://numba.pydata.org/
下面以官方计算π \pi π 的例子来测试性能提升幅度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 from numba import jitimport randomimport timedef monte_carlo_pi (nsamples ): acc = 0 for i in range (nsamples): x = random.random() y = random.random() if (x ** 2 + y ** 2 ) < 1.0 : acc += 1 return 4.0 * acc / nsamples @jit(nopython=True ) def monte_carlo_pi_numba (nsamples ): acc = 0 for i in range (nsamples): x = random.random() y = random.random() if (x ** 2 + y ** 2 ) < 1.0 : acc += 1 return 4.0 * acc / nsamples def test_time (func, *args, **kwargs ): start = time.time() res = func(*args) end = time.time() return end-start magnitude1 = 10000 print (f"Magnitude {magnitude1} : non-accelerated costed time:{test_time(monte_carlo_pi, magnitude1)} " )print (f"Magnitude {magnitude1} : accelerated costed time:{test_time(monte_carlo_pi_numba, magnitude1)} " )magnitude2 = 100000 print (f"Magnitude {magnitude2} : non-accelerated costed time:{test_time(monte_carlo_pi, magnitude2)} " )print (f"Magnitude {magnitude2} : accelerated costed time:{test_time(monte_carlo_pi_numba, magnitude2)} " )
Magnitude 10000 : non-accelerated costed time:0.004992485046386719
Magnitude 10000 : accelerated costed time:0.2682771682739258
Magnitude 100000 : non-accelerated costed time:0.053856611251831055
Magnitude 100000 : accelerated costed time:0.0010225772857666016
从上述时间测试中可以看出,对于量级小于100000的计算量来使用Numba加速发现加速效果并不佳,而且还可能减慢运行时间!因此需要根据自己的数据量来选择是否使用Numba!
上面谈到Numba仅能加速纯python操作和numpy操作,那么对于数据分析中另一常用库 pandas 如何加速呢?写下自己了解的两种方法。
Python 多线程 python多线程可以加速任意的操作,加速的上限取决于电脑的性能,可以使用python多线程并行处理来加速pandas操作。操作代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import numpy as npimport pandas as pdfrom multiprocessing import cpu_count, Pooldef parallelize (func, df ): """ Split data into max core partitions and execute func in parallel. https://www.machinelearningplus.com/python/parallel-processing-python/ Parameters ---------- df : pandas Dataframe func : any functions Returns ------- data : pandas Dataframe Returned dataframe of func. """ cores = cpu_count() data_split = np.array_split(df, cores) pool = Pool(cores) data = pd.concat(pool.map (func, data_split), ignore_index=1 ) pool.close() pool.join() return data
测试多线程处理的性能:
1 2 3 4 5 6 7 8 9 10 nsamples = 100 data = pd.DataFrame({"a" : np.random.rand(nsamples), "b" : np.random.rand(nsamples)}) def func (data ): """test func.""" return data["a" ].apply(lambda x: np.sqrt(x)) - data["b" ] ** 2 if __name__ == '__main__' : print (f"non-accelerated costed time:{test_time(func, data)} " ) print (f"accelerated costed time:{test_time(parallelize, func, data)} " )
注意 :在Windows上要想使用multipropressing
模块,必须把有关进程的代码写 if __name__ == ‘__main__’
语句中,才能正常使用Windows下的进程模块,否则进程将不会停止。Unix/Linux下则不需要。 这个Bug真是让我头疼半天!
Modin 库 Modin 库是pandas库的升级版,同样是使用多核调度的方法来加速pandas中的操作,和numba一样操作简单,它只需增加一行代码来优化而不需要自己控制调度过程!
一行代码加速确实非常香,但缺点是需要安装底层依赖r a y ray r a y 或者d a s k dask d a s k ,此外也不是完全支持pandas操作,待进一步完善。可以满足日常需求!参考: modin-project/modin
给出官方的测试效果,其它细节可以参考官方文档:文档说明
目前暂时用不到这库,因此以后有需求的时候再补充使用说明吧!
联系作者