为什么 scipy.take 不适用于稀疏矩阵?
Why does scipy.take not work with a 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 稀疏矩阵不可能?
spicy.take
似乎没有实现稀疏矩阵的逻辑。但是,take
函数的大部分功能都可以使用花哨的索引来实现。就您而言,我相信这可以满足您的需求:
ao = a[:, bo.flat]
此处,bo.flat
是将 bo
矩阵转换为简单迭代器的简单方法。
您不能期望 scipy.sparse
矩阵的行为与密集的 numpy 矩阵或数组完全相同。
一方面,scipy.sparse
矩阵仅支持可应用于密集 arrays/matrices 的索引操作的子集,并且该子集取决于所讨论的特定稀疏格式。例如,您不能将切片索引应用于 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
不兼容。
稍微扩展一下其他答案。 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
returns一个属性错误。 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
因此,如果内存允许,将稀疏矩阵转换为数组、索引并以其他方式对其进行操作,然后再转换回稀疏矩阵可能会更有效。
如果我对 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 稀疏矩阵不可能?
spicy.take
似乎没有实现稀疏矩阵的逻辑。但是,take
函数的大部分功能都可以使用花哨的索引来实现。就您而言,我相信这可以满足您的需求:
ao = a[:, bo.flat]
此处,bo.flat
是将 bo
矩阵转换为简单迭代器的简单方法。
您不能期望 scipy.sparse
矩阵的行为与密集的 numpy 矩阵或数组完全相同。
一方面,scipy.sparse
矩阵仅支持可应用于密集 arrays/matrices 的索引操作的子集,并且该子集取决于所讨论的特定稀疏格式。例如,您不能将切片索引应用于 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
不兼容。
稍微扩展一下其他答案。 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
returns一个属性错误。 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
因此,如果内存允许,将稀疏矩阵转换为数组、索引并以其他方式对其进行操作,然后再转换回稀疏矩阵可能会更有效。