繁体   English   中英

为什么scipy.sparse.csc_matrix.sum()的结果会将其类型更改为numpy矩阵?

[英]Why does the result of scipy.sparse.csc_matrix.sum() change its type to numpy matrix?

我想生成一个大的稀疏矩阵并求它,但我遇到了很多MemoryError 所以我尝试通过scipy.sparse.csc_matrix.sum进行操作,但发现数据类型在获取总和后变回了numpy matrix

window = 10    
np.random.seed = 0
mat = sparse.csc_matrix(np.random.rand(100, 120)>0.5, dtype='d')
print type(mat)
>>> <class 'scipy.sparse.csc.csc_matrix'>

mat_head = mat[:,0:window].sum(axis=1)
print type(mat_head)
>>> <class 'numpy.matrixlib.defmatrix.matrix'>

因此,我将mat生成为零作为矩阵,以便在mat_head全为零时测试结果。

mat = sparse.csc_matrix((100,120))
print type(mat)
>>> <class 'scipy.sparse.csc.csc_matrix'>
mat_head = mat.sum(axis=1)
print type(mat_head)
>>> <class 'numpy.matrixlib.defmatrix.matrix'>
print np.count_nonzero(mat_head)
>>> 0

为什么会这样? 因此,通过scipy.sparse来保存内存不比numpy因为它们无论如何都会改变数据类型?

只要有可能给出一个基本上是设计选择的硬理由,我就会提出以下论点:

csr和csc格式设计用于稀疏但非极稀疏的矩阵。 特别是,对于具有明显少于n个非零的nxn矩阵,这些格式相当浪费,因为除了数据和索引之外,它们还带有大小为n + 1的字段indptr(描绘行或列)。

因此,假设正确使用csc或csr矩阵,期望行或列和不是稀疏的并且相应的方法应该返回密集向量是合理的。

我知道你的“为什么”的问题主要针对设计决策背后的动机,但无论如何我追踪到csc_matrix.sum(axis=1)实际上是如何变成一个numpy matrix

所述csc_matrix从继承_cs_matrix从继承_data_matrix从继承spmatrix基类 最后一个实现.sum(ax)

if axis == 0:
    # sum over columns
    ret = np.asmatrix(np.ones(
        (1, m), dtype=res_dtype)) * self
else:
    # sum over rows
    ret = self * np.asmatrix(np.ones((n, 1), dtype=res_dtype))

换句话说, 如在注释中所指出的 ,列/行和通过分别乘以1的密集行或列矩阵来计算。 此操作的结果将是您在输出中看到的密集矩阵。

虽然有些子类覆盖了它们的.sum()方法,但据我所知,这只发生在axis=None情况下,所以你看到的结果可以归结为上面的代码块。

csrcsc格式是针对线性algeba开发的,尤其是大而稀疏的线性方程的解

A*x = b
x = b/A

A必须是可逆的,并且不能包含所有0的行或列。

A.sum(1)通过矩阵乘法完成,其中(n,1)数组为1。

用你的mat

In [203]: np.allclose(mat*np.mat(np.ones((120,1))), mat.sum(1))
Out[203]: True

自己这样做实际上有点快(在某处开销?)

In [204]: timeit mat.sum(1)
92.7 µs ± 111 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [205]: timeit mat*np.mat(np.ones((120,1)))
59.2 µs ± 53.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

我也可以用稀疏矩阵做到这一点:

In [209]: mat*sparse.csc_matrix(np.ones((120,1)))
Out[209]: 
<100x1 sparse matrix of type '<class 'numpy.float64'>'
    with 100 stored elements in Compressed Sparse Column format>
In [211]: np.allclose(mat.sum(1),_.todense())
Out[211]: True

但是时间比较慢,即使我将稀疏创建移到循环之外:

In [213]: %%timeit I=sparse.csc_matrix(np.ones((120,1)))
     ...: mat*I
     ...: 
215 µs ± 401 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

如果mat(115100,10)并且全部为0行,则这种稀疏方法可以节省时间和空间。


mat[:,:10]也用矩阵乘法执行,具有稀疏提取器矩阵。

它实际上比行总和慢:

In [247]: timeit mat[:,:10]
305 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [248]: timeit mat[:,:10].sum(1)
384 µs ± 9.05 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

我可以使用以下内容将列选择与总和相结合:

In [252]: I = sparse.lil_matrix((120,1),dtype=int); I[:10,:]=1; I=I.tocsc()
In [253]: I
Out[253]: 
<120x1 sparse matrix of type '<class 'numpy.int64'>'
    with 10 stored elements in Compressed Sparse Column format>
In [254]: np.allclose((mat*I).todense(),mat[:,:10].sum(1))
Out[254]: True

在这个mat*I虽然我可以改进I构造步骤,但速度较慢。

I = sparse.csc_matrix((np.ones(10,int), np.arange(10), np.array([0,10])), shape=(120,1))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM