Python Scipy稀疏:意外的身份行为

Python Scipy稀疏:意外的身份行为,python,scipy,Python,Scipy,下面是我创建一个稀疏矩阵的尝试,该矩阵的对角线为c。我知道还有其他方法可以实现这一点,但我很好奇为什么下面的代码没有按预期工作: import numpy as np import scipy.sparse as sparse c = np.arange(0,5) >>> np.identity(5)*c array([[ 0., 0., 0., 0., 0.], [ 0., 1., 0., 0., 0.], [ 0., 0.,

下面是我创建一个稀疏矩阵的尝试,该矩阵的对角线为
c
。我知道还有其他方法可以实现这一点,但我很好奇为什么下面的代码没有按预期工作:

import numpy as np
import scipy.sparse as sparse

c = np.arange(0,5)
>>> np.identity(5)*c
array([[ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  0.,  0.,  0.],
       [ 0.,  0.,  2.,  0.,  0.],
       [ 0.,  0.,  0.,  3.,  0.],
       [ 0.,  0.,  0.,  0.,  4.]])
>>> sparse.identity(5)*c
array([ 0.,  1.,  2.,  3.,  4.])
#expected output:
<5x5 sparse matrix of type '<type 'numpy.float64'>'
with 5 stored elements (1 diagonals) in DIAgonal format>
# and (sparse.identity(5)*c).todense() == np.identity(5)*c
将numpy导入为np
将scipy.sparse导入为稀疏
c=np.arange(0,5)
>>>np.标识(5)*c
数组([[0,0,0,0,0,0.]),
[ 0.,  1.,  0.,  0.,  0.],
[ 0.,  0.,  2.,  0.,  0.],
[ 0.,  0.,  0.,  3.,  0.],
[ 0.,  0.,  0.,  0.,  4.]])
>>>三、身份(5)*c
数组([0,1,2,3,4.]))
#预期产出:
#和(稀疏标识(5)*c).todense()==np.identity(5)*c

在表达式
sparse.identity(5)*c
中,使用稀疏矩阵的乘法运算符,即代数矩阵乘法(即矩阵乘以向量得到向量)

可以使用以下方法创建具有给定对角线的稀疏对角线矩阵:

[18]中的
:来自scipy导入稀疏
在[19]中:c=np.arange(5)
In[20]:d=sparse.diags(c,0)
In[21]:d
出[21]:
在[22]中:d.A
出[22]:
数组([[0,0,0,0,0,0.]),
[ 0.,  1.,  0.,  0.,  0.],
[ 0.,  0.,  2.,  0.,  0.],
[ 0.,  0.,  0.,  3.,  0.],
[ 0.,  0.,  0.,  0.,  4.]])

数组乘法有两种常见类型:逐元素和矩阵

在MATLAB中,
*
是矩阵版本,
*
是逐元素的

在numpy中,
*
是元素对元素(带有广播),“np.dot”是矩阵乘法的基本形式。Python开发人员已经批准将
@
作为一种可以用于矩阵乘法的操作符(最终)

对于numpy
matrix
子类,
*
是矩阵乘法,
np.multiply
用于元素对元素的乘法。(
np.multiply
也适用于
ndarray

scipy
遵循
np.matrix
惯例
*
是矩阵乘法
sparse.identity(5).multiply(c)
执行元素对元素的乘法(尽管它返回
np.matrix
,而不是稀疏矩阵)

至于原因,归根结底是开发人员习惯的惯例。对于线性代数问题,矩阵乘法很常见,因此在
稀疏
中使用
np.matrix
复制MATLAB约定。创建MATLAB是为了访问FORTRAN矩阵库

在物理学中还有另一个惯例,爱因斯坦记法。这是一个广义矩阵乘法,扩展到更多维度<代码>np.einsum执行此操作。它可以实现元素对元素的乘法,尽管它的核心是使用“乘积之和”方法。但是对于
np.matrix
sparse
(实际上并不需要,因为它们总是二维的)

请注意,对于您的示例,规范是多么相似

np.einsum('ij,j->ij',np.identity(5),c) # element by element
np.einsum('ij,j->i',np.identity(5),c)  # matrix (sum on j)

你能详细说明一下为什么使用这个操作符吗?这背后的原因是什么,用例是什么?这是我问题背后的重点,以理解其工作方式背后的逻辑。除了scipy稀疏类是矩阵类(不是numpy数组)之外,我不知道还能说些什么,稀疏矩阵代码的原始作者选择将
*
实现为代数矩阵乘法。这并不是不合理的——只是不要将它们视为稀疏的numpy数组。Numpy还有一个(密集的)矩阵类(),该类还将
*
定义为代数矩阵乘法。
np.einsum('ij,j->ij',np.identity(5),c) # element by element
np.einsum('ij,j->i',np.identity(5),c)  # matrix (sum on j)