如果我使用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稀疏矩阵是不可能的?
答案 0 :(得分:2)
您不能指望scipy.sparse
矩阵的行为与密集的numpy矩阵或数组完全相同。
首先,scipy.sparse
矩阵仅支持可应用于密集数组/矩阵的索引操作的子集,并且此子集取决于所讨论的特定稀疏格式。例如,您无法将切片索引应用于coo_matrix
,您只能对dok_matrix
等See here的单个轴应用花式索引,以便对这些限制进行更多讨论。
在您的特定情况下,您可以使用花式索引代替np.take
:
ao = a[:, np.ravel(bo)]
# or ao = a[:, bo.flat]
# or ao = a[:, bo.A1]
然而,并非每种稀疏矩阵格式都支持这种索引,这可能解释了为什么稀疏矩阵缺少.take
方法且与numpy.take
不兼容。
答案 1 :(得分:1)
稍微扩展其他答案。 np.take
(sp.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
矩阵转换为简单迭代器的简单方法。