两点之间的x距离

2024-06-16 12:40:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个1D numpy数组A和B,大小分别为(n,)和(m,),它们对应于一条线上点的x位置。我要计算A中的每个点到B中的每个点之间的距离,然后我需要用这些距离在一个设定的y距离,d,计算出A中每个点的电势

我目前使用的是:

V = numpy.zeros(n)
for i in range(n):
    xdist = A[i] - B
    r = numpy.sqrt(xdist**2 + d**2)
    dV = 1/r
    V[i] = numpy.sum(dV)

这是可行的,但对于大型数据集,它可能需要一段时间,所以我想使用一个类似于scipy.spatial.distance公司.cdist,它不适用于1D数组,我不想在数组变得太大时再添加其他维度。在


Tags: 数据innumpy距离forzerosrangescipy
3条回答

I would like to use a function similar to scipy.spatial.distance.cdist which doesn't work for 1D arrays and I don't want to add another dimension to the arrays as they become too large.

^{}效果很好,您只需重新塑造数组的形状(n,1),而不是(n,)。您可以使用A[:, None]A.reshape(-1, 1)向一维数组A添加另一个维度,而无需复制底层数据。在

例如

In [56]: from scipy.spatial.distance import cdist

In [57]: A
Out[57]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [58]: B
Out[58]: array([0, 2, 4, 6, 8])

In [59]: A[:, None]
Out[59]: 
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7],
       [8],
       [9]])

In [60]: cdist(A[:, None], B[:, None])
Out[60]: 
array([[ 0.,  2.,  4.,  6.,  8.],
       [ 1.,  1.,  3.,  5.,  7.],
       [ 2.,  0.,  2.,  4.,  6.],
       [ 3.,  1.,  1.,  3.,  5.],
       [ 4.,  2.,  0.,  2.,  4.],
       [ 5.,  3.,  1.,  1.,  3.],
       [ 6.,  4.,  2.,  0.,  2.],
       [ 7.,  5.,  3.,  1.,  1.],
       [ 8.,  6.,  4.,  2.,  0.],
       [ 9.,  7.,  5.,  3.,  1.]])

要计算代码中显示的V,可以将cdist与{}一起使用,如下所示:

^{pr2}$

矢量化方法

A扩展到{}之后的一种矢量化方法是-

(1/(np.sqrt((A[:,None] - B)**2 + d**2))).sum(1)

大型阵列的混合方法

现在,对于大型数组,我们可能需要将数据分成块。在

因此,使用BSZ作为块大小,我们将使用一种混合方法,如-

^{pr2}$

运行时测试

方法-

def original_app(A,B,d):
    V = np.zeros(n)
    for i in range(n):
        xdist = A[i] - B
        r = np.sqrt(xdist**2 + d**2)
        dV = 1/r
        V[i] = np.sum(dV)
    return V

def vectorized_app1(A,B,d):
    return (1/(np.sqrt((A[:,None] - B)**2 + d**2))).sum(1)

def vectorized_app2(A,B,d, BSZ = 100):
    dsq = d**2   
    V = np.zeros((n//BSZ,BSZ))
    for i in range(n//BSZ):
        V[i] = (1/(np.sqrt((A[i*BSZ:(i+1)*BSZ,None] - B)**2 + dsq))).sum(1)
    return V.ravel()

时间安排和验证-

In [203]: # Setup inputs
     ...: n,m = 10000,2000
     ...: A = np.random.rand(n)
     ...: B = np.random.rand(m)
     ...: d = 10
     ...: 

In [204]: out1 = original_app(A,B,d)
     ...: out2 = vectorized_app1(A,B,d)
     ...: out3 = vectorized_app2(A,B,d, BSZ = 100)
     ...: 
     ...: print np.allclose(out1, out2)
     ...: print np.allclose(out1, out3)
     ...: 
True
True

In [205]: %timeit original_app(A,B,d)
10 loops, best of 3: 133 ms per loop

In [206]: %timeit vectorized_app1(A,B,d)
10 loops, best of 3: 138 ms per loop

In [207]: %timeit vectorized_app2(A,B,d, BSZ = 100)
10 loops, best of 3: 65.2 ms per loop

我们可以使用参数块大小BSZ-

In [208]: %timeit vectorized_app2(A,B,d, BSZ = 200)
10 loops, best of 3: 74.5 ms per loop

In [209]: %timeit vectorized_app2(A,B,d, BSZ = 50)
10 loops, best of 3: 67.4 ms per loop

因此,最好的方法似乎是在我的末尾提供一个块大小为2x的加速。在

编辑:经过仔细观察,我的答案与Divakar的答案几乎相同。不过,在某些地方做一些操作可以节省内存。沿着第二个轴求和比长第一个轴更有效。在

import numpy

a = numpy.random.randint(0,10,10) * 1.
b = numpy.random.randint(0,10,10) * 1.

xdist = a[:,None] - b
xdist **= 2
xdist += d**2
xdist **= -1
V = numpy.sum(xdist, axis=1)

它提供了与代码相同的解决方案。在

相关问题 更多 >