[英]Using NumPy in the correct way to apply a function to specific points in an array
cArr是以下形式的数组:
cArr=np.array([[0,x0,y0,z0,1],[1,x1,y1,z1,1]])
每行的中间三个数字表示两个点的坐标(参考点0和1),在3D中。 每行的第一个和最后一个值由其他函数使用。
cEDA是一个4D形状的数组(100,100,100,4),基本上由随机数填充。
对于0和1的每个点,在6个基本方向上,每个点周围都有点的邻域,坐标仅相差一个。
x0,y0,z0
x0+1,y0,z0
x0,y0+1,z0
x0,y0,z0+1
x0-1,y0,z0
x0,y0-1,z0
x0,y0,z0-1
计算与点0和点1相关的这7个点之间的距离(因此,点1与点0和点0本身周围的点的邻域之间的距离)并与-2(100,100,100)数组中的对应值组合cEDA并放置在cEDA中第i个100,100,100立方体中,其中i分别是点0或1。
我是C语言背景的python新手,并且正努力摆脱循环思维定势。 我已经尝试过预先计算距离并求和数组,但速度慢得多,但到目前为止最快的方法是遍历每个单独的值并赋值。 该函数运行很多次,并且是代码中的瓶颈,并且确信有更好的方法来执行此功能。
我从概念上理解并且可以使用NumPy,但在这种情况下似乎无法应用-关于如何通过使用NumPy加快此功能的任何想法是正确的方法? 我已尽力解释此功能的功能,对不起,我知道这很令人困惑!
def cF2(cArr, cEDA):
# the coordinates of points 0 and 1 for readability
x0 = cArr[0,1]
y0 = cArr[0,2]
z0 = cArr[0,3]
x1 = cArr[1,1]
y1 = cArr[1,2]
z1 = cArr[1,3]
# for each point around point 0 and the point itself, calculate the distance between this point and point 1
# use this value and the corresponding value in cEDA(x,y,z,-2) and place result in cEDA(x,y,z,0)
cEDA[x0,y0,z0,0] = cEDA[x0,y0,z0,-2]-0.4799/(np.linalg.norm([x0,y0,z0]-cArr[1,1:4]))
cEDA[x0-1,y0,z0,0] = cEDA[x0-1,y0,z0,-2]-0.4799/(np.linalg.norm([x0-1,y0,z0]-cArr[1,1:4]))
cEDA[x0+1,y0,z0,0] = cEDA[x0+1,y0,z0,-2]-0.4799/(np.linalg.norm([x0+1,y0,z0]-cArr[1,1:4]))
cEDA[x0,y0-1,z0,0] = cEDA[x0,y0-1,z0,-2]-0.4799/(np.linalg.norm([x0,y0-1,z0]-cArr[1,1:4]))
cEDA[x0,y0+1,z0,0] = cEDA[x0,y0+1,z0,-2]-0.4799/(np.linalg.norm([x0,y0+1,z0]-cArr[1,1:4]))
cEDA[x0,y0,z0-1,0] = cEDA[x0,y0,z0-1,-2]-0.4799/(np.linalg.norm([x0,y0,z0-1]-cArr[1,1:4]))
cEDA[x0,y0,z0+1,0] = cEDA[x0,y0,z0+1,-2]-0.4799/(np.linalg.norm([x0,y0,z0+1]-cArr[1,1:4]))
cEDA[x1,y1,z1,1] = cEDA[x1,y1,z1,-2]+0.4799/(np.linalg.norm([x1,y1,z1]-cArr[0,1:4]))
cEDA[x1-1,y1,z1,1] = cEDA[x1-1,y1,z1,-2]+0.4799/(np.linalg.norm([x1-1,y1,z1]-cArr[0,1:4]))
cEDA[x1+1,y1,z1,1] = cEDA[x1+1,y1,z1,-2]+0.4799/(np.linalg.norm([x1+1,y1,z1]-cArr[0,1:4]))
cEDA[x1,y1-1,z1,1] = cEDA[x1,y1-1,z1,-2]+0.4799/(np.linalg.norm([x1,y1-1,z1]-cArr[0,1:4]))
cEDA[x1,y1+1,z1,1] = cEDA[x1,y1+1,z1,-2]+0.4799/(np.linalg.norm([x1,y1+1,z1]-cArr[0,1:4]))
cEDA[x1,y1,z1-1,1] = cEDA[x1,y1,z1-1,-2]+0.4799/(np.linalg.norm([x1,y1,z1-1]-cArr[0,1:4]))
cEDA[x1,y1,z1+1,1] = cEDA[x1,y1,z1+1,-2]+0.4799/(np.linalg.norm([x1,y1,z1+1]-cArr[0,1:4]))
return cEDA
如果您想多次调用它,则需要通过numba或Cython将整个for循环转换为C循环。 但是,有一些方法可以提高功能的速度,这是您的原始功能:
def cF2(cArr, cEDA):
# the coordinates of points 0 and 1 for readability
x0 = cArr[0,1]
y0 = cArr[0,2]
z0 = cArr[0,3]
x1 = cArr[1,1]
y1 = cArr[1,2]
z1 = cArr[1,3]
# for each point around point 0 and the point itself, calculate the distance between this point and point 1
# use this value and the corresponding value in cEDA(x,y,z,-2) and place result in cEDA(x,y,z,0)
cEDA[x0,y0,z0,0] = cEDA[x0,y0,z0,-2]-0.4799/(np.linalg.norm([x0,y0,z0]-cArr[1,1:4]))
cEDA[x0-1,y0,z0,0] = cEDA[x0-1,y0,z0,-2]-0.4799/(np.linalg.norm([x0-1,y0,z0]-cArr[1,1:4]))
cEDA[x0+1,y0,z0,0] = cEDA[x0+1,y0,z0,-2]-0.4799/(np.linalg.norm([x0+1,y0,z0]-cArr[1,1:4]))
cEDA[x0,y0-1,z0,0] = cEDA[x0,y0-1,z0,-2]-0.4799/(np.linalg.norm([x0,y0-1,z0]-cArr[1,1:4]))
cEDA[x0,y0+1,z0,0] = cEDA[x0,y0+1,z0,-2]-0.4799/(np.linalg.norm([x0,y0+1,z0]-cArr[1,1:4]))
cEDA[x0,y0,z0-1,0] = cEDA[x0,y0,z0-1,-2]-0.4799/(np.linalg.norm([x0,y0,z0-1]-cArr[1,1:4]))
cEDA[x0,y0,z0+1,0] = cEDA[x0,y0,z0+1,-2]-0.4799/(np.linalg.norm([x0,y0,z0+1]-cArr[1,1:4]))
cEDA[x1,y1,z1,1] = cEDA[x1,y1,z1,-2]+0.4799/(np.linalg.norm([x1,y1,z1]-cArr[0,1:4]))
cEDA[x1-1,y1,z1,1] = cEDA[x1-1,y1,z1,-2]+0.4799/(np.linalg.norm([x1-1,y1,z1]-cArr[0,1:4]))
cEDA[x1+1,y1,z1,1] = cEDA[x1+1,y1,z1,-2]+0.4799/(np.linalg.norm([x1+1,y1,z1]-cArr[0,1:4]))
cEDA[x1,y1-1,z1,1] = cEDA[x1,y1-1,z1,-2]+0.4799/(np.linalg.norm([x1,y1-1,z1]-cArr[0,1:4]))
cEDA[x1,y1+1,z1,1] = cEDA[x1,y1+1,z1,-2]+0.4799/(np.linalg.norm([x1,y1+1,z1]-cArr[0,1:4]))
cEDA[x1,y1,z1-1,1] = cEDA[x1,y1,z1-1,-2]+0.4799/(np.linalg.norm([x1,y1,z1-1]-cArr[0,1:4]))
cEDA[x1,y1,z1+1,1] = cEDA[x1,y1,z1+1,-2]+0.4799/(np.linalg.norm([x1,y1,z1+1]-cArr[0,1:4]))
return cEDA
np.random.seed(42)
cArr = np.random.randint(0, 100, (2, 5))
cEDA = np.random.rand(100, 100, 100, 4)
r1 = cF2(cArr, cEDA)
这是优化的功能:
tmp = np.eye(3)
offsets = np.concatenate((tmp, -tmp, [[0, 0, 0]]), 0).astype(int)[:, None, :]
def fast_cF2(cArr, cEDA):
cArr = cArr[:, 1:4]
t = cArr[None,:,:] + offsets
X0, Y0, Z0 = t[:, 0, :].T
X1, Y1, Z1 = t[:, 1, :].T
d1 = 0.4799/np.linalg.norm(t[:, 0, :] - cArr[1], axis=1)
d0 = 0.4799/np.linalg.norm(t[:, 1, :] - cArr[0], axis=1)
cEDA[X0, Y0, Z0, 0] = cEDA[X0, Y0, Z0, -2] - d1
cEDA[X1, Y1, Z1, 1] = cEDA[X1, Y1, Z1, -2] + d0
return cEDA
np.random.seed(42)
cArr = np.random.randint(0, 100, (2, 5))
cEDA = np.random.rand(100, 100, 100, 4)
r2 = fast_cF2(cArr, cEDA)
print np.allclose(r1, r2)
时间结果:
%timeit cF2(cArr, cEDA)
%timeit fast_cF2(cArr, cEDA)
输出:
1000 loops, best of 3: 320 µs per loop
10000 loops, best of 3: 91.6 µs per loop
我认为scipy.ndimage.generic_filter可以做到...
def neighborly_function(in_arr1d):
# put your equation below - will have to figure out the details
# below is just an example
# has to return a scalar
return sum(in_arr1d)
import scipy.ndimage as nd
huge_arr3d = [....]
# Since you want the cardinal directions you have to 'footprint'
footprint = np.array([[[False, False, False],
[False, True, False],
[False, False, False]],
[[False, True, False],
[ True, False, True],
[False, True, False]],
[[False, False, False],
[False, True, False],
[False, False, False]]])
out = nd.generic_filter(huge_arr3d, neighborly_function, footprint=footprint)
在http://docs.scipy.org/doc/scipy/reference/tutorial/ndimage.html上查看ndimage文档,并在http://docs.scipy.org/doc/scipy/reference/tutorial/ndimage上查看generic_filter 。 HTML#通用的过滤函数
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.