我想(有效地)找到所有比某个距离更近的点对max_d
。我当前使用cdist
的方法是:
import numpy as np
from scipy.spatial.distance import cdist
def close_pairs(X,max_d):
d = cdist(X,X)
I,J = (d<max_d).nonzero()
IJ = np.sort(np.vstack((I,J)), axis=0)
# remove diagonal element
IJ = IJ[:,np.diff(IJ,axis=0).ravel()<>0]
# remove duplicate
dt = np.dtype([('i',int),('j',int)])
pairs = np.unique(IJ.T.view(dtype=dt)).view(int).reshape(-1,2)
return pairs
def test():
X = np.random.rand(100,2)*20
p = close_pairs(X,2)
from matplotlib import pyplot as plt
plt.clf()
plt.plot(X[:,0],X[:,1],'.r')
plt.plot(X[p,0].T,X[p,1].T,'-b')
但我认为这是一个过度的杀戮(而且不太可读),因为大部分的工作只是为了消除与自我和重复的距离。在
我的主要问题是:有更好的方法吗?在
(注意:输出类型(array
,set
,…)在这一点上并不重要)
{My-thinking数组{My-thinking-on-current}只返回当前的距离。然而,一旦我从压缩距离数组中找到合适的坐标k
,我如何计算它与哪个i,j
对等价?在
所以另一个问题是:有没有一种简单的方法来获得pdist
输出项的坐标对列表:
f(k)->i,j
cdist(X,X)[i,j] = pdist(X)[k]
下面我比较四种方法:
Scipy.spatial.ckdtree
scipy.spatial.distance.pdist
测试设置:
n
点分散在体积密度为0.2的矩形框中。系统大小从10到1000000(一百万)个粒子。接触半径取自0.5, 1, 2, 4, 7, 10
。注意,因为密度是0.2,在接触半径为0.5时,我们平均每个粒子有0.1个接触点,1=0.8,2=6.4,10-大约800!对小系统重复多次接触发现,对大于30k粒子的系统重复一次。如果每次呼叫的时间超过5秒,则中止运行。在设置:dual xeon 2687Wv3,128GB内存,Ubuntu 14.04,python 2.7.11,scipy 0.16.0,numpy 1.10.1。所有的代码都没有使用并行优化(除了OpenMM,尽管并行部分运行得非常快,以至于在CPU图上甚至都不明显,但大部分时间都是通过管道将数据从OpenMM传递出去)。在
结果:请注意,下面的曲线图是对数标度,分布在6个数量级上。即使是很小的视觉差异,实际上也可能是10倍。 对于少于1000个粒子的系统,
Cython
代码总是更快。但是,1000个粒子之后,结果取决于接触半径。pdist
实现总是比cython慢,并且占用更多的内存,因为它显式地创建了一个距离矩阵,这是由于sqrt而导致的。在ckdtree
是所有系统尺寸的好选择。在ckdtree
的性能仅差3-10倍安装OpenMM非常棘手;您可以在http://bitbucket.org/mirnylab/openmm-polymer文件中阅读更多内容”联系人地图.py“或者在自述中。然而,下面的结果表明,对于N>;100k粒子,每个粒子只有5-50个接触点才是有利的。在
Cython代码如下:
Cython代码的编译(或生成文件):
^{pr2}$测试代码:
我终于自己找到了。将压缩距离数组中的索引
k
转换为平方距离数组中的等价i,j
的函数为:我不得不和
^{pr2}$sympy
玩了一会儿才能找到它。现在,要计算相距小于给定距离的所有点对:正如预期的那样,它比其他方法更有效(但是我没有测试ckdtree)。我将更新timeit答案。在
下面是如何使用cKDTree模块来实现这一点。见query_pairs
相关问题 更多 >
编程相关推荐