Python 如何有效地比较numpy数组中的条目?

Python 如何有效地比较numpy数组中的条目?,python,arrays,pandas,numpy,vectorization,Python,Arrays,Pandas,Numpy,Vectorization,我有一个numpy数组embed_-vec,长度tot_-vec,其中每个条目都是一个3d向量: [[ 0.52483319 0.78015841 0.71117216] [ 0.53041481 0.79462171 0.67234534] [ 0.53645428 0.80896727 0.63119403] ..., [ 0.72283509 0.40070804 0.15220522] [ 0.71277758 0.38498613 0.16141834]

我有一个numpy数组
embed_-vec
,长度
tot_-vec
,其中每个条目都是一个3d向量:

[[ 0.52483319  0.78015841  0.71117216]
 [ 0.53041481  0.79462171  0.67234534]
 [ 0.53645428  0.80896727  0.63119403]
 ..., 
 [ 0.72283509  0.40070804  0.15220522]
 [ 0.71277758  0.38498613  0.16141834]
 [ 0.70221445  0.36918032  0.17370776]]
对于这个数组中的每个元素,我想找出“接近”该条目的其他条目的数量。闭合是指两个向量之间的距离小于指定值
R
。为此,我必须将此数组中所有可能的对相互比较,然后找出数组中每个向量的闭合向量数。因此,我正在这样做:

p = np.zeros(tot_vec) # This contains the number of close vectors
for i in range(tot_vec-1):
    for j in range(i+1, tot_vec):
        if np.linalg.norm(embed_vec[i]-embed_vec[j]) < R:
            p[i] += 1
p=np.zeros(tot_vec)#包含闭合向量的数量
对于范围内的i(tot_vec-1):
对于范围内的j(i+1,tot_vec):
如果np.linalg.norm(嵌入向量[i]-嵌入向量[j])
然而,这是非常低效的,因为我有两个嵌套的python循环,对于更大的数组大小,这需要花费很长时间。如果这是在C++或FORTRAN中,那就不是一个大问题。我的问题是,使用一些矢量化方法可以有效地使用numpy实现同样的事情吗?作为补充说明,我不介意也使用熊猫来解决问题

方法#1:矢量化方法-

def vectorized_app(embed_vec, R):  
    tot_vec = embed_vec.shape[0]          
    r,c = np.triu_indices(tot_vec,1)
    subs = embed_vec[r] - embed_vec[c]
    dists = np.einsum('ij,ij->i',subs,subs)
    return np.bincount(r,dists<R**2,minlength=tot_vec)
def loopy_app(embed_vec, R):
    tot_vec = embed_vec.shape[0]
    p = np.zeros(tot_vec) # This contains the number of close vectors
    for i in range(tot_vec-1):
        for j in range(i+1, tot_vec):
            if np.linalg.norm(embed_vec[i]-embed_vec[j]) < R:
                p[i] += 1
    return p                
350x+
在那里加速

使用建议的
loopy\u less\u应用程序使用更大的阵列
-

In [81]: # Sample random array
    ...: embed_vec = np.random.rand(20000,3)
    ...: R = 0.5
    ...: 

In [82]: %timeit loopy_less_app(embed_vec, R)
1 loops, best of 3: 4.47 s per loop

首先,广播不同之处:

disp_vecs=tot_vec[:,无,:]-tot_vec[无,:,:]

现在,根据你的数据集有多大,你可能想做一个没有全部数学知识的第一关。如果距离小于
r
,则所有部件应小于
r


first_mask=np.max(disp_vec,axis=-1)我对这个问题很感兴趣,并试图用scipy的方法有效地解决它。但是,这种方法可能会耗尽内存,因为在内部有一个所有对的列表,其中包含距离
嵌入向量在您的实际用例中的形状是什么?@Divakar:It is
(60000,3)
@我删除了注释,因为您使用的是多维距离。尽管我可能会尝试使用一些逻辑,但这是一个明显不同的问题,您可以使用scipy来获得距离矩阵。如果tot_vec
很大,可能会遇到内存问题。应该有人为此实施一些措施。这一定是问得最多的问题了。这给了我:
ValueError:array太大了arr.size*arr.dtype.itemsize`大于最大可能大小`@和平退房方式#2?希望这对您的
(60000,3)
阵列有好处!这的确令人印象深刻。你能解释一下我如何修改一维向量吗?因为在这种情况下它抛出错误:
ValueError:einstein sum subscripts string包含太多操作数0的下标对于1D数组,跳过
einsum
步骤,在最后一步执行:
out[i]=np.count\u非零(np.abs(subs)
用于
无循环应用程序
方法。如果输入数组都是1D和排序的,如何进一步加快速度?你的意思是写
嵌入vec
来代替
tot\u vec
?我在研究kmeans,但没有运气。很高兴看到它用于解决这个问题!那怎么办?@Divakar我猜
count\u neights
效率较低,因为它要在两棵树上运行,因此可能会遍历树两次。不过我没试过,我明白了。不太熟悉kmeans工具:)我想看看一些时间安排会很有趣。
In [76]: # Sample random array
    ...: embed_vec = np.random.rand(3000,3)
    ...: R = 0.5
    ...: 

In [77]: %timeit loopy_app(embed_vec, R)
1 loops, best of 3: 50.5 s per loop

In [78]: %timeit loopy_less_app(embed_vec, R)
10 loops, best of 3: 143 ms per loop
In [81]: # Sample random array
    ...: embed_vec = np.random.rand(20000,3)
    ...: R = 0.5
    ...: 

In [82]: %timeit loopy_less_app(embed_vec, R)
1 loops, best of 3: 4.47 s per loop
disps=np.linlg.norm(disp_vec[first_mask],axis=-1)
second_mask=disps<r
disps=disps[second_mask]
first_mask[first_mask]=second_mask
import numpy as np
from scipy.spatial import cKDTree as KDTree

tot_vec = 60000
embed_vec = np.random.randn(tot_vec, 3)
R = 0.1

tree = KDTree(embed_vec, leafsize=100)
p = np.zeros(tot_vec)
for pair in tree.query_pairs(R):
    p[pair[0]] += 1
    p[pair[1]] += 1