【问题标题】:Building and updating a sparse matrix in python using scipy使用 scipy 在 python 中构建和更新稀疏矩阵
【发布时间】:2014-01-02 05:14:11
【问题描述】:

当我从文件中读取数据时,我正在尝试构建和更新一个稀疏矩阵。 矩阵大小为100000X40000

更新稀疏矩阵的多个条目最有效的方法是什么? 具体来说,我需要将每个条目增加 1。

假设我有行索引[2, 236, 246, 389, 1691]

和列索引[117, 3, 34, 2757, 74, 1635, 52]

所以以下所有条目必须加一:

(2,117) (2,3) (2,34) (2,2757) ...

(236,117) (236,3) (236, 34) (236,2757) ...

等等。

我已经在使用lil_matrix,因为它在我尝试更新单个条目时给了我一个警告。

lil_matrix 格式已经不支持多次更新。 matrix[1:3,0] += [2,3] 给了我一个未实现的错误。

我可以通过单独递增每个条目来天真地做到这一点。我想知道是否有更好的方法来做到这一点,或者我可以使用更好的稀疏矩阵实现。

我的电脑也是一台普通的 i5 机器,有 4GB 内存,所以我必须小心不要把它炸毁:)

【问题讨论】:

  • 它适用于lil_matrix,如果右侧是匹配形状的numpy数组,如A[1:3, 0] += np.array( [[ 2 ],[ 3 ]] )
  • 是的,我想通了。但是您对我的具体问题有什么建议吗?就像给定行索引和列索引一样,我想增加问题中给出的所有组合条目。

标签: python python-2.7 matrix scipy sparse-matrix


【解决方案1】:

在新坐标中使用1s 创建第二个矩阵并将其添加到现有矩阵中是一种可行的方法:

>>> import scipy.sparse as sps
>>> shape = (1000, 2000)
>>> rows, cols = 1000, 2000
>>> sps_acc = sps.coo_matrix((rows, cols)) # empty matrix
>>> for j in xrange(100): # add 100 sets of 100 1's
...     r = np.random.randint(rows, size=100)
...     c = np.random.randint(cols, size=100)
...     d = np.ones((100,))
...     sps_acc = sps_acc + sps.coo_matrix((d, (r, c)), shape=(rows, cols))
... 
>>> sps_acc
<1000x2000 sparse matrix of type '<type 'numpy.float64'>'
    with 9985 stored elements in Compressed Sparse Row format>

【讨论】:

    【解决方案2】:
    import scipy.sparse
    
    rows = [2, 236, 246, 389, 1691]
    cols = [117, 3, 34, 2757, 74, 1635, 52]
    prod = [(x, y) for x in rows for y in cols] # combinations
    r = [x for (x, y) in prod] # x_coordinate
    c = [y for (x, y) in prod] # y_coordinate
    data = [1] * len(r)
    m = scipy.sparse.coo_matrix((data, (r, c)), shape=(100000, 40000))
    

    我认为它运作良好并且不需要循环。我直接关注doc

    <100000x40000 sparse matrix of type '<type 'numpy.int32'>'
        with 35 stored elements in COOrdinate format>
    

    【讨论】:

    • cols_iter = cycle(cols), r,c = zip(*[(x, cols_iter.next()) for x in rows ]) 和 data = np.ones(len(r))让这稍微快一点
    • 这是一种有效的方法吗?我的意思是我可以在每次迭代中将它添加到我的主矩阵中,每次迭代我都会得到一个新的行和列数组。
    • @syllogismos 我认为是这样,根据文档,这就是生成新稀疏矩阵的方式。至少应该比循环快。
    • m 是每次迭代的结果矩阵,f 是我的主矩阵,也在 coo_matrix 中。我能做到吗,f += m? f 和 m 应该是什么格式。它在文档中给出 coo_matrix 对于算术运算不是很有效。
    • @syllogismos 我注意到,m 是由特定索引中的数据值直接生成的,因此它不涉及太多的算术运算。
    【解决方案3】:

    这个答案扩展了@behzad.nouri 的评论。要增加行和列索引列表的“外积”的值,只需将它们创建为配置为广播的 numpy 数组。在这种情况下,这意味着将行放入一列。例如,

    In [59]: a = lil_matrix((4,4), dtype=int)
    
    In [60]: a.A
    Out[60]: 
    array([[0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 0]])
    
    In [61]: rows = np.array([1,3]).reshape(-1, 1)
    
    In [62]: rows
    Out[62]: 
    array([[1],
           [3]])
    
    In [63]: cols = np.array([0, 2, 3])
    
    In [64]: a[rows, cols] += np.ones((rows.size, cols.size))
    
    In [65]: a.A
    Out[65]: 
    array([[0, 0, 0, 0],
           [1, 0, 1, 1],
           [0, 0, 0, 0],
           [1, 0, 1, 1]])
    
    In [66]: rows = np.array([0, 1]).reshape(-1,1)
    
    In [67]: cols = np.array([1, 2])
    
    In [68]: a[rows, cols] += np.ones((rows.size, cols.size))
    
    In [69]: a.A
    Out[69]: 
    array([[0, 1, 1, 0],
           [1, 1, 2, 1],
           [0, 0, 0, 0],
           [1, 0, 1, 1]])
    

    【讨论】:

    • 我对这个解决方案很满意,因为它允许您在稀疏 lil_matrix 中一次更新一行。
    猜你喜欢
    • 2019-07-22
    • 2017-02-17
    • 2018-03-18
    • 2017-03-31
    • 2020-05-31
    • 2023-04-10
    • 1970-01-01
    • 2014-10-15
    • 2015-05-08
    相关资源
    最近更新 更多