特殊情况之谜的numpy花式广播

时间:2018-06-22 09:04:22

标签: python arrays numpy indexing

我想在顶点之间进行一些力计算,并且由于力是对称的,所以我有一个需要添加这些力的顶点对列表。我相信花式索引是可能的,但是我真的可以使它与慢速的Python for循环一起使用。由于对称的原因,在添加力时索引数组的右侧需要一个负号。

考虑您拥有顶点索引数组:

>>> I = np.array([[0,1],[1,2],[2,0]])
I = [[0 1]
     [1 2]
     [2 0]]

以及每对的x,y force数组:

>>> F = np.array([[3,6],[4,7],[5,8]])
F = [[3 6]
     [4 7]
     [5 8]]

所需的操作可以描述为:

"vertice #0 sums the force vectors (3,6) and (-5,-8),
 vertice #1 sums the force vectors (-3,-6) and (4,7),
 vertice #2 sums the force vectors (-4,-7) and (5,8)"

所需结果:

     [ 3  6 ]   [ 0  0 ]   [-5 -8 ]   [-2 -2 ] //resulting force Vertice #0
A =  [-3 -6 ] + [ 4  7 ] + [ 0  0 ] = [ 1  1 ] //resulting force Vertice #1
     [ 0  0 ]   [-4 -7 ]   [ 5  8 ]   [ 1  1 ] //resulting force Vertice #2

编辑:

我难看的for循环解决方案:

import numpy as np

I = np.array([[0,1],[1,2],[2,0]])
F = np.array([[3,6],[4,7],[5,8]])
A = np.zeros((3,2))

A_x = np.zeros((3,2))
A_y = np.zeros((3,2))

for row in range(0,len(F)):


    A_x[I[row][0],0]= F[row][0]
    A_x[I[row][1],1]= -F[row][0] 

    A_y[I[row][0],0]= F[row][1]
    A_y[I[row][1],1]= -F[row][1] 


A = np.hstack((np.sum(A_x,axis=1).reshape((3,1)),np.sum(A_y,axis=1).reshape((3,1)))) 

print(A)

A=  [[-2. -2.]
     [ 1.  1.]
     [ 1.  1.]]

3 个答案:

答案 0 :(得分:1)

您当前对I的“推送式”解释是

  

对于k中的行索引I,请从F[k]中获取力,并将其添加/减去到out[I[k], :]

I = np.array([[0,1],[1,2],[2,0]])
out = numpy.zeros_like(F)
for k, d in enumerate(I):
    out[d[0], :] += F[k]
    out[d[1], :] -= F[k]
out
# array([[-2, -2],
#        [ 1,  1],
#        [ 1,  1]])

不过,您还可以更改I的含义并将其设置为“拉式”,因此它说

  

对于k中的行索引I,将顶点out[k]设置为F[I[k]]的差异

I = np.array([[0,2],[1,0],[2,1]])
out = numpy.zeros_like(F)
for k, d in enumerate(I):
    out[k, :] = F[d[0], :] - F[d[1], :]
out
# array([[-2, -2],
#        [ 1,  1],
#        [ 1,  1]])

在这种情况下,操作很容易简化为仅花式索引:

out = F[I[:, 0], :] - F[I[:, 1], :]
# array([[-2, -2],
#        [ 1,  1],
#        [ 1,  1]])

答案 1 :(得分:0)

您可以预分配一个数组以容纳随机移动的力量,然后像这样使用索引:

>>> N = I.max() + 1
>>> out = np.zeros((N, 2, 2), F.dtype)
>>> out[I, [1, 0]] = F[:, None, :]
>>> np.diff(out, axis=1).squeeze()
array([[-2, -2],
       [ 1,  1],
       [ 1,  1]])

或等效地

>>> out = np.zeros((2, N, 2), F.dtype)
>>> out[[[1], [0]], I.T] = F
>>> np.diff(out, axis=0).squeeze()
array([[-2, -2],
       [ 1,  1],
       [ 1,  1]])

答案 2 :(得分:0)

根据我对问题的理解,I数组中的值表示涡旋数或涡旋的名称。它们不是实际的位置索引。基于这种想法,我有一个使用原始I数组的解决方案。它并不是没有循环,但是对于合理数量的顶点应该可以:

I = np.array([[0,1],[1,2],[2,0]])   
F = np.array([[3,6],[4,7],[5,8]])

pos = I[:, 0]
neg = I[:, 1]
A = np.zeros_like(F)

unique = np.unique(I)
for i, vortex_number in enumerate(unique):
    A[i] = F[np.where(pos==vortex_number)] - F[np.where(neg==vortex_number)]

# produces the expected result
# [[-2 -2]
#  [ 1  1]
#  [ 1  1]]

也许这个循环也可以用一些麻木的魔法代替。