【问题标题】:Ignoring duplicate entries in sparse matrix忽略稀疏矩阵中的重复条目
【发布时间】:2020-03-30 04:09:31
【问题描述】:

按照文档的建议,我尝试从(data, (rows, cols)) 值列表中初始化csc_matrixcsr_matrix

sparse = csc_matrix((data, (rows, cols)), shape=(n, n))

问题在于,我实际用于生成datarowscols 向量的方法在某些点上引入了重复项。默认情况下,scipy 添加重复条目的值。但是,就我而言,对于给定的(row, col),这些重复项在data 中具有完全相同的值。

我想要实现的是让 scipy 忽略第二个条目(如果已经存在),而不是添加它们。

忽略我可以改进生成算法以避免生成重复的事实,是否有创建忽略重复的稀疏矩阵的参数或其他方法?

目前data = [4, 4]; cols = [1, 1]; rows = [1, 1]; 的两个条目生成一个稀疏矩阵,其(1,1) 的值为8,而所需的值为4

>>> c = csc_matrix(([4, 4], ([1,1],[1,1])), shape=(3,3))
>>> c.todense()
matrix([[0, 0, 0],
        [0, 8, 0],
        [0, 0, 0]])

我也知道我可以使用二维 numpy unique 函数过滤它们,但列表非常大,所以这不是一个真正有效的选项。

该问题的其他可能答案:有没有办法指定如何处理重复项?即保留minmax 而不是默认的sum

【问题讨论】:

  • 我很确定答案是否定的,没有改变重复行为的内置方法。不过,您不应该太快放弃使用 np.unique:无论您的列表有多大,scipy 都会将它们转换为数组并在后台执行类似的操作,因此您没有理由不应该这样做不要尝试。
  • np.unique 是 1d,因此处理这些 2d 坐标需要一些额外的努力。
  • 没错,但是像this 这样的技巧使它变成了2D。

标签: python numpy scipy duplicates sparse-matrix


【解决方案1】:

在您的示例中创建一个中介 dok 矩阵有效:

In [410]: c=sparse.coo_matrix((data, (cols, rows)),shape=(3,3)).todok().tocsc()

In [411]: c.A
Out[411]: 
array([[0, 0, 0],
       [0, 4, 0],
       [0, 0, 0]], dtype=int32)

coo 矩阵将您的输入数组放入它的 data,col,row 属性中而不会发生变化。在将其转换为 csc 之前,不会发生求和。

todok 直接从coo 属性加载字典。它创建空白dok 矩阵,并用以下内容填充:

dok.update(izip(izip(self.row,self.col),self.data))

因此,如果有重复的 (row,col) 值,则它是最后一个剩余的值。这使用标准 Python 字典散列来查找唯一键。


这是使用np.unique 的一种方式。我必须构造一个特殊的对象数组,因为unique 是在 1d 上运行的,而我们有一个 2d 索引。

In [479]: data, cols, rows = [np.array(j) for j in [[1,4,2,4,1],[0,1,1,1,2],[0,1,2,1,1]]]

In [480]: x=np.zeros(cols.shape,dtype=object)

In [481]: x[:]=list(zip(rows,cols))

In [482]: x
Out[482]: array([(0, 0), (1, 1), (2, 1), (1, 1), (1, 2)], dtype=object)

In [483]: i=np.unique(x,return_index=True)[1]

In [484]: i
Out[484]: array([0, 1, 4, 2], dtype=int32)

In [485]: c1=sparse.csc_matrix((data[i],(cols[i],rows[i])),shape=(3,3))

In [486]: c1.A
Out[486]: 
array([[1, 0, 0],
       [0, 4, 2],
       [0, 1, 0]], dtype=int32)

我不知道哪种方法更快。


根据liuengo's链接获取唯一索引的另一种方法:

rc = np.vstack([rows,cols]).T.copy()
dt = rc.dtype.descr * 2
i = np.unique(rc.view(dt), return_index=True)[1]

rc 必须拥有自己的数据才能使用视图更改 dtype,因此 .T.copy()

In [554]: rc.view(dt)
Out[554]: 
array([[(0, 0)],
       [(1, 1)],
       [(2, 1)],
       [(1, 1)],
       [(1, 2)]], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])

【讨论】:

  • 看起来不错。我现在不能尝试,类型之间的转换是否需要很多时间/内存?
  • todok() 不会忽略 scipy 0.19 的重复项
  • 是的,coo.todok 现在包含 self.sum_duplicates() 行。解决方案是按照我的描述进行更新,但没有这个sum
  • @hpaulj 有什么解决办法?你的意思是使用todok() 函数代码没有`self.sum_duplicates()` 行?
【解决方案2】:

由于你data中重复(row, col)的值是相同的,你可以得到唯一的行、列和值如下:

rows, cols, data = zip(*set(zip(rows, cols, data)))

例子:

data = [4, 3, 4]
cols = [1, 2, 1]
rows = [1, 3, 1]

csc_matrix((data, (rows, cols)), shape=(4, 4)).todense()

matrix([[0, 0, 0, 0],
        [0, 8, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 3, 0]])



rows, cols, data = zip(*set(zip(rows, cols, data)))
csc_matrix((data, (rows, cols)), shape=(4, 4)).todense()

matrix([[0, 0, 0, 0],
        [0, 4, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 3, 0]])

【讨论】:

    【解决方案3】:

    只是为了更新 hpaulj 对 SciPy 最新版本的回答,这个问题最简单的解决方案是现在,给定一个 COO 矩阵 c now:

    dok=sparse.dok_matrix((c.shape),dtype=c.dtype)
    dok._update(zip(zip(c.row,c.col),c.data))
    
    new_c = dok.tocsc()
    

    这是由于 dok update() 函数中的新包装器,阻止它直接更改数组,需要使用下划线绕过包装器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 2018-01-19
      • 1970-01-01
      • 2012-01-10
      • 2015-04-26
      • 1970-01-01
      相关资源
      最近更新 更多