将3参数函数应用于3D numpy数组

时间:2017-08-24 14:00:48

标签: python numpy

我有一个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_axisnumpy.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

2 个答案:

答案 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个数组),这个显式循环比vectorizefrompyfunc或{{1}更容易使用}。

为了节省大量时间,您必须编写apply_along/over..以直接使用3d数组。