Python中稀疏矩阵的唯一列

Python中稀疏矩阵的唯一列,python,scipy,sparse-matrix,Python,Scipy,Sparse Matrix,识别以csc_矩阵格式表示的稀疏矩阵的唯一列以及每列的重复次数的好方法是什么 我没有关于矩阵元素的先验信息。这是通过替换另一个矩阵的列进行采样的结果,因此我可以有两个重复的列,因为一个列被多次采样,或者原始矩阵中存在重复的列。因此,我无法将numpy.unique应用于采样列的索引,我认为将整个矩阵转换为密集格式,然后将numpy.unique应用于它不是一个好的选择。您可以按每列中非零的数量进行排序和分组。然后,每组按索引和值进行排序,并分成无变化的块: import numpy as np

识别以csc_矩阵格式表示的稀疏矩阵的唯一列以及每列的重复次数的好方法是什么


我没有关于矩阵元素的先验信息。这是通过替换另一个矩阵的列进行采样的结果,因此我可以有两个重复的列,因为一个列被多次采样,或者原始矩阵中存在重复的列。因此,我无法将
numpy.unique
应用于采样列的索引,我认为将整个矩阵转换为密集格式,然后将
numpy.unique
应用于它不是一个好的选择。

您可以按每列中非零的数量进行排序和分组。然后,每组按索引和值进行排序,并分成无变化的块:

import numpy as np
from scipy import sparse

def sparse_unique_columns(M):
    M = M.tocsc()
    m, n = M.shape
    if not M.has_sorted_indices:
        M.sort_indices()
    if not M.has_canonical_format:
        M.sum_duplicates()
    sizes = np.diff(M.indptr)
    idx = np.argsort(sizes)
    Ms = M@sparse.csc_matrix((np.ones((n,)), idx, np.arange(n+1)), (n, n))
    ssizes = np.diff(Ms.indptr)
    ssizes[1:] -= ssizes[:-1]
    grpidx, = np.where(ssizes)
    grpidx = np.concatenate([grpidx, [n]])
    if ssizes[0] == 0:
        counts = [np.array([0, grpidx[0]])]
    else:
        counts = [np.zeros((1,), int)]
    ssizes = ssizes[grpidx[:-1]].cumsum()
    for i, ss in enumerate(ssizes):
        gil, gir = grpidx[i:i+2]
        pl, pr = Ms.indptr[[gil, gir]]
        dv = Ms.data[pl:pr].view(f'V{ss*Ms.data.dtype.itemsize}')
        iv = Ms.indices[pl:pr].view(f'V{ss*Ms.indices.dtype.itemsize}')
        idxi = np.lexsort((dv, iv))
        dv = dv[idxi]
        iv = iv[idxi]
        chng, = np.where(np.concatenate(
            [[True], (dv[1:] != dv[:-1]) | (iv[1:] != iv[:-1]), [True]]))
        counts.append(np.diff(chng))
        idx[gil:gir] = idx[gil:gir][idxi]
    counts = np.concatenate(counts)
    nu = counts.size - 1
    uniques = M@sparse.csc_matrix((np.ones((nu,)), idx[counts[:-1].cumsum()],
                                   np.arange(nu + 1)), (n, nu))
    return uniques, idx, counts[1:]


a = np.random.uniform(0, 10, (1000, 200))
a[a>1] = 0
a = sparse.csc_matrix(a)
b = sparse.csc_matrix((np.ones(1000), np.random.randint(0, 200, (1000,)), np.arange(1001)))
c = a@b

unq, idx, cnt = sparse_unique_columns(c)
unqd, idxd, cntd = np.unique(c.A, axis=1, return_counts=True, return_inverse=True)
from timeit import timeit

print('sparse:', timeit(lambda: sparse_unique_columns(c), number=1000), 'ms')
print('dense: ', timeit(lambda: np.unique(c.A, axis=1, return_counts=True), number=100)*10, 'ms')
样本输出:

sparse: 2.735588440205902 ms
dense:  49.32689592242241 ms

没有一种方法可以做到这一点,因此,如果不进行实验,我们无法确定哪种方法最有效。将
np.unique
应用到稠密版本是一个良好的开端。或者,根据值的大小和范围,列总和可以完成这项工作,或者至少可以确定可能的重复候选项。我还将考虑查看<代码> M.T.TelILL()/<代码>矩阵的属性。副本将有匹配的
数据
列表。在任何人给出有用的答案之前,您需要提供一些示例,可能是一个用于测试想法的小玩具示例,以及一个用于测试效率的更现实的示例。生成一个随机矩阵很容易,其中每个列都是唯一的,除了那些都是0的列。我改进了我的问题。你能告诉我
Ms=M@sparse.csc_matrix((np.ones((n,)),idx,np.arange(n+1)),(n,n))
视图(f'V{ss*Ms.data.dtype.itemsize})
?@momomi第一种方法是将
M的列(按非零的数量)乘以适当的(稀疏的)排列矩阵进行排序。第二种方法将
ss
元素(=列)的块组合成
void
dtype的单个元素。这将加速这些列的排序。谢谢。无论如何,如果我编译你的代码,我会得到两个错误:一个是关于'view(f'V{ss*Ms.data.dtype.itemsize}')的语法,另一个是关于'idx[gil:gir]=idx[gil:gir][idxi'的越界。实际上,我很难理解最后一行的含义,以及在比较每个块的每个M.data和M.index元素时,如何获得重复列的行索引。@momomi编译是什么意思?--关于语法错误:您使用的是旧的python版本吗?f字串是一个相对较新的特性。你是如何解决这个问题的?您看到的其他错误很可能是后续错误您发现的这行很难用给定数量的非零对当前列块进行排序。是的,我使用的是Python 2.7,我通过
V{s}.format(s=ss*Ms.data.dtype.itemsize)
进行了解析,但现在引发了另一个错误:idxi=np.lexsort((dv,iv))ValueError:所有键都必须是相同的形状。很抱歉,即使我省略了
.view()
我在
idx[gil:gir][idxi]
中也有一个错误:在这里,您提取了Ms的ss列的索引,该索引与idxi有关,它指的是Ms.data[gil,gir]的排序,为什么?