【问题标题】:How to calculate the relative vectors from a list of points, from one point to every other point如何从点列表中计算相对向量,从一个点到每个其他点
【发布时间】:2019-04-09 17:24:56
【问题描述】:

我有一个(x,y) 对中的点列表,它表示代理列表的位置。例如,给定 3 个代理,有 3 对点,我存储如下:

points = np.array([[x1, y1],
                   [x2, y2],
                   [x3, y3]])

我想计算一个后续数组,即从一个代理到所有其他代理的相对位置,但不是它本身。因此,使用上面的数据,我想使用数组points 生成数组relative_positions。 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 个案例(因为它是代理到自身的相对位置),但是我不认为这是一种“纯粹”的方式,因为我可能会不小心删除恰好在同一点(或非常接近)的代理

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    方法#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
    

    More info.

    创建valid_mask 的另一种方法是 -

    r = np.arange(len(a))
    valid_mask = r[:,None] != r
    

    方法 #2

    我们将利用np.lib.stride_tricks.as_strided 为3D 数组(沿前两个轴)获取非对角掩码,以便我们在此处使用它来掩码差异数组d。这个掩码生成的灵感来自here 发布的2D 数组问题,而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])
    

    展示方法#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
    

    【讨论】:

    • 这是一个非常优雅的解决方案。我了解大部分情况,您能否解释一下a[:,None,:] 在这种情况下的作用?
    • @Athena 添加了一些 cmets。
    【解决方案2】:

    虽然我没有特定于 numpy 的解决方案(我确定它存在),但双 for 循环和 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])
    

    【讨论】:

    • 谢谢,我考虑过这个选项,但是我可能正在寻找 numpy 特定的解决方案,因为我关心速度(这个计算可以在每集 100k-10M 次之间执行
    猜你喜欢
    • 1970-01-01
    • 2015-11-12
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 2016-10-03
    • 1970-01-01
    相关资源
    最近更新 更多