[英]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.