Python 有效地从scipy中的每一行稀疏矩阵中选择随机非零列

Python 有效地从scipy中的每一行稀疏矩阵中选择随机非零列,python,numpy,scipy,Python,Numpy,Scipy,我试图为大型稀疏SciPy矩阵的每一行有效地选择一个随机非零列索引。我似乎想不出一种矢量化的方法,所以我求助于一个非常慢的Python循环: random_columns = np.zeros((sparse_matrix.shape[0])) for i,row in enumerate(sparse_matrix): random_columns[i] = (np.random.choice(row.nonzero()[1])) 我的矩阵是一个大约(4000000800)的csr_

我试图为大型稀疏SciPy矩阵的每一行有效地选择一个随机非零列索引。我似乎想不出一种矢量化的方法,所以我求助于一个非常慢的Python循环:

random_columns = np.zeros((sparse_matrix.shape[0]))
for i,row in enumerate(sparse_matrix):
    random_columns[i] = (np.random.choice(row.nonzero()[1]))
我的矩阵是一个大约(4000000800)的csr_矩阵,几乎每行只有一个非零值,因此Python循环正在破坏性能。一定有更好的办法

编辑通过直接访问
csr\u矩阵的底层数据
,我可以使编辑速度提高2倍左右:

random_columns[i] = row.indices[np.random.choice(len(row.data))]

您是否研究过此格式和其他稀疏格式的底层数据表示

例如,对于小矩阵

In [257]: M = sparse.rand(10,10,.1,format='csr')

In [258]: M
Out[258]: 
<10x10 sparse matrix of type '<class 'numpy.float64'>'
    with 10 stored elements in Compressed Sparse Row format>

In [259]: M.data
Out[259]: 
array([ 0.86390256,  0.85244302,  0.88549326,  0.78737361,  0.99918561,
        0.89862529,  0.86842524,  0.25714778,  0.4174032 ,  0.33137501])

In [260]: M.indices
Out[260]: array([1, 5, 8, 8, 9, 0, 3, 9, 4, 5], dtype=int32)

In [261]: M.indptr
Out[261]: array([ 0,  1,  1,  3,  4,  4,  5,  5,  7,  8, 10], dtype=int32)
也可以对整个矩阵取
非零

 In [274]: M.nonzero()
 Out[274]: 
 (array([0, 2, 2, 3, 5, 7, 7, 8, 9, 9], dtype=int32),
 array([1, 5, 8, 8, 9, 0, 3, 9, 4, 5], dtype=int32))
这些数组与使用
M.tocoo()
并查看
属性时得到的数组相同。理论上,您可以使用
groupby
获取列的子列表,并从中进行选择。但同样地,您有列表、生成器和迭代

我不知道这些表述中是否有人更快

将问题矢量化可能存在一些限制。非零的数量(输入到
选项
)将因行而异。有些行有非指定行,其他行有1行或多行。每当遇到长度不同的数组或列表时,都很难对操作进行矢量化。如果无法将值排列到常规二维数组中,则无法使用数组操作将其作为一个整体进行操作


lil
格式值得一看:

In [276]: timeit [np.random.choice(x.nonzero()[1]) for x in M if len(x.nonzero()[1])]
100 loops, best of 3: 4.24 ms per loop

In [289]: timeit [np.random.choice(row.indices) for row in M if len(row.indices)]
1000 loops, best of 3: 1.52 ms per loop
# 3x speedup using row.indices

In [277]: %%timeit
   .....: Ml=M.tolil()
   .....: [np.random.choice(x) for x in Ml.rows if x]
   .....: 
10000 loops, best of 3: 181 µs per loop

您的代码抛出
i,np.random.choice(row.nonzero()[1]:元组索引超出范围
Um well sparse\u矩阵需要是二维的。此代码适合我…是的,但您正在选择第一个维度来定义
np.zero((sparse\u matrix.shape[0])
这将得到一个1d数组?
是来自
稀疏矩阵
的一行,而不是来自
随机列
。稀疏矩阵的形状是什么?
稀疏矩阵
?谢谢你的详细回答!对于我来说,
lil
格式似乎可以做到,它将事情减少了10倍。
In [276]: timeit [np.random.choice(x.nonzero()[1]) for x in M if len(x.nonzero()[1])]
100 loops, best of 3: 4.24 ms per loop

In [289]: timeit [np.random.choice(row.indices) for row in M if len(row.indices)]
1000 loops, best of 3: 1.52 ms per loop
# 3x speedup using row.indices

In [277]: %%timeit
   .....: Ml=M.tolil()
   .....: [np.random.choice(x) for x in Ml.rows if x]
   .....: 
10000 loops, best of 3: 181 µs per loop