目录
- 问题概述以及优化算法方面
- 关于numba加速的代码部分(想看实战的建议直接跳到这一部分)
- 结论&心得&注意事项
问题概述
之前有一次上课,老师时讲到过一种情况,就是在获取了湖面的二维点云数据后需要和已知的其他点进行匹配。对于这一部分老师程序设计的思路是,将点云数据建立为一个向量,然后将每个待匹配的点进行循环,减去这一向量,得到二者绝对值最小的数,此点即为所匹配到的点。
优化算法
而我设计了此种优化算法,大概意思是给点的坐标数据排序之后,在每一次减去此向量之后将匹配到的点在向量中前面位置的所有元素删去可以提高运行效率。数学证明如下
算法设计如下
然后就是程序设计进行验证了
(1)导入测试数据,并随机生成待匹配的点数据
#导入测试数据,并随机生成待匹配的点数据
from numba import jit
import pandas as pd
import warnings
import random
import time
import numpy as np
warnings.filterwarnings('ignore')
#创建训练数据
def creatfun(path,n):
rawdata = pd.read_csv(path)
num = range(1, len(rawdata['Time (sec)']) + 1)
nums = random.sample(num, n)
vector = []
for index in nums:
vector.append(rawdata['Latitude (deg)'][index])
vector.sort()
vector = np.array(vector)
# 创建latitude向量
latitude = []
for i in num:
latitude.append(rawdata['Latitude (deg)'][i - 1])
latitude.sort()
latitudearr = np.array(latitude)
return vector,latitudearr
vector,latitudearr=creatfun('E:/qq下载/ATL03_20190506122205_05840306_003_01_gt1l.csv',10000)
(2)老师的原始方法
#原始方法
starttime = time.time()
import time
starttime=time.time()
ssss= np.zeros(len(vector),dtype=np.float64)
counter = 0
for i in range(len(vector)):
arr = (vector[i] - latitudearr) ** 2
smallest = arr[0]
smallest_index = 0
for u in range(1, len(arr)):
if arr[u] < smallest:
smallest = arr[u]
smallest_index = u
ssss[i] = smallest_index
endtime=time.time()
usetime=endtime-starttime
print('优化前程序用时:',usetime)
(3)改进后的方法
#优化后的情况
import time
starttime=time.time()
ssss= np.zeros(len(vector),dtype=np.float64)
counter = 0
for i in range(len(vector)):
arr = (vector[i] - latitudearr) ** 2
smallest = arr[0]
smallest_index = 0
for u in range(1, len(arr)):
if arr[u] < smallest:
smallest = arr[u]
smallest_index = u
latitudearr = latitudearr[smallest_index:]
counter = counter + smallest_index
ssss[i] = counter
endtime=time.time()
usetime=endtime-starttime
print('优化后程序用时:',usetime)
(3)优化的方案启动numba加速后
#重建数据集
vector,latitudearr=creatfun('E:/qq下载/ATL03_20190506122205_05840306_003_01_gt1l.csv',10000)
starttime=time.time()
@jit()
def match(vector,latitudearr):
ssss= np.zeros(len(vector),dtype=np.float64)
counter = 0
for i in range(len(vector)):
arr = (vector[i] - latitudearr)**2
smallest = arr[0]
smallest_index = 0
for u in range(1, len(arr)):
if arr[u] < smallest:
smallest = arr[u]
smallest_index = u
latitudearr = latitudearr[smallest_index:]
counter = counter + smallest_index
ssss[i]=counter
return ssss
counter=match(vector,latitudearr)
endtime = time.time()
usetime = endtime - starttime
print('优化并加速后程序用时:',usetime)
程序运行结果如下
结论&心得&注意事项
结论:
优化后相对于优化前运行效率提升了2倍多
而使用numba加速后运行效率更是提升了100多倍,相当恐怖。
心得以及注意事项:
numba库在分析完Python函数的语法树之后,通过直接调用LLVM编译器的方式来得到巨幅的性能提升,但因为编译本身是需要花费不少时间的,而这花费的时间和代码长度呈正相关,这就提示我们为了尽可能压榨numba库所带来的性能提升,最好只将for循环的部分和numpy数组运算的封装成独立函数后再使用,同时numba只支持numpy和部分Python自带函数(低版本的numba甚至连python自带的abs()函数都不能正确编译),因此为保证numba的正常运行,不能使用Python变量的动态性,即让一个变量名始终表示为一种数据类型,而且尽可能使用numpy自带函数解决问题。(很多时候numba在JJVM编译失败时,并不会报错,而是以运行其他普通函数的方式重新运行这段函数,但在这之前,由于已经使用了numba编译而花费了时间,所以会出现程序在使用@JIT后速度反而下降的情况)。