计算scipy csr矩阵中的欧式距离
Calculate the euclidean distance in scipy csr matrix
我需要计算存储在 csr 稀疏矩阵中的所有点与一些点列表之间的欧氏距离。将 csr 转换为密集的对我来说会更容易,但由于内存不足我不能,所以我需要将其保留为 csr。
例如我有这个 data_csr 稀疏矩阵(同时查看 csr 和 dense):
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 之间的欧氏距离数组就像下面一个。因此,针对 data_csr 中的所有行计算了 center 的每一行中的总共 6 个点中的每个点。结果数组(2,5)的第一行是center第一行和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),center
是 (2,6)。你用这两个数组做什么并不明显。
至于访问'raw'稀疏值,coo
格式最容易理解。它与我用来创建矩阵的行、列、数据相同
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
矩阵乘法比 addition/subtraction 更好。
我等待进一步的说明。
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
是二维数组的步骤,其列数与 xA
相同。然后对于 euclidian
它调用
_distance_wrap.cdist_euclidean_wrap(_convert_to_double(XA),
_convert_to_double(XB), dm)
这看起来像是一些 C 代码的包装器。我无法想象有什么方法可以为它提供稀疏矩阵。
您可以遍历行;用 M[[0],:].A
调用 dist
与 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)
文档:http://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.pairwise_distances.html
我需要计算存储在 csr 稀疏矩阵中的所有点与一些点列表之间的欧氏距离。将 csr 转换为密集的对我来说会更容易,但由于内存不足我不能,所以我需要将其保留为 csr。
例如我有这个 data_csr 稀疏矩阵(同时查看 csr 和 dense):
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 之间的欧氏距离数组就像下面一个。因此,针对 data_csr 中的所有行计算了 center 的每一行中的总共 6 个点中的每个点。结果数组(2,5)的第一行是center第一行和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),center
是 (2,6)。你用这两个数组做什么并不明显。
至于访问'raw'稀疏值,coo
格式最容易理解。它与我用来创建矩阵的行、列、数据相同
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
矩阵乘法比 addition/subtraction 更好。
我等待进一步的说明。
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
是二维数组的步骤,其列数与 xA
相同。然后对于 euclidian
它调用
_distance_wrap.cdist_euclidean_wrap(_convert_to_double(XA),
_convert_to_double(XB), dm)
这看起来像是一些 C 代码的包装器。我无法想象有什么方法可以为它提供稀疏矩阵。
您可以遍历行;用 M[[0],:].A
调用 dist
与 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)
文档:http://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.pairwise_distances.html