编程语言
首页 > 编程语言> > python – 计算scipy csr矩阵中的欧氏距离

python – 计算scipy csr矩阵中的欧氏距离

作者:互联网

我需要计算存储在csr稀疏矩阵和一些点列表中的所有点之间的欧几里德距离.将csr转换为密集的csr会更容易,但由于缺少内存,我不能这样做,所以我需要将它保持为csr.

所以例如我有这个data_csr稀疏矩阵(两者中的视图,csr和密集):

data_csr
(0, 2)  4
(1, 0)  1
(1, 4)  2
(2, 0)  2
(2, 3)  1
(3, 5)  1
(4, 0)  4
(4, 2)  3
(4, 3)  2

data_csr.todense()
[[0, 0, 4, 0, 0, 0]
 [1, 0, 0, 0, 2, 0]
 [2, 0, 0, 1, 0, 0]
 [0, 0, 0, 0, 0, 1]
 [4, 0, 3, 2, 0, 0]]

这个中心点列表:

center
array([[0, 1, 2, 2, 4, 1],
      [3, 4, 1, 2, 4, 0]])

使用scipy.spatial包,data_csr和center之间的Euclidean Distance数组将如下所示.因此,每个中心行中的每个点(总共6个点)是针对data_csr中的所有行计算的.结果数组(2,5)的第一行是第一行中心与data_csr中所有行之间的ED.

scipy.spatial.distance.cdist(center, data_csr, 'euclidean')

array([[ 5.09901951,  3.87298335,  5.19615242,  5.        ,  5.91607978],
      [ 7.34846923,  5.38516481,  5.91607978,  6.8556546 ,  6.08276253]])

到目前为止我学到的东西,我可以获得非零值以及索引:

data_csr.data
array([4, 1, 2, 2, 1, 1, 4, 3, 2])

data_csr.indices
array([2, 0, 4, 0, 3, 5, 0, 2, 3])

但我仍然无法弄清楚如何计算这两个对象之间的ED.

解决方法:

所以让我们创建你的矩阵(太糟糕了,你没有提供我可以复制粘贴的输入)

In [114]: data=[4,1,2,2,1,1,4,3,2]   
In [115]: col=[0,1,1,2,2,3,4,4,4]
In [116]: row=[2,0,4,0,3,5,0,2,3]
In [117]: M=sparse.csr_matrix((data,(col,row)))

In [118]: M
Out[118]: 
<5x6 sparse matrix of type '<type 'numpy.int32'>'
    with 9 stored elements in Compressed Sparse Row format>

In [119]: M.A
Out[119]: 
array([[0, 0, 4, 0, 0, 0],
       [1, 0, 0, 0, 2, 0],
       [2, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 1],
       [4, 0, 3, 2, 0, 0]])

In [121]: center=np.array([[0,1,2,2,4,1],[3,4,1,2,4,0]])

那么你是如何计算距离的? M.A是(5,6),中心是(2,6).你用这两个数组做什么并不明显.

至于访问’原始’稀疏值,最简单的格式是最容易理解的.它与我用于创建矩阵的行,列,数据相同

In [131]: M.tocoo().data
Out[131]: array([4, 1, 2, 2, 1, 1, 4, 3, 2])

In [132]: M.tocoo().col
Out[132]: array([2, 0, 4, 0, 3, 5, 0, 2, 3])

In [133]: M.tocoo().row
Out[133]: array([0, 1, 1, 2, 2, 3, 4, 4, 4])

csr在data,indices和indptr数组中存储相同的信息.但是你必须做一些数学运算才能从最后的2中获取i,j值.csr乘法例程充分利用了这些数组.

通常,与加法/减法相比,使用csr矩阵进行乘法更好.

我等待进一步澄清.

spatial.distance.cdist(center,M.A, 'euclidean')
Out[156]: 
array([[ 5.09901951,  3.87298335,  5.19615242,  5.        ,  5.91607978],
       [ 7.34846923,  5.38516481,  5.91607978,  6.8556546 ,  6.08276253]])

我们需要做的是研究这个功能,并了解它的输入.我们可能不得不超越其文档并查看代码.

但是看看这段代码,我看到了确保xB是2d数组的步骤,其列数与xA相同.然后为欧几里得调用它

_distance_wrap.cdist_euclidean_wrap(_convert_to_double(XA),
                                    _convert_to_double(XB), dm)

它看起来像是某些C代码的包装器.我无法想象任何以稀疏矩阵为食的方式.

你可以遍历行;用M [[0],:]调用dist .A与M.A [[0],]相同 – 除了速度.迭代稀疏矩阵的行有点慢,因为它必须在每次迭代时构造一个新的稀疏矩阵.行迭代中csr和lil是最快的2.

这里的内容可能更快 – 直接迭代lil格式的属性:

 def foo(a,b,n):
    # make a dense array from data,row
    res = np.zeros((1,n))
    res[0,b]=a
    return res

In [190]: Ml=M.tolil()

In [191]: Ml.data
Out[191]: array([[4], [1, 2], [2, 1], [1], [4, 3, 2]], dtype=object)

In [192]: Ml.rows
Out[192]: array([[2], [0, 4], [0, 3], [5], [0, 2, 3]], dtype=object)

In [193]: rowgen=(foo(a,b,6) for a,b in zip(Ml.data,Ml.rows))

In [194]: np.concatenate([spatial.distance.cdist(center,row, 'euclidean') for row in rowgen],axis=1)
Out[194]: 
array([[ 5.09901951,  3.87298335,  5.19615242,  5.        ,  5.91607978],
       [ 7.34846923,  5.38516481,  5.91607978,  6.8556546 ,  6.08276253]])

现在我将跳过时间测试.

标签:python,sparse-matrix,euclidean-distance
来源: https://codeday.me/bug/20190527/1167108.html