首页 文章

从元组列表列表构造稀疏矩阵

提问于
浏览
11

我有一个稀疏矩阵的行信息的Python列表 . 每行表示为(列,值)元组的列表 . 叫它 alist

alist = [[(1,10), (3,-3)],
         [(2,12)]]

如何从列表列表中有效地构造一个scipy稀疏矩阵,得到如下矩阵:

0  10   0  -3
0   0  12   0

显而易见的方法是创建一个 scipy.sparse.lil_matrix ,它内部具有这个"list of lists"结构 . 但是从scipy.sparse.lil_matrix — SciPy v0.19.0 Reference Guide开始,我只看到了构建它们的三种方法:

  • 从密集阵列开始

  • 从另一个稀疏数组开始

  • 只是构造一个空数组

因此,获取新数据的唯一方法是使用其他稀疏矩阵表示来解决此问题,或者从密集数组开始,这两者都没有解决初始问题,并且这两者似乎都是效率低于表示的 lil_matrix 本身就是这个数据 .

我想我可以制作一个空的,并使用循环来添加值,但我肯定错过了一些东西 .

在稀疏矩阵方面,scipy文档非常令人沮丧 .

4 回答

  • 8

    您可以从(列,值)元组 alist 列表中创建 dict 位置和值,然后使用 dok_matrix 构造稀疏矩阵

    >>> d = {(i,j):v for i,l in enumerate(alist) for j,v in l}
    >>> d
    {(0, 1): 10, (0, 3): -3, (1, 2): 12}
    >>> 
    >>> from operator import itemgetter
    >>> m = max(d.keys(), key=itemgetter(0))[0] + 1
    >>> n = max(d.keys(), key=itemgetter(1))[1] + 1
    >>> m,n
    (2, 4)
    >>>
    >>> from scipy.sparse import dok_matrix
    >>> S = dok_matrix((m,n), dtype=int)
    >>> for pos,v in d.items():
    ...     S[pos] = v
    ... 
    >>> S.todense()
    matrix([[ 0, 10,  0, -3],
            [ 0,  0, 12,  0]])
    >>>
    
  • 5

    只是想用 coo_matrix 发布另一个答案,它是一种构造稀疏矩阵的快速格式 .

    >>> alist = [[(1, 10), (3, -3)], [(2, 12)]]
    >>> row, col, data = zip(*((i,j,v) for i,l in enumerate(alist) for j,v in l))
    >>>
    >>> from scipy.sparse import coo_matrix
    >>> S = coo_matrix((data, (row, col)), (max(row)+1,max(col)+1), dtype=np.int8)
    >>> S.todense()
    matrix([[ 0, 10,  0, -3],
            [ 0,  0, 12,  0]], dtype=int8)
    >>>
    
  • 4

    您的数据布局是不寻常的 . 这是我第一次尝试使用它 .

    In [565]: M = sparse.lil_matrix((2,4), dtype=int)
    In [566]: M
    Out[566]: 
    <2x4 sparse matrix of type '<class 'numpy.int32'>'
        with 0 stored elements in LInked List format>
    In [567]: for i,row in enumerate(alist):
         ...:     for col in row:
         ...:         M[i, col[0]] = col[1]
         ...:         
    In [568]: M
    Out[568]: 
    <2x4 sparse matrix of type '<class 'numpy.int32'>'
        with 3 stored elements in LInked List format>
    In [569]: M.A
    Out[569]: 
    array([[ 0, 10,  0, -3],
           [ 0,  0, 12,  0]])
    

    是的,它是迭代的;和 lil 是用于此目的的最佳格式 .

    或使用常见的 coo 输入样式:

    In [580]: data,col,row = [],[],[]
    In [581]: for i, rr in enumerate(alist):
         ...:     for cc in rr:
         ...:         row.append(i)
         ...:         col.append(cc[0])
         ...:         data.append(cc[1])
         ...:         
    In [582]: data,col,row
    Out[582]: ([10, -3, 12], [1, 3, 2], [0, 0, 1])
    In [583]: M1=sparse.coo_matrix((data,(row,col)),shape=(2,4))
    In [584]: M1
    Out[584]: 
    <2x4 sparse matrix of type '<class 'numpy.int32'>'
        with 3 stored elements in COOrdinate format>
    In [585]: M1.A
    Out[585]: 
    array([[ 0, 10,  0, -3],
           [ 0,  0, 12,  0]])
    

    另一种选择是创建空白 lil 矩阵,并直接填写其属性:

    换句话说,从:

    In [591]: m.data
    Out[591]: array([[], []], dtype=object)
    In [592]: m.rows
    Out[592]: array([[], []], dtype=object)
    

    并将其更改为:

    In [587]: M.data
    Out[587]: array([[10, -3], [12]], dtype=object)
    In [588]: M.rows
    Out[588]: array([[1, 3], [2]], dtype=object)
    

    它仍然需要在 alist 结构上进行2级迭代 .

    In [593]: for i, rr in enumerate(alist):
         ...:     for cc in rr:
         ...:         m.rows[i].append(cc[0])
         ...:         m.data[i].append(cc[1])       
    In [594]: m
    Out[594]: 
    <2x4 sparse matrix of type '<class 'numpy.int32'>'
        with 3 stored elements in LInked List format>
    In [595]: m.A
    Out[595]: 
    array([[ 0, 10,  0, -3],
           [ 0,  0, 12,  0]])
    

    在另一条评论中,你提到了理解 csr indptr 的难度 . 最简单的方法是转换这些格式:

    In [597]: Mr=M.tocsr()
    In [598]: Mr.indptr
    Out[598]: array([0, 2, 3], dtype=int32)
    In [599]: Mr.data
    Out[599]: array([10, -3, 12])
    In [600]: Mr.indices
    Out[600]: array([1, 3, 2], dtype=int32)
    
  • 3

    如果在创建稀疏矩阵之前有整个 alist ,则无需使用 lil_matrix ,因为它已针对递增更新稀疏矩阵进行了优化 .

    如果你想用矩阵后跟词进行任何算术运算, csr_matrix 可能是你的最佳选择 . 您可以使用 (data, (row, column)) 格式直接构造 csr_matrix ,如下所示:

    In [40]: alist = [[(1,10), (3,-3)],
        ...:          [(2,12)]]
    
    In [41]: i, j, data = zip(*((i, t[0], t[1]) for i, row in enumerate(alist) for t in row))
    
    In [42]: (i, j, data)
    Out[42]: ((0, 0, 1), (1, 3, 2), (10, -3, 12))
    
    In [43]: csr_matrix((data, (i, j)), shape=(2, 4)).todense()
    Out[43]: 
    matrix([[ 0, 10,  0, -3],
            [ 0,  0, 12,  0]], dtype=int64)
    

    如果效率是一个真正的问题,您可以直接创建 csr_matrix 内部格式(使用indptr):

    In [57]: indptr = np.cumsum([0] + [len(row) for row in alist])
    
    In [58]: j, data = zip(*(t for row in alist for t in row))
    
    In [59]: csr_matrix((data, j, indptr), shape=(2, 4)).todense()
    Out[59]: 
    matrix([[ 0, 10,  0, -3],
            [ 0,  0, 12,  0]])
    

    如果您要转换为pandas afterwords,那么 coo_matrix 是可行的方法,因为pandas无论如何都会转换为 coo_matrix

    In [41]: i, j, data = zip(*((i, t[0], t[1]) for i, row in enumerate(alist) for t in row))
    
    In [43]: coo_matrix((data, (i, j)), shape=(2, 4))
    

相关问题