numpy创建nxn数组的nx2点数乘积nxnx2数组

时间:2017-11-23 03:05:48

标签: python numpy multidimensional-array vector masked-array

我的目标是在模拟中为所有粒子创建一个粒子与每个其他粒子之间角度的nxn数组。然后,蒙版数组可以选择特定视野中的所有粒子。

我的问题是如何逐行取两个nxn数组(dx /距离和dy /距离)并使用nx2向量的行获取点积,得到一个粒子与另一个粒子之间的nx1角度数组粒子。对所有行重复此操作,并生成所有角度的nxn数组。

上下文 - 有n个位置(x,y)和速度(x,y)的粒子。可以通过创建n×n阵列dx和n×n阵列dy来计算每个粒子之间的偏移矢量。偏移向量(从粒子i到粒子j)是(xi-xj,yi-yj),我们可以从(dx,dy)得到。创建单位矢量分量dx /距离和dy /距离。

n = 4
k = 10
width = 50
boid_radius = 8
dim = 2

position = np.random.rand(n, dim) * width  # random dataset
velocity = 0.5 * np.random.random_sample((n, dim)) + 1

from sklearn import preprocessing as pp
velocity_normalized = pp.normalize(velocity)

dx = np.subtract.outer(position[:, 0], position[:, 0])
dy = np.subtract.outer(position[:, 1], position[:, 1])
distance = np.hypot(dx, dy)
# mask zeros
ox = dx/distance
ox = dy/distance

示例数据:

position
Out[233]: 
array([[  6.68625116,  34.35642605],
       [ 18.96766714,  45.61291941],
       [ 49.49921981,  37.95450382],
       [ 28.22272906,  42.90652135]])

dx
Out[234]: 
array([[  0.        , -12.28141597, -42.81296865, -21.5364779 ],
       [ 12.28141597,   0.        , -30.53155268,  -9.25506192],
       [ 42.81296865,  30.53155268,   0.        ,  21.27649075],
       [ 21.5364779 ,   9.25506192, -21.27649075,   0.        ]])

dy
Out[235]: 
array([[  0.        , -11.25649336,  -3.59807777,  -8.5500953 ],
       [ 11.25649336,   0.        ,   7.65841559,   2.70639806],
       [  3.59807777,  -7.65841559,   0.        ,  -4.95201753],
       [  8.5500953 ,  -2.70639806,   4.95201753,   0.        ]])

形成偏移单位矢量分量:

distance = np.hypot(dx, dy).round()
array([[  0.,  17.,  43.,  23.],
       [ 17.,   0.,  31.,  10.],
       [ 43.,  31.,   0.,  22.],
       [ 23.,  10.,  22.,   0.]])

zeros = ma.masked_where(distance==0, distance)
masked_array(data =
 [[-- 17.0 43.0 23.0]
 [17.0 -- 31.0 10.0]
 [43.0 31.0 -- 22.0]
 [23.0 10.0 22.0 --]],
             mask =
 [[ True False False False]
 [False  True False False]
 [False False  True False]
 [False False False  True]],
       fill_value = 1e+20)

ox = dx / zeros
masked_array(data =
 [[-- -0.7224362336046727 -0.9956504337130146 -0.9363686041759272]
 [0.7224362336046727 -- -0.9848887960767806 -0.9255061924766889]
 [0.9956504337130146 0.9848887960767806 -- 0.9671132160733322]
 [0.9363686041759272 0.9255061924766889 -0.9671132160733322 --]],
             mask =
 [[ True False False False]
 [False  True False False]
 [False False  True False]
 [False False False  True]],
       fill_value = 1e+20)

下一步是在单位速度矢量和单位偏移矢量之间取点积。这就是我被困的地方。

velocity
Out[239]: 
array([[ 1.08980931,  1.10142992],
       [ 1.42378512,  1.31445528],
       [ 1.4599431 ,  1.34567875],
       [ 1.45934809,  1.03997269]])

pp.normalize(velocity)
Out[242]: 
array([[ 0.70334695,  0.71084672],
       [ 0.73475404,  0.67833363],
       [ 0.73529551,  0.67774665],
       [ 0.81437139,  0.58034407]])

下一步?我无法解决如何将矢量索引以使numpy看起来像神奇的方式完成所有操作。

1 个答案:

答案 0 :(得分:0)

谢谢@kazemakase,回答盯着我的脸......试图寻找过于复杂的。

import numpy as np
import sklearn.preprocessing as pp
import numpy.ma as ma

n = 4 # number of particles
dim = 2 # x and y coords

pos = np.random.randint(0,9,(n,2))
vel = np.random.randint(0,9,(n,2))
vel_unit = pp.normalize(vel)

dx = np.subtract.outer(pos[:,0], pos[:,0])
dy = np.subtract.outer(pos[:,1], pos[:,1])
distance = np.hypot(dx, dy).round()
m = ma.masked_where(distance==0, distance)
o_unit_x = dx/m
o_unit_y = dy/m
angles = o_unit_y * vel_unit[:,1] + o_unit_x * vel_unit[:,0]

只需要测试一下这是对的,并且它正在做我认为的事情。

示例输出:

pos
Out[154]: 
array([[6, 1],
       [5, 7],
       [0, 7],
       [5, 2]])

vel
Out[155]: 
array([[6, 3],
       [7, 5],
       [5, 4],
       [2, 2]])

distance
Out[156]: 
array([[ 0.,  6.,  8.,  1.],
       [ 6.,  0.,  5.,  5.],
       [ 8.,  5.,  0.,  7.],
       [ 1.,  5.,  7.,  0.]])

angles.round(3)
Out[158]: 
masked_array(data =
 [[-- -0.446 0.117 0.0]
 [0.298 -- 0.781 0.707]
 [-0.335 -0.814 -- 0.0]
 [-0.447 -0.581 0.112 --]],
             mask =
 [[ True False False False]
 [False  True False False]
 [False False  True False]
 [False False False  True]],
       fill_value = 1e+20)