使用np.select或if else子句加速

问题描述

Python GIS开发人员的问题。我有一个高密度3D点云,每个像素最多可进行73次观察。使用SFM获得云。我正在将来自云的DEM融合为HSI图像中的新波段,以供将来分析。

我有一个代表8个波段的numpy数组(n点,最小z,最大z,和z ...)。我需要基于点云更改此数组的值。因此,我一次只能工作一个像素,因此很难将numpy向量化。

变量为: map_z =浮点数,平均海平面阵列上方单个云点的高度为8波段numpy阵列

array = np.full((nbands,2000,3000),np.nan,dtype=OUTPUT_RASTER_DTYPE)

我尝试了两个版本的代码。矢量化版本和Else If版本。

slice_arr = array[0:4,pixel_y,pixel_x]
slice_arr[0] = np.where(slice_arr[0] == 0,1,slice_arr[0] + 1)
slice_arr[1] = np.select([np.isnan(slice_arr[1]) == True,slice_arr[1] > map_z],[map_z,map_z],slice_arr[1])
slice_arr[2] = np.select([np.isnan(slice_arr[2]) == True,slice_arr[2] < map_z],slice_arr[2])
slice_arr[3] = np.where(np.isnan(slice_arr[3]) == True,map_z,slice_arr[3] + map_z)
array[0:4,pixel_x] = slice_arr

slice_arr = array[0:4,pixel_x] # Take a slice of the array
if slice_arr[0] == 0:
    slice_arr[0] = 1
else:
    slice_arr[0] = slice_arr[0] + 1
if np.isnan(slice_arr[1]) == True:
    slice_arr[1] = map_z
elif slice_arr[1] > map_z:
    slice_arr[1] = map_z
else:
    pass
if np.isnan(slice_arr[2]) == True:  
    slice_arr[2] = map_z
elif slice_arr[2] < map_z:
    slice_arr[2] = map_z
else:
    pass
if np.isnan(slice_arr[3]) == True:  
    slice_arr[3] = map_z
else:
    slice_arr[3] = slice_arr[3] + map_z
array[0:4,pixel_x] = slice_arr

很明显,If else版本的速度要快4倍,因为我一次只能操作一个像素。这是因为map_z是一个点云,我一次只能处理一个点,并且该点仅落在数组中的一个像素上。向量化应在更大的数组上进行。

是否有一种方法可以使用numpy来加速我的代码的这一部分? 如果数组(slice_arr)比(8,3000)大得多,对切片进行切片是否具有速度优势?

解决方法

最后,我能够提高If Else子句的速度,但可以将其放入函数中并使用numba。这样可以减少从2.33分钟开始的时间。到0.42分钟!!

from numba import jit
@jit(nopython=True)
def query_speed_up(slice_arr,map_z):

    if slice_arr[0] == 0:
        slice_arr[0] = 1
    else:
        slice_arr[0] = slice_arr[0] + 1

    # min z
    if np.isnan(slice_arr[1]) == True:  # not is
        slice_arr[1] = map_z
    elif slice_arr[1] > map_z:
        slice_arr[1] = map_z
    else:
        pass

    # max z
    if np.isnan(slice_arr[2]) == True:  # not is
        slice_arr[2] = map_z
    elif slice_arr[2] < map_z:
        slice_arr[2] = map_z
    else:
        pass

    # sum z
    if np.isnan(slice_arr[3]) == True:  # not is
        slice_arr[3] = map_z
    else:
        slice_arr[3] = slice_arr[3] + map_z

    return slice_arr

slice_arr = array[0:4,pixel_y,pixel_x]  # Take a slice of the array
jittest = query_speed_up(slice_arr,map_z)
array[0:4,pixel_x] = jittest