为什么scipy.take不适用于稀疏矩阵?

时间:2016-02-14 21:35:30

标签: python numpy matrix scipy sparse-matrix

如果我使用numpy.zeros矩阵执行相同操作,则可以正常工作。但是使用scipy稀疏矩阵它不起作用。为什么?

import scipy.sparse as sparse
import scipy as sp
a = sparse.lil_matrix((3,3), dtype=int)
a[0,0] = 0
a[1,1] = 1
a[2,2] = 2
b = a.sum(0)
bo = (-b).argsort()
ao = sp.take(a, bo, axis=1)

我收到错误:

ValueError: axis(=1) out of bounds

为什么这不起作用。请有人告诉我如何解决它?或者用scipy稀疏矩阵是不可能的?

3 个答案:

答案 0 :(得分:2)

您不能指望scipy.sparse矩阵的行为与密集的numpy矩阵或数组完全相同。

首先,scipy.sparse矩阵仅支持可应用于密集数组/矩阵的索引操作的子集,并且此子集取决于所讨论的特定稀疏格式。例如,您无法将切片索引应用于coo_matrix,您只能对dok_matrixSee here的单个轴应用花式索引,以便对这些限制进行更多讨论。

在您的特定情况下,您可以使用花式索引代替np.take

ao = a[:, np.ravel(bo)]
# or ao = a[:, bo.flat]
# or ao = a[:, bo.A1]

然而,并非每种稀疏矩阵格式都支持这种索引,这可能解释了为什么稀疏矩阵缺少.take方法且与numpy.take不兼容。

答案 1 :(得分:1)

稍微扩展其他答案。 np.takesp.take是相同的事情):

try:
    take = a.take
except AttributeError:
    return _wrapit(a, 'take', indices, axis, out, mode)
return take(indices, axis, out, mode)

换句话说,它试图执行

a.take(bo, axis=1)

但是a.take会返回属性错误。 a,稀疏矩阵没有take方法。尝试将a转换为np.array(a)的数组也不起作用 - 它只是将稀疏矩阵包装在0d对象数组中。这就是为什么我们得到index越界错误。

使用lil格式,矩阵存储为两个列表,或者最具体的是列表的对象数组,每行一个子列表。

In [620]: a.data
Out[620]: array([[1], [2], [3]], dtype=object)

In [621]: a.rows
Out[621]: array([[0], [1], [2]], dtype=object)

a.__getitem__是执行索引的函数。它将喜欢索引的花哨numpy转换为列表推导。与数组相比,没有快速编译的索引。

请注意,如果我首先将a转换为密集数组,则此重新排序会更快。即使往返也更快。

In [626]: b0=(-b.A1).argsort()
In [627]: timeit a[:,b0].A
1000 loops, best of 3: 705 us per loop

In [628]: timeit a.A[:,b0]
10000 loops, best of 3: 22.3 us per loop

In [630]: timeit sparse.lil_matrix(a.A[:,b0])
1000 loops, best of 3: 483 us per loop

因此,如果内存允许,将稀疏矩阵转换为数组,索引和以其他方式操纵它可能会更有效,并且转换回稀疏。

答案 2 :(得分:0)

spicy.take似乎没有实现稀疏矩阵的逻辑。但是,take函数的大多数功能都可以使用花哨的索引来实现。在你的情况下,我相信这会给你你想要的东西:

ao = a[:, bo.flat]

这里,bo.flat是将bo矩阵转换为简单迭代器的简单方法。