python - 如何通过索引将 scipy.sparse 矩阵分配给 NumPy 数组?

标签 python numpy scipy

当我尝试分配 scipy.sparse 时矩阵 s(任何可用的稀疏类型)到 NumPy 数组 a,如下所示:

a[:] = s

我收到一个TypeError:

TypeError: float() argument must be a string or a number

有办法解决这个问题吗?

我知道 todense()toarray() 方法,但我真的很想避免不必要的复制,我更愿意使用相同的方法NumPy 数组和 SciPy 稀疏矩阵的代码。 现在,我不担心从稀疏矩阵中获取的值效率低下。

是否可能存在某种可与 NumPy 索引分配一起使用的稀疏矩阵包装器?

如果没有,有什么建议我可以自己构建这样的东西吗?

在这种情况下是否有与 NumPy 配合的不同的稀疏数组库?

更新:

我在 NumPy 源代码中四处寻找,搜索错误消息字符串,我想我在 numpy/core/src/multiarray/arraytypes.c.src around line 187 中找到了索引分配发生的部分。在函数 @TYPE@_setitem() 中。

我还是不太明白,但是在某些时候,似乎调用了float()函数(如果a是一个 float 组) .因此,我尝试对 SciPy 稀疏矩阵类之一进行猴子修补,以允许调用此函数:

import scipy
s = scipy.sparse.dok_matrix((5, 1))
def myfloat(self):
    assert self.shape == (1, 1)
    return self[0, 0]
scipy.sparse.dok.dok_matrix.__float__ = myfloat
a[:] = s

遗憾的是,这不起作用,因为 float() 是在整个稀疏矩阵上调用的,而不是在其中的单个项上调用的。

所以我想我的新问题是:如何进一步更改稀疏矩阵类以使 NumPy 遍历所有项并对每个项调用 float()

另一项更新:

我在 Github ( https://github.com/FRidh/sparse ) 上找到了一个稀疏数组模块,它允许分配给 NumPy 数组。遗憾的是,该模块的功能非常有限(例如,切片还不能真正起作用),但它可能有助于理解如何实现对 NumPy 数组的分配。 我会进一步调查......

又一更新:

我做了更多挖掘,发现一个更有趣的源文件可能是 numpy/core/src/multiarray/ctors.c . 我怀疑函数 PySequence_Check() ( docs/code ) 在分配过程中的某个时间被调用。来自 https://github.com/FRidh/sparse 的简单稀疏数组类通过测试,但看起来 SciPy 中的稀疏矩阵类没有(尽管在我看来它们是序列)。

检查它们的 __array_struct____array_interface____array__,然后以某种方式确定它们不是序列。 未检查属性 __getitem____len__(所有稀疏数组类都有!)。

这让我想到了另一个问题:如何以通过 PySequence_Check() 的方式操作稀疏矩阵类(或其对象)?

我认为一旦它们被识别为序列,赋值就应该起作用,因为 __getitem__()__len__() 应该足够了。

最佳答案

正如在对我的问题的评论中提到的,序列接口(interface)不适用于稀疏矩阵,因为它们在用单个数字索引时不会丢失维度。 无论如何尝试,我在纯 Python 中创建了一个非常有限的快速和肮脏的稀疏 array 类,当用单个数字索引时,它返回一个“行”类(它持有一个 View 原始数据),它又可以用单个数字进行索引以产生该索引处的实际值。使用我的类的实例 s,分配给 NumPy 数组 a 完全按照要求工作:

a[:] = s

我预计这会有点低效,但它真的、真的、真的、非常慢。分配一个 500.000 x 100 的稀疏数组需要几分钟! 不过,好消息是在赋值期间不会创建完整大小的临时数组。在分配期间内存使用率保持不变(同时其中一个 CPU 已达到极限)。

所以这基本上是原始问题的一种解决方案。

为了使分配更高效并且仍然不使用密集数组数据的临时副本,NumPy 必须在内部执行类似的操作

s.toarray(out=a)

据我所知,目前还没有办法让 NumPy 这样做。

但是,有一种方法可以做一些非常相似的事情,方法是提供一个返回 NumPy 数组的 __array__() 方法。顺便说一句,SciPy 稀疏矩阵已经有了这样的方法,只是名称不同:toarray()。所以我只是重命名它:

scipy.sparse.dok_matrix.__array__ = scipy.sparse.dok_matrix.toarray
a[:] = s

这就像一个魅力(也适用于其他稀疏矩阵类)并且非常快!

根据我对情况的有限理解,这应该创建一个与 a 大小相同的临时 NumPy 数组,它包含 s 中的所有值(以及许多零) 然后分配给 a。 但奇怪的是,即使我使用非常大的 a 几乎占据了我所有可用的 RAM,分配仍然很快发生并且没有使用额外的 RAM。

所以我想这是对我原来的问题的另一个更好的解决方案。

这留下了另一个问题:为什么这在没有临时数组的情况下也能工作?

关于python - 如何通过索引将 scipy.sparse 矩阵分配给 NumPy 数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26934349/

相关文章:

python:查找 cdf 的随机变量的值

python - 根据另一个列表从 pandas 数据框列中的列表中删除值

python - 使用 Numpy 计算相关系数

python - 查找稀疏 csc_matrix 中存在非零条目的行的索引

python - 如何在 scipy 中最小化具有离散变量值的函数

python - 为什么 scipy.optimize 中的 linear_sum_assignment 永远不会返回,如果其中一项分配的成本必须为无穷大?

python - Sqlite3 或 QtSql

python - 在 python 中简单编辑二进制文件

python - python 中的 dsearchn 等效项

一定范围内整数的 Python numpy 乘积