【问题标题】:NumPy matrix to SciPy sparse matrix: What is the safest way to add a scalar?NumPy 矩阵到 SciPy 稀疏矩阵:添加标量最安全的方法是什么?
【发布时间】:2015-05-31 22:20:35
【问题描述】:

首先,我不是数学家。我承认。然而,我仍然需要了解 ScyPy 的稀疏矩阵如何在算术上工作,以便在我必须处理的应用程序中从密集 NumPy 矩阵切换到 SciPy 稀疏矩阵。问题是内存使用情况。一个大的密集矩阵会消耗大量的内存。

有争议的公式部分是将矩阵添加到标量的位置。

A = V + x

其中 V 是一个方阵(它很大,比如 60,000 x 60,000)并且人口稀少。 x 是一个浮点数。

使用 NumPy 的操作将(如果我没记错的话)将 x 添加到 V 中的每个字段。如果我完全偏离基础,请告诉我,x 只会添加到 V 中的非零值。

使用 SciPy,并非所有稀疏矩阵都支持相同的功能,例如标量加法。 dok_matrix (键的字典)支持标量加法,但它看起来(在实践中)它正在分配每个矩阵条目,有效地将我的稀疏 dok_matrix 渲染为具有更多开销的密集矩阵。 (不好)

其他矩阵类型(CSR、CSC、LIL)不支持标量加法。

我可以尝试用标量值 x 构造一个完整的矩阵,然后将其添加到 V。我对矩阵类型没有任何问题,因为它们似乎都支持矩阵加法。但是,我必须消耗大量内存才能将 x 构造为矩阵,并且加法的结果也可能最终成为完全填充的矩阵。

必须有另一种方法来做到这一点,不需要分配 100% 的稀疏矩阵。

我愿意接受需要大量内存,但我想我会先寻求一些建议。谢谢。

【问题讨论】:

  • 只是要明确一点:最终,您想要的结果是密集矩阵A?还是要将标量 x 添加到 V 的非零元素?

标签: numpy matrix scipy sparse-matrix


【解决方案1】:

诚然,稀疏矩阵并不真正在我的驾驶室中,但 ISTM 的最佳前进方式取决于矩阵类型。如果你是 DOK:

>>> S = dok_matrix((5,5))
>>> S[2,3] = 10; S[4,1] = 20
>>> S.todense()
matrix([[  0.,   0.,   0.,   0.,   0.],
        [  0.,   0.,   0.,   0.,   0.],
        [  0.,   0.,   0.,  10.,   0.],
        [  0.,   0.,   0.,   0.,   0.],
        [  0.,  20.,   0.,   0.,   0.]])

然后你可以更新:

>>> S.update(zip(S.keys(), np.array(S.values()) + 99))
>>> S
<5x5 sparse matrix of type '<type 'numpy.float64'>'
    with 2 stored elements in Dictionary Of Keys format>
>>> S.todense()
matrix([[   0.,    0.,    0.,    0.,    0.],
        [   0.,    0.,    0.,    0.,    0.],
        [   0.,    0.,    0.,  109.,    0.],
        [   0.,    0.,    0.,    0.,    0.],
        [   0.,  119.,    0.,    0.,    0.]])

不是特别高效,但是 O(非零)。

OTOH,如果你有COO、CSC、CSR之类的,可以直接修改data属性:

>>> C = S.tocoo()
>>> C
<5x5 sparse matrix of type '<type 'numpy.float64'>'
    with 2 stored elements in COOrdinate format>
>>> C.data
array([ 119.,  109.])
>>> C.data += 1000
>>> C
<5x5 sparse matrix of type '<type 'numpy.float64'>'
    with 2 stored elements in COOrdinate format>
>>> C.todense()
matrix([[    0.,     0.,     0.,     0.,     0.],
        [    0.,     0.,     0.,     0.,     0.],
        [    0.,     0.,     0.,  1109.,     0.],
        [    0.,     0.,     0.,     0.,     0.],
        [    0.,  1119.,     0.,     0.,     0.]])

请注意,您可能需要添加一个额外的

>>> C.eliminate_zeros()

处理您添加负数的可能性,因此现在有一个 0 实际上正在被记录。就其本身而言,这应该可以正常工作,但是下一次您执行C.data += some_number 技巧时,它会将somenumber 添加到您引入的那个零。

【讨论】:

  • "直接修改数据属性" 谢谢你,这是一个绝妙的见解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-26
  • 1970-01-01
  • 2017-07-21
  • 2017-07-02
  • 2013-11-13
  • 1970-01-01
  • 2012-02-20
相关资源
最近更新 更多