在coo_matrix(scipy稀疏矩阵)中,我如何选择并返回"随机列索引"在每一行中排除该行中的非零索引?

时间:2017-03-01 01:12:57

标签: python numpy scipy

我是Python的新手,这似乎很天真。我正在使用coo_matrix(scipy稀疏矩阵) M 并希望返回M的三元组:

row_index,column_index,random_index

具备以下条件:

  1. row_index,column_index必须指向M
  2. 的非零条目
  3. row_index,应返回与所有非零条目对应的column_index
  4. 对于每对row_index,column_index,应返回random_index
  5. random_index应该在M
  6. 的[0,total_num_columns]范围内
  7. random_index不应该在所有列索引的集合中,该索引指向该row_index的某个非零值
  8. 我可以提出以下功能:

     def get_triplets(M):
    return M.row, M.col, np.random.randint(M.shape[1], size=len(M.row))
    

    上述函数中的一切正常,但三元组的最后一个条目 - random_index 不是理想的方式。不保证随机索引不会位于该行的非零索引集合中。换句话说,不满足条件数(5)

    是否有一种有效的方法可以返回满足上述所有5个条件的三元组。希望我能说清楚,并感谢任何帮助解决我的问题

    由于

1 个答案:

答案 0 :(得分:1)

对于库矩阵MM.rowM.colM.data是定义矩阵的3个数组,并一起标识所有非零条目。它们可能是无序的,它们可能包含重复项。

In [1]: from scipy import sparse
In [2]: row=[0,0,1,1,1,2,2]
In [3]: col=[0,2,0,1,0,1,2]
In [4]: data=[1,2,3,4,5,6,7]
In [5]: M=sparse.coo_matrix((data,(row,col)))
In [6]: M
Out[6]: 
<3x3 sparse matrix of type '<class 'numpy.int32'>'
    with 7 stored elements in COOrdinate format>
In [7]: print(M)
  (0, 0)    1
  (0, 2)    2
  (1, 0)    3
  (1, 1)    4
  (1, 0)    5
  (2, 1)    6
  (2, 2)    7
In [8]: M.A
Out[8]: 
array([[1, 0, 2],
       [8, 4, 0],
       [0, 6, 7]])

我们可以将其设为规范 - 无需重复排序:

In [9]: M.sum_duplicates()
In [10]: print(M)
  (0, 0)    1
  (1, 0)    8
  (1, 1)    4
  (2, 1)    6
  (0, 2)    2
  (2, 2)    7

顺便说一句,这是转换为csr格式的一步。

(Opps - 首先按列排序的lex)

如果我正确地对随机位进行了图像处理,则对于每个非零条目,您需要从同一行的零时隙中随机选择。我假设我们不关心是否有重复。

所以我们需要一起收集所有行。  使用lil格式

可能会更容易
In [13]: Ml = M.tolil()
In [14]: Ml.data
Out[14]: array([[1, 2], [8, 4], [6, 7]], dtype=object)
In [16]: Ml.rows
Out[16]: array([[0, 2], [0, 1], [1, 2]], dtype=object)

只需迭代Ml.rows中的每个列表并生成随机选择。

这是一个开始:

def foo(cols, N):
    c = set(range(N))
    c = c.difference(cols)
    return np.random.choice(list(c))
In [29]: [foo(c,3) for c in Ml.rows]
Out[29]: [1, 2, 0]

不完全是我们想要的;它为每一行选择一个零列。在这个例子中,每行只有一个。

更改choice以便每次调用返回多个值:

def foo(cols, N):
    c = set(range(N))
    c = c.difference(cols)
    return np.random.choice(list(c),size=len(cols), replace=True)

In [32]: [foo(c,3) for c in Ml.rows]
Out[32]: [array([1, 1]), array([2, 2]), array([0, 0])]

我们可以将这些随机值写回Ml作为data

In [37]: randval = [foo(c,3) for c in Ml.rows]
In [38]: randval
Out[38]: [array([1, 1]), array([2, 2]), array([0, 0])]
In [39]: Ml.data
Out[39]: array([[1, 2], [8, 4], [6, 7]], dtype=object)
In [40]: Ml.data[:] = randval
In [41]: Ml.data
Out[41]: array([array([1, 1]), array([2, 2]), array([0, 0])], dtype=object)
In [42]: Ml.A
Out[42]: 
array([[1, 0, 1],
       [2, 2, 0],
       [0, 0, 0]], dtype=int32)

In [45]: print(Ml)
  (0, 0)    1
  (0, 2)    1
  (1, 0)    2
  (1, 1)    2
  (2, 1)    0
  (2, 2)    0

In [48]: Mo=Ml.tocoo()
In [51]: np.column_stack((Mo.row, Mo.col, Mo.data))
Out[51]: 
array([[0, 0, 1],
       [0, 2, 1],
       [1, 0, 2],
       [1, 1, 2],
       [2, 1, 0],
       [2, 2, 0]], dtype=int32)

如果数组较大且每行有多个零列,则此显示更有意义。如果任何行密集(没有零),我的代码也会中断。

所以一起

In [56]: M=sparse.rand(10,10,.2,'coo')
In [58]: Ml=M.tolil()
In [59]: randval = [foo(c,Ml.shape[1]) for c in Ml.rows]
In [61]: Ml.data[:] = randval
In [62]: Mo=Ml.tocoo()
In [63]: np.column_stack((Mo.row, Mo.col, Mo.data))

从评论中复制,以便于格式化

  

最初,我有这个功能:

def get_triplets(M): 
   return M.row, M.col, np.random.randint(M.shape[1], size=len(M.row))
  

它及时运作但不一致。但现在:

def get_triplets(mat): 
     M1 = mat.tolil() 
     randval = [foo(c, M1.shape[1]) for c in M1.rows] 
     M1.data[:] = randval 
     Mo = M1.tocoo() 
     return_mat = np.column_stack((Mo.row, Mo.col, Mo.data)) 
     return return_mat[:, 0], return_mat[:, 1], return_mat[:, 2]