我在(x,y)
对中有一个点列表,它表示代理列表的位置。例如,给定3个代理,有3对点,我将其存储如下:
points = np.array([[x1, y1],
[x2, y2],
[x3, y3]])
我想计算一个后续数组,即一个代理到每个其他代理之间的相对位置,而不是它本身。因此,使用上面的数据,我想使用数组relative_positions
生成数组points
。points
可以有N
的位置(我可以在任何时候有超过50-100个代理).
因此,使用上面描述的points
,我希望生成输出:
relative_positions = [[x2-x1, y2-y1],
[x3-x1, y3-y1],
[x1-x2, y1-y2],
[x3-x2, y3-y2],
[x1-x3, y1-y3],
[x2-x3, y2-y3]]
例如,给定作为numpy数组存储的四个代理位置:
agent_points = np.array([[10, 1],
[30, 3],
[25, 10],
[5, 5]])
我想要生成输出:
relative_positions = [[30-10, 3-1],
[25-10, 10-1],
[5-10, 5-1],
[10-30, 1-3],
[25-30, 10-3],
[5-30, 5-3],
[10-25, 1-10],
[30-25, 3-10],
[5-25, 5-10],
[10-5, 1-5],
[30-5, 3-5],
[25-5, 10-5]]
我怎样才能有效地做到这一点呢?我考虑过只计算每一个可能的差异,并移除0的情况(当它是从代理到其自身的相对位置时),但是我不认为这是一种“纯”的方法,因为我可能会意外地删除刚好处于同一点(或非常接近)的代理。
发布于 2019-04-09 08:40:10
方法#1
使用a
输入数组,您可以-
d = (a-a[:,None,:])
valid_mask = ~np.eye(len(a),dtype=bool)
out = d[valid_mask]
基本上,我们将a
扩展到3D
,使第一个轴成为outer-broadcastable
,然后对其2D
版本执行减法,从而产生mxmx2
形状的输出,而m
是a.shape[0]
。按示意图-
a[:, None, :] : 4 x 1 x 2
a : 4 x 2
output : 4 x 4 x 2
另一种创建valid_mask
的方法是-
r = np.arange(len(a))
valid_mask = r[:,None] != r
方法#2
我们将利用np.lib.stride_tricks.as_strided
为3D
数组(沿前两个轴)获得一个无对角线掩码,因此我们将在这里使用它来掩盖差异数组d
。这个掩码生成是受2D
数组问题(如发布的here )的启发,对于3D
情况,如下所示-
def nodiag_view3D(a):
m = a.shape[0]
p,q,r = a.strides
return np.lib.stride_tricks.as_strided(a[:,1:], shape=(m-1,m,2), strides=(p+q,q,r))
为了解决我们的问题,应该是-
d = (a-a[:,None,:])
out = nodiag_view3D(d).reshape(-1,a.shape[1])
展示approach#2在#1上是如何改进的
In [96]: a = np.random.rand(5000,2)
In [97]: d = (a-a[:,None,:])
In [98]: %%timeit
...: valid_mask = ~np.eye(len(a),dtype=bool)
...: out = d[valid_mask]
1 loop, best of 3: 763 ms per loop
In [99]: %%timeit
...: r = np.arange(len(a))
...: valid_mask = r[:,None] != r
...: out = d[valid_mask]
1 loop, best of 3: 767 ms per loop
In [100]: %timeit nodiag_view3D(d).reshape(-1,a.shape[1])
10 loops, best of 3: 177 ms per loop
发布于 2019-04-09 08:30:57
虽然我没有一个numpy特定的解决方案(我肯定它存在),但是双循环和id检查可以很好地完成这个任务。不过,如果points
增长的话,还需要一些时间。
points = [
[x1, y1],
[x2, y2],
[x3, y3]
]
relative_positions = []
for point1 in points:
for point2 in point:
if id(point1) != id(point2):
relative_positions.append([CALC_HERE_OR_FUNCTION])
https://stackoverflow.com/questions/55588122
复制相似问题