扩展(添加行或列)scipy.sparse矩阵

32

假设我有一个来自scipy.sparse的NxN矩阵M(lil_matrix或csr_matrix),我想将其变为(N+1)xN,其中对于0 <= i < N(和所有j),M_modified[i, j] = M[i, j],并且对于所有j,M[N, j] = 0。基本上,我想在M的底部添加一行零并保留矩阵的其余部分。是否有一种方法可以在不复制数据的情况下完成这个操作?


2
https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.vstack.html - user96265
Spicy确实提供了例程。请查看下面Sidhant的答案并点赞。hstack和vstack页面也为您提供了简单的示例代码。 - user96265
3个回答

31

Scipy没有一种方法可以在不复制数据的情况下完成此操作,但是您可以通过更改定义稀疏矩阵的属性来自己完成。

csr_matrix由4个属性组成:

data:包含矩阵中实际值的数组

indices:包含与data中每个值对应的列索引的数组

indptr:指定每行第一个值之前的索引的数组。如果该行为空,则索引与上一列相同。

shape:包含矩阵形状的元组

如果您只是在底部添加了一行零,则只需更改矩阵的形状和indptr即可。

x = np.ones((3,5))
x = csr_matrix(x)
x.toarray()
>> array([[ 1.,  1.,  1.,  1.,  1.],
          [ 1.,  1.,  1.,  1.,  1.],
          [ 1.,  1.,  1.,  1.,  1.]])
# reshape is not implemented for csr_matrix but you can cheat and do it  yourself.
x._shape = (4,5)
# Update indptr to let it know we added a row with nothing in it. So just append the last
# value in indptr to the end.
# note that you are still copying the indptr array
x.indptr = np.hstack((x.indptr,x.indptr[-1]))
x.toarray()
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.]])

这里是一个处理任意两个csr矩阵进行垂直拼接的函数。你仍然需要复制底层的numpy数组,但它仍然比scipy的vstack方法快得多。

def csr_vappend(a,b):
    """ Takes in 2 csr_matrices and appends the second one to the bottom of the first one. 
    Much faster than scipy.sparse.vstack but assumes the type to be csr and overwrites
    the first matrix instead of copying it. The data, indices, and indptr still get copied."""

    a.data = np.hstack((a.data,b.data))
    a.indices = np.hstack((a.indices,b.indices))
    a.indptr = np.hstack((a.indptr,(b.indptr + a.nnz)[1:]))
    a._shape = (a.shape[0]+b.shape[0],b.shape[1])
    return a

1
我认为你甚至可以不返回a,因为函数参数是通过引用传递的,即使在函数范围内,a也会直接被修改。另外,是否有一个类似于csc_happend(a,b)的模拟函数? - richizy
好主意,直接重置形状。 - Jan
1
更改您建议的形状会有什么影响?我尝试了您的方法,对于添加行可以正常工作,但是对于列却出现了问题,您有任何想法吗?! - leoschet
Spicy确实提供了例程。请查看Sidhant下面的答案并点赞。hstack和vstack页面还提供了简单的示例代码。 - user96265
袜子娃娃警报 - Robin De Schepper

11

2
source code for vstack 正如其所示,它返回输入矩阵的一个新副本,因此如果我们想要就地扩展矩阵,则效率不够高。 - JenkinsY

7

我认为无法从复制中真正逃脱。这两种类型的稀疏矩阵将它们的数据作为Numpy数组存储(在csr的数据和索引属性中,在lil的数据和行属性中),Numpy数组不能扩展。

更多信息更新:

LIL确实代表链表,但是当前实现并不完全符合名称。用于datarows 的Numpy数组都是对象类型。这些数组中的每个对象实际上都是Python列表(当一行中所有值为零时为空列表)。 Python列表并不完全是链表,但它们很接近,而且由于O(1)查找,它们是更好的选择。就我个人而言,我并没有立即看出在此处使用Numpy对象数组的意义,而不仅仅是Python列表。您可以相当容易地更改当前的lil实现以使用Python列表,这将使您能够添加行而无需复制整个矩阵。


如果这对你的应用程序非常关键,你可以实现一个新类,使用scipy.sparse接口,在底层使用更易于扩展的数据类型。 - Aaron Altman
1
也许更了解底层数据结构的人可以回答这个问题。我认为lil_matrix是用链表实现的? - RandomGuy
@scandido,请看一下我最新添加的内容是否回答了你的问题。 - Justin Peel
Spicy确实提供了例程。请查看下面Sidhant的答案并点赞。hstack和vstack页面也为您提供了简单的示例代码。 - user96265

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接