首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >了解csr格式

了解csr格式
EN

Stack Overflow用户
提问于 2020-01-29 09:24:26
回答 2查看 318关注 0票数 1

我正在尝试理解scipy CSR是如何工作的。

https://docs.scipy.org/doc/scipy/reference/sparse.html

例如,https://en.wikipedia.org/wiki/Sparse_matrix上的以下矩阵

代码语言:javascript
复制
( 0 0 0 0 )
( 5 8 0 0 )
( 0 0 3 0 )
( 0 6 0 0 )

它说CSR表示如下所示。

V是否必须在行列表中从左到右列出具有非零元素的一行?

我可以理解COL_INDEX是对应于V中的元素的列索引(列1被索引为0)。

我不明白ROW_INDEX。谁能告诉我ROW_INDEX是如何从原始矩阵中创建的?谢谢。

代码语言:javascript
复制
   V         = [ 5 8 3 6 ]
   COL_INDEX = [ 0 1 2 1 ]
   ROW_INDEX = [ 0 0 2 3 4 ]
EN

回答 2

Stack Overflow用户

发布于 2020-01-29 10:08:45

coo格式

我认为最好从coo定义开始。它更容易理解,并得到了广泛的应用:

代码语言:javascript
复制
In [90]: A = np.array([[0,0,0,0],[5,8,0,0],[0,0,3,0],[0,6,0,0]])                                 
In [91]: M = sparse.coo_matrix(A)                                                                

这些值存储在3个属性中:

代码语言:javascript
复制
In [92]: M.row                                                                                   
Out[92]: array([1, 1, 2, 3], dtype=int32)
In [93]: M.col                                                                                   
Out[93]: array([0, 1, 2, 1], dtype=int32)
In [94]: M.data                                                                                  
Out[94]: array([5, 8, 3, 6])

我们可以从这3个数组中生成一个新的矩阵:

代码语言:javascript
复制
In [95]: sparse.coo_matrix((_94, (_92, _93))).A                                                  
Out[95]: 
array([[0, 0, 0],
       [5, 8, 0],
       [0, 0, 3],
       [0, 6, 0]])

哦,我需要添加一个形状,因为有一列都是0:

代码语言:javascript
复制
In [96]: sparse.coo_matrix((_94, (_92, _93)), shape=(4,4)).A                                     
Out[96]: 
array([[0, 0, 0, 0],
       [5, 8, 0, 0],
       [0, 0, 3, 0],
       [0, 6, 0, 0]])

显示此矩阵的另一种方式:

代码语言:javascript
复制
In [97]: print(M)                                                                                
  (1, 0)    5
  (1, 1)    8
  (2, 2)    3
  (3, 1)    6

np.where(A)给出了相同的非零坐标。

代码语言:javascript
复制
In [108]: np.where(A)                                                                            
Out[108]: (array([1, 1, 2, 3]), array([0, 1, 2, 1]))

转换为csr

一旦我们有了coo,我们就可以很容易地将它转换成csr。事实上,sparse经常为我们做到这一点:

代码语言:javascript
复制
In [98]: Mr = M.tocsr()                                                                          
In [99]: Mr.data                                                                                 
Out[99]: array([5, 8, 3, 6], dtype=int64)
In [100]: Mr.indices                                                                             
Out[100]: array([0, 1, 2, 1], dtype=int32)
In [101]: Mr.indptr                                                                              
Out[101]: array([0, 0, 2, 3, 4], dtype=int32)

Sparse做了几件事--它对索引进行排序,对重复项求和,并用indptr数组替换row。在这里,它实际上比原始的更长,但通常它会更短,因为它每行只有一个值(加1)。也许更重要的是,大多数快速计算例程,特别是矩阵乘法,都是使用 csr 格式编写的。

我已经用过这个包很多次了。它的默认定义是coo样式,但内部存储是csc (但不像scipy那样向用户公开)。但是我从来没有尝试过从头开始派生indptr。我可以,但我不需要。

csr_matrix接受coo格式的输入,但也接受indptr etc格式的输入。我不推荐这样做,除非你已经计算了这些输入(比如从另一个矩阵)。它更容易出错,而且可能也不会快很多。

使用indptr进行迭代

但是,有时在intptr上迭代并直接在data上执行计算是很有用的。通常,这比使用提供的方法更快。

例如,我们可以按行列出非零值:

代码语言:javascript
复制
In [104]: for i in range(Mr.shape[0]): 
     ...:     pt = slice(Mr.indptr[i], Mr.indptr[i+1]) 
     ...:     print(i, Mr.indices[pt], Mr.data[pt]) 
     ...:                                                                                        
0 [] []
1 [0 1] [5 8]
2 [2] [3]
3 [1] [6]

保留初始0会使迭代变得更容易。当矩阵是(10000,90000)时,没有太多的动机将indptr的大小减少1。

lil格式

lil格式以类似的方式存储矩阵:

代码语言:javascript
复制
In [105]: Ml = M.tolil()                                                                         
In [106]: Ml.data                                                                                
Out[106]: array([list([]), list([5, 8]), list([3]), list([6])], dtype=object)
In [107]: Ml.rows                                                                                
Out[107]: array([list([]), list([0, 1]), list([2]), list([1])], dtype=object)

In [110]: for i,(r,d) in enumerate(zip(Ml.rows, Ml.data)): 
     ...:     print(i, r, d) 
     ...:                                                                                        
0 [] []
1 [0, 1] [5, 8]
2 [2] [3]
3 [1] [6]

由于行的存储方式,lil实际上允许我们获取view

代码语言:javascript
复制
In [167]: Ml.getrowview(2)                                                                       
Out[167]: 
<1x4 sparse matrix of type '<class 'numpy.longlong'>'
    with 1 stored elements in List of Lists format>
In [168]: for i in range(Ml.shape[0]): 
     ...:     print(Ml.getrowview(i)) 
     ...:                                                                                        

  (0, 0)    5
  (0, 1)    8
  (0, 2)    3
  (0, 1)    6
票数 1
EN

Stack Overflow用户

发布于 2020-01-29 09:31:52

scipy手册中:

数据索引((

,csr_matrix,indptr),shape=(M,N))是标准的CSR表示,其中行i的列索引存储在索引[indptri:indptri+1]中,其相应的值存储在数据[indptri:indptri+1]中。如果未提供形状参数,则从索引数组推断矩阵尺寸。

indptrROW_INDEX相同,indiciesCOL_INDEX相同。

下面是一个创建索引和值数组的简单方法的示例。本质上,ROW_INDICESi +1是从第0行到第i行的非零条目的总数,最后一个条目是非零条目的总数。

代码语言:javascript
复制
ROW_INDICES = [0]
COL_INDICES = []
VALS = []
for i in range(num_rows):
    ROW_INDICES.append(ROW_INDICES[i])
    for j in range(num_cols):
        if m[i, j] > 0:
            ROW_INDICES[i + 1] += 1
            COL_INDICES.append(j)
        VALS.append(m[i, j])
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59959379

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档