有没有办法全局避免在{numpy计算的任何结果中出现matrix
?例如,如果您将x
作为numpy.ndarray
而y
作为scipy.sparse.csc_matrix
,并且您说x += y
,则x
将成为{ {1}}之后。有没有办法防止这种情况发生,即保持matrix
x
,更一般地说,在生成ndarray
的所有地方继续使用ndarray
?< / p>
答案 0 :(得分:2)
我添加了scipy
代码,这是scipy.sparse
个问题,而不是np.matrix
个问题。
In [250]: y=sparse.csr_matrix([[0,1],[1,0]])
In [251]: x=np.arange(2)
In [252]: y+x
Out[252]:
matrix([[0, 2],
[1, 1]])
稀疏+数组=&gt;基质
(作为旁注,np.matrix
是np.ndarray
的子类。sparse.csr_matrix
不是子类。它有许多类似numpy的操作,但它在自己的代码中实现它们)
In [255]: x += y
In [256]: x
Out[256]:
matrix([[0, 2],
[1, 1]])
从技术上讲,这不应该发生;实际上它正在x = x+y
为x
分配新值,而不仅仅是修改x
。
如果我先将y
变为常规密集matrix
,我会收到错误消息。允许该操作会将1d数组更改为2d数组。
In [258]: x += y.todense()
...
ValueError: non-broadcastable output operand with shape (2,) doesn't match the broadcast shape (2,2)
将x
更改为2d允许继续添加 - 而不将数组更改为矩阵:
In [259]: x=np.eye(2)
In [260]: x
Out[260]:
array([[ 1., 0.],
[ 0., 1.]])
In [261]: x += y.todense()
In [262]: x
Out[262]:
array([[ 1., 1.],
[ 1., 1.]])
通常,使用稀疏矩阵执行加法/减法是棘手的。它们是为矩阵乘法而设计的。乘法不会像添加一样改变稀疏性。例如y+1
使其密集。
如果不深入研究稀疏添加的编码细节,我会说 - 在没有先将x+=...
转换为密集版本的情况下,不要尝试此y
操作。
In [265]: x += y.A
In [266]: x
Out[266]:
array([[ 1., 2.],
[ 2., 1.]])
我无法想到不这样做的充分理由。
(我应该检查scipy
github
是否存在错误问题。)
scipy / sparse / compressed.py有csr
个附加代码。 x+y
使用x.__add__(y)
,但有时会将其翻转为y.__add__(x)
。 x+=y
使用x.__iadd__(y)
。因此,我可能还需要检查__iadd__
ndarray
。
但稀疏矩阵的基本添加是:
def __add__(self,other):
# First check if argument is a scalar
if isscalarlike(other):
if other == 0:
return self.copy()
else: # Now we would add this scalar to every element.
raise NotImplementedError('adding a nonzero scalar to a '
'sparse matrix is not supported')
elif isspmatrix(other):
if (other.shape != self.shape):
raise ValueError("inconsistent shapes")
return self._binopt(other,'_plus_')
elif isdense(other):
# Convert this matrix to a dense matrix and add them
return self.todense() + other
else:
return NotImplemented
因此y+x
变为y.todense() + x
。 x+y
使用同样的东西。
无论+=
详细信息如何,很明显将稀疏添加到密集(数组或np.matrix)涉及将稀疏转换为密集。没有代码可以遍历稀疏值并将这些值有选择地添加到密集数组中。
仅当数组稀疏时才执行特殊的稀疏加法。 y+y
有效,返回稀疏。来自y+=y
的{{1}} NotImplmenentedError
失败。
这是我提出的最佳诊断序列,尝试了将sparse.base.__iadd__
添加到y
数组的各种方法。
(2,2)
添加会产生一个矩阵,但值可以写入In [348]: x=np.eye(2)
In [349]: x+y
Out[349]:
matrix([[ 1., 1.],
[ 1., 1.]])
In [350]: x+y.todense()
Out[350]:
matrix([[ 1., 1.],
[ 1., 1.]])
而不会更改x
类(或形状)
x
具有密集矩阵的 In [351]: x[:] = x+y
In [352]: x
Out[352]:
array([[ 1., 1.],
[ 1., 1.]])
也是如此:
+=
但In [353]: x += y.todense()
In [354]: x
Out[354]:
array([[ 1., 2.],
[ 2., 1.]])
中的内容更改了+=sparse
x
进一步测试并查看In [355]: x += y
In [356]: x
Out[356]:
matrix([[ 1., 3.],
[ 3., 1.]])
和id(x)
很明显x.__array_interface__
取代x += y
。即使x
以x
开头,也是如此。所以稀疏np.matrix
不是一个就地操作。 +=
是一个现场操作。
答案 1 :(得分:0)
是的,这是一个错误;但https://github.com/scipy/scipy/issues/7826说
我真的没有办法改变这一点。
<小时/> 接下来是
X += c * Y
没有todense
一些inc( various array / matrix, various sparse )
已经过测试,但肯定不是全部。
def inc( X, Y, c=1. ):
""" X += c * Y, X Y sparse or dense """
if (not hasattr( X, "indices" ) # dense += sparse
and hasattr( Y, "indices" )):
# inc an ndarray view, because ndarry += sparse -> matrix --
X = getattr( X, "A", X ).squeeze()
X[Y.indices] += c * Y.data
else:
X += c * Y # sparse + different sparse: SparseEfficiencyWarning
return X