我有一个3D numpy阵列A形状(2133,3,3)。基本上这是包含三个3D点的2133个列表的列表。此外,我有一个函数,它获取三个3D点并返回一个3D点x = f(a, b, c)
,其中a,b,c,x numpy数组的长度为3.现在我想将f应用于A,因此输出为一个形状的阵列(2133,3)。所以像numpy.array([f(*A[0]),...,f(*A[2132]))
。
我尝试了numpy.apply_along_axis
和numpy.vectorize
但没有成功。
更准确地说,我考虑的函数由下式给出:
def f(a, b, c, r1, r2=None, r3=None):
a = np.asarray(a)
b = np.asarray(b)
c = np.asarray(c)
if np.linalg.matrix_rank(np.matrix([a, b, c])) != 3:
# raise ValueError('The points are not collinear.')
return None
a, b, c, = sort_triple(a, b, c)
if any(r is None for r in (r2, r3)):
r2, r3 = (r1, r1)
ex = (b - a) / (np.linalg.norm(b - a))
i = np.dot(ex, c - a)
ey = (c - a - i*ex) / (np.linalg.norm(c - a - i*ex))
ez = np.cross(ex, ey)
d = np.linalg.norm(b - a)
j = np.dot(ey, c - a)
x = (pow(r1, 2) - pow(r2, 2) + pow(d, 2)) / (2 * d)
y = ((pow(r1, 2) - pow(r3, 2) + pow(i, 2) + pow(j, 2)) / (2*j)) - ((i/j)*x)
z_square = pow(r1, 2) - pow(x, 2) - pow(y, 2)
if z_square >= 0:
z = np.sqrt(z_square)
intersection = a + x * ex + y*ey + z*ez
return intersection
A = np.array([[[131.83, 25.2, 0.52], [131.51, 22.54, 0.52],[133.65, 23.65, 0.52]], [[13.02, 86.98, 0.52], [61.02, 87.12, 0.52],[129.05, 87.32, 0.52]]])
r1 = 1.7115
答案 0 :(得分:1)
感谢@jdehesa的大力帮助,我能够为@hpaulj提供另一种解决方案。我不确定这个解决方案是否是最优雅的解决方案,但它到目前为止仍然有效。评论很感激。
def sort_triple(a, b, c):
pts = np.stack((a, b, c), axis=1)
xSorted = pts[np.arange(pts.shape[0])[:, None], np.argsort(pts[:, :, 0])]
orientation = np.cross(xSorted[:, 1] - xSorted[:, 0], xSorted[:, 2] -
xSorted[:, 0])[:, 2] >= 0
xSorted_flipped = np.stack((xSorted[:, 0], xSorted[:, 2], xSorted[:, 1]),
axis=1)
xSorted = np.where(orientation[:, np.newaxis, np.newaxis], xSorted,
xSorted_flipped)
return map(np.squeeze, np.split(xSorted, 3, axis=1))
def f(A, r1, r2=None, r3=None):
a, b, c = map(np.squeeze, np.split(A, 3, axis=1))
a, b, c = sort_triple(a, b, c)
if any(r is None for r in (r2, r3)):
r2, r3 = (r1, r1)
ex = (b - a) / (np.linalg.norm(b - a, axis=1))[:, np.newaxis]
i = inner1d(ex, (c - a))
ey = ((c - a - i[:, np.newaxis]*ex) /
(np.linalg.norm(c - a - i[:, np.newaxis]*ex, axis=1))[:, np.newaxis])
ez = np.cross(ex, ey)
d = np.linalg.norm(b - a, axis=1)
j = inner1d(ey, c - a)
x = (np.square(r1) - np.square(r2) + np.square(d)) / (2 * d)
y = ((np.square(r1) - np.square(r3) + np.square(i) + np.square(j)) / (2*j) -
i/j*x)
z_square = np.square(r1) - np.square(x) - np.square(y)
mask = z_square < 0
z_square[mask] *= 0
z = np.sqrt(z_square)
z[mask] = np.nan
intersection = (a + x[:, np.newaxis] * ex + y[:, np.newaxis] * ey +
z[:, np.newaxis] * ez)
return intersection
每个功能中的map
部分可能会做得更好。也许过度使用np.newaxis
。
答案 1 :(得分:0)
这很好用(在评论sort_triple
之后):
res = [f(*row,r1) for row in A]
print(res)
制造
[array([ 132.21182324, 23.80481826, 1.43482849]), None]
看起来一行产生了一个(3,)数组,另一行产生了某种问题并产生了None
。我不知道None
是否因删除排序而导致。但无论如何,将数组和None
的混合变回数组将是一个问题。如果res
的所有项都匹配数组,我们可以stack
将它们重新组合成2d数组。
有一些方法可以获得适度的速度提升(与此列表理解相比)。但是对于像这样的复杂函数,在函数中花费的时间(称为2000次)主导了迭代机制所花费的时间。
由于你在第一维迭代,并传递另外两个(作为3个数组),这个显式循环比vectorize
,frompyfunc
或{{1}更容易使用}。
为了节省大量时间,您必须编写apply_along/over..
以直接使用3d数组。