如何创建索引组合(n 中的 k)作为 numpy 的稀疏位掩码

How to create index combinations (k out of n) as sparse bitmasks for numpy

对于numpy我怎样才能有效地创建

  1. an array/matrix 表示所有组合的列表(n 个中的 k 个)作为 k 个索引的列表。形状将是 (binomial(n, k), k).

  2. 稀疏 array/matrix 将此组合表示为长度为 n 的位掩码。 (因此将上述索引扩展为位掩码。)形状为 (binomial(n, k), n).

我需要用大的 n(可能还有小的 k)来做这件事。所以算法应该是

  1. 节省时间(例如,也许在填充之前立即space分配完整的结果?)

  2. space 高效(例如 稀疏 位掩码)

非常感谢您的帮助。

假设爆炸不是那么糟糕(如上面评论中所述),您可以试试这个。它非常矢量化并且应该很快(对于可以处理的情况)。

编辑: 我假设您对基于 scipy.sparse 的输出感兴趣。也许你不是。

代码

import itertools
import numpy as np
import scipy.sparse as sp

def combs(a, r):
    """
    Return successive r-length combinations of elements in the array a.
    Should produce the same output as array(list(combinations(a, r))), but
    faster.
    """
    a = np.asarray(a)
    dt = np.dtype([('', a.dtype)]*r)
    b = np.fromiter(itertools.combinations(a, r), dt)
    b_ = b.view(a.dtype).reshape(-1, r)
    return b_

def sparse_combs(k, n):
    combs_ = combs(np.arange(n), k)
    n_bin = combs_.shape[0]

    spmat = sp.coo_matrix(( np.ones(n_bin*k),
                            (np.repeat(np.arange(n_bin), k),
                             combs_.ravel()) ),
                            shape=(n_bin, n))
    return spmat


print('dense')
print(combs(range(4), 3))
print('sparse (dense for print)')
print(sparse_combs(3, 4).todense())

输出

dense
[[0 1 2]
 [0 1 3]
 [0 2 3]
 [1 2 3]]
sparse (dense for print)
[[ 1.  1.  1.  0.]
 [ 1.  1.  0.  1.]
 [ 1.  0.  1.  1.]
 [ 0.  1.  1.  1.]]

辅助函数 combs 我(可能)从 this question(过去的某个时候)得到的。

小的(不科学的)时间:

from time import perf_counter as pc
start = pc()
spmat = sparse_combs(5, 50)
time_used = pc() - start
print('secs: ', time_used)
print('nnzs: ', spmat.nnz)

#secs:  0.5770790778094155
#nnzs:  10593800

(3, 500)
#secs:  3.4843752405405497
#nnzs:  62125500