如何使用scipy.sparse.csr_matrix.minimum忽略隐式零?

3pvhb19x  于 2022-11-10  发布在  其他
关注(0)|答案(2)|浏览(152)

我有两个稀疏矩阵mat1mat2(大多数元素都是零),我对零值元素不感兴趣:我从图论的Angular 来看待矩阵,其中零意味着节点之间没有边。
如何 * 有效地 * 使用scipy.sparse矩阵仅在非零项之间获得最小值?即,mat1.minimum(mat2)的等价矩阵将忽略隐式零。
使用稠密矩阵,可以很容易地做到:

import numpy as np
nnz = np.where(np.multiply(mat1, mat2))
m = mat1 + mat2
m[nnz] = np.minimum(mat1[nnz], mat2[nnz])

但是,这对于稀疏矩阵来说是非常低效的。

**注意:**以前曾询问过similar question,但未得到任何相关答案,scipy存储库上有一个相关的PR,它建议为(arg)min/max实现此功能,但不建议为minimum实现此功能。

编辑:为了更详细地说明,所需行为是可交换的,即nonzero-minimum将取两个矩阵中仅一个矩阵中存在的所有值以及两个矩阵中存在的元素的最小值

46scxncf

46scxncf1#

为了防止有人也在寻找这个,我目前的实现如下。然而,我会感谢任何建议,将加快这一点或减少内存占用。

s = mat1.multiply(mat2)
s.data[:] = 1.

a1 = mat1.copy()
a1.data[:] = 1.
a1 = (a1 - s).maximum(0)

a2 = mat2.copy()
a2.data[:] = 1.
a2 = (a2 - s).maximum(0)

res = mat1.multiply(a1) + mat2.multiply(a2) + \
      mat1.multiply(s).minimum(mat2.multiply(s))
ltskdhd1

ltskdhd12#

如果稀疏非零值为正数,则使用maximum的正确 UNION 行为的另一种方法可能是 * 取反并使其为正数 *。

按照你的指导,我明确地用data来做了一些事情。

def sp_min_nz_positive(asp,bsp):  # a and b scipy sparse
    amax = asp.max()
    bmax = bsp.max()
    abmaxplus = max(amax, bmax) # + 1.0 : surprise! not needed.
    # invert the direction, while remaining positive
    arev = asp.copy()
    arev.data[:] = abmaxplus - asp.data[:]
    brev = bsp.copy()
    brev.data[:] = abmaxplus - bsp.data[:]
    out = arev.maximum(brev)  # 
    # revert the direction of these positives
    out.data[:] = abmaxplus - out.data[:]
    return out

由于四舍五入,可能会有不精确之处
还有一个建议是使用稀疏内部函数。一个相当通用的函数是sp.find,它返回 anything 的非零元素。
因此,您也可以尝试使用minimum它也可以处理负值,如下所示:

import scipy.sparse as sp
def sp_min_union(a, b):
    assert a.shape == b.shape
    assert sp.issparse(a) and sp.issparse(b)
    (ra,ca,_) = sp.find(a)   # over nonzeros only
    (rb,cb,_) = sp.find(b)   # over nonzeros only
    setab = set(zip(ra,ca)).union(zip(rb,cb)) # row-column union-of-nonzero
    r=[]
    c=[]
    v=[]
    for (rr,cc) in setab:
        r.append(rr)
        c.append(cc)
        anz = a[rr,cc]
        bnz = b[rr,cc]
        assert anz!=0 or bnz!=0   # they came from *some* sp.find
        if anz==0: anz = bnz
        #else:
        #    #if bnz==0: anz = anz
        #    #else:      anz=min(anz,bnz)
        # equiv.
        elif bnz!=0: anz=min(anz,bnz)
        v.append(anz)
    # choose what sparse output format you want, many seem
    # constructible as:
    return sp.csr_matrix((v, (r,c)), shape=a.shape)

相关问题