2017-08-24 21 views
0

3D numpy配列A(2133,3,3)があります。基本的にこれは3つの3Dポイントを持つ2133リストのリストです。さらに私は、3つの3Dポイントを取り、長さ3のa、b、c、x numpyの配列を持つx = f(a, b, c)という1つの3Dポイントを返す関数を持っています。今度は、出力を形状の配列にするためにfにAを適用したい(2133,3)。だから、numpy.array([f(*A[0]),...,f(*A[2132]))のようなものです。3D numpy配列に3引数関数を適用する

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 
+0

'np.vectorize'と' np.apply_along_axis'で何を試してみるのが参考になるでしょうか。また、関数fは正確に何をするのですか?ベクトル化されたバージョンで置き換えることができます。 – user2699

+0

@ user2699私は関数fを提供しました。私は 'np.apply_along_axis'の問題は、与えられた軸に沿って1次元スライスに適用されていることです。アンパックが正しい方法で行われないので、 'np.vectorize'は動作しません。私が 'f'を書き直しても形状の配列(3,3)が得られるように、numpyを第1軸上で反復して3x3のサブ配列を取る方法を教えてください。 – patrik

+0

これを行う自動方法はありません。単一点の代わりに点の配列で動作するように 'f'を書く必要があります。私はそれがほぼ大丈夫だと思いますが、最初の 'if'を変更する必要がありますが、' np.linalg.norm'呼び出しに 'axis'パラメータを追加し、多分もっと多くのものを' sort_triple'としますあなたの機能が適応される必要があるかもしれない場合は別です)。 Btwでは、すべての 'pow(x、2)'呼び出しを 'np.square(x)'に置き換えることを検討してください。 – jdehesa

答えて

0

これは正常に動作します(sort_tripleをコメントアウトした後):

は私が考える関数fによって与えられ、より正確には

res = [f(*row,r1) for row in A] 
print(res) 

が生産:

[array([ 132.21182324, 23.80481826, 1.43482849]), None] 

1列に(3)配列が生成され、もう1行に何らかの問題があり、None。そのNoneがその並べ替えを削除したかどうかはわかりません。しかし、どのような場合でも、配列の組み合わせとNoneを配列に戻すことは問題になります。 resのすべての項目が一致する配列であれば、stackを2次元配列に戻すことができます。

(このリストの解説と比較して)控えめな速度向上を得る方法があります。しかし、このような複雑な関数では、関数に費やされた時間(2000回と呼ばれます)は、反復メカニズムが費やした時間を支配します。

そして、あなたが第一次元で反復し、他の2(3として配列)を通過しているので、この明示的なループはvectorizefrompyfuncまたはapply_along/over..より使いずっと簡単です。

時間を大幅に節約するには、f()と書いて3dアレイを直接操作する必要があります。

+0

ありがとう@hpaulj。 fがNoneを生成するのは確かに起こり得る。 fは3点の三辺測点を計算し、 'r1'の与えられた値に対しては存在しないこともあります。そのようなケースを扱う適切な方法は何ですか? – patrik

+0

リストの場合は、Noneを返すと問題ありません。問題は、2次元配列で何を望みますか?その場合をスキップしますか?何らかのダミー値を入力してください。このリスト理解アプローチは、多くの柔軟性を提供します。 – hpaulj

+0

ありがとう私はそのシンプルさのためにリストアプローチが好きです。たぶん私は 'f'を練習として書き直して、三辺測点が存在しなければ3つの座標すべてに対して' np.nan'を設定すると思います。 – patrik

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の過剰使用も。

関連する問題