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

Python 计算scipy csr矩阵中的欧氏距离,python,sparse-matrix,euclidean-distance,Python,Sparse Matrix,Euclidean Distance,我需要计算存储在csr稀疏矩阵和一些点列表中的所有点之间的欧氏距离。对我来说,将csr转换为稠密的csr会更容易,但由于内存不足,我无法将其转换为稠密的csr,因此我需要将其保留为csr 例如,我有一个数据\u csr稀疏矩阵(csr和稠密视图): 这个中心列出了一些点: center array([[0, 1, 2, 2, 4, 1], [3, 4, 1, 2, 4, 0]]) 使用scipy.spatial包,data_csr和center之间的欧几里德距离数组如下所示。因此,

我需要计算存储在csr稀疏矩阵和一些点列表中的所有点之间的欧氏距离。对我来说,将csr转换为稠密的csr会更容易,但由于内存不足,我无法将其转换为稠密的csr,因此我需要将其保留为csr

例如,我有一个数据\u csr稀疏矩阵(csr和稠密视图):

这个中心列出了一些点:

center
array([[0, 1, 2, 2, 4, 1],
      [3, 4, 1, 2, 4, 0]])
使用
scipy.spatial
包,data_csr和center之间的欧几里德距离数组如下所示。因此,根据数据中的所有行计算中心每行总共6个点中的每个点。结果数组(2,5)的第一行是数据_csr中第一行中心和所有行之间的ED


到目前为止,我所学到的是,我可以通过以下方式获得非零值和索引:

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。

因此,让我们创建您的矩阵(很遗憾,您没有提供我可以复制粘贴的输入)

csr
数据
索引
indptr
数组中存储相同的信息。但是你必须做一些数学运算,才能得出最后2个变量的
i,j
csr
乘法例程充分利用了这些数组

一般来说,使用
csr
矩阵进行乘法比加法/减法更好

我等待进一步澄清


我们需要做的是研究这个函数,了解它的输入。我们可能不得不超越它的文档,看看代码

但看看这段代码,我看到了确保
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
是行迭代中最快的两个

下面是一些可能更快的方法-直接迭代
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]])

现在我将跳过时间测试。

稀疏矩阵上的成对欧几里德距离在sklearn中实现(正如hpaulj所指出的,scipy实现在稀疏矩阵上不起作用)

hpaulj示例示例:

import scipy.sparse
import sklearn.metrics.pairwise
data = [4,1,2,2,1,1,4,3,2]  
col = [0,1,1,2,2,3,4,4,4]
row = [2,0,4,0,3,5,0,2,3]
M = scipy.sparse.csr_matrix((data,(col,row)))
distances = sklearn.metrics.pairwise.pairwise_distances(M,M)

文档:

如何计算数据与中心之间的ED(假设密集)?@Alexander我已经编辑了它,我使用了
scipy.spatial.distance.cdist(中心,数据与中心,欧几里德),
我仍然无法复制您的结果来计算上述距离。关于如何从矩阵中提取数据,请参阅本文,这是我所掌握的。我已经编辑了这个案例,并解释了我是如何计算的,希望它足够清晰易懂。使用
scipy.spatial.distance.cdist(中心,数据_csr,'euclidean')
只是为了理解稀疏矩阵上下文。我正在读这篇文章,似乎
sklearn``成对距离
非常“低效”,但另一方面,这里似乎是一个不错的选择,你认为哪一个最快?
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])
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]])
_distance_wrap.cdist_euclidean_wrap(_convert_to_double(XA),
                                    _convert_to_double(XB), dm)
 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]])
import scipy.sparse
import sklearn.metrics.pairwise
data = [4,1,2,2,1,1,4,3,2]  
col = [0,1,1,2,2,3,4,4,4]
row = [2,0,4,0,3,5,0,2,3]
M = scipy.sparse.csr_matrix((data,(col,row)))
distances = sklearn.metrics.pairwise.pairwise_distances(M,M)