【问题标题】:How can I combine an array of values and mask into a matrix?如何将一组值和掩码组合成一个矩阵?
【发布时间】:2020-05-23 06:34:24
【问题描述】:

如何将一组值和掩码组合成一个矩阵,该矩阵仅包含数组中的每个值一次,但仅在掩码非零的地方?你可以说我想用数组中的值填充掩码矩阵。

我实际上并不关心结果中原始元素的顺序。

mask = [[0, 1, 0], [1, 0, 1], [0, 1, 0]]
values = [1, 2, 3, 4]
result = some_magical_operation(mask, values)

# output: result = [[0, 1, 0], [2, 0, 3], [0, 4, 0]]

# alternative output: result2 = [[0, 2, 0], [1, 0, 3], [0, 4, 0]]
# alternative output: result3 = [[0, 4, 0], [3, 0, 2], [0, 1, 0]]

注意:我的实际矩阵的密度明显低于此。

【问题讨论】:

标签: python numpy matrix scipy sparse-matrix


【解决方案1】:
In [229]: mask = [[0, 1, 0], [1, 0, 1], [0, 1, 0]] 
     ...: values = [1, 2, 3, 4]                                                          
In [230]: mask = np.array(mask, bool)                                                    
In [231]: mask                                                                           
Out[231]: 
array([[False,  True, False],
       [ True, False,  True],
       [False,  True, False]])
In [232]: res =  np.zeros(mask.shape, int)                                               

如果mask 是布尔值,那么它可以用于索引res 的相关槽,用于获取值或分配它们。

In [233]: res[mask]                                                                      
Out[233]: array([0, 0, 0, 0])

In [234]: res[mask]= values                                                              
In [235]: res                                                                            
Out[235]: 
array([[0, 1, 0],
       [2, 0, 3],
       [0, 4, 0]])

要使用scipy.sparse,您可以这样做:

In [241]: from scipy import sparse                                                       

mask 创建一个稀疏矩阵:

In [243]: M = sparse.csr_matrix(mask, dtype=int)                                         
In [244]: M                                                                              
Out[244]: 
<3x3 sparse matrix of type '<class 'numpy.longlong'>'
    with 4 stored elements in Compressed Sparse Row format>
In [245]: M.A                                                                            
Out[245]: 
array([[0, 1, 0],
       [1, 0, 1],
       [0, 1, 0]], dtype=int64)

然后将其data 值替换为values

In [246]: M.data                                                                         
Out[246]: array([1, 1, 1, 1], dtype=int64)                                                         
In [250]: M.data[:] = values                                                             
In [251]: M.A                                                                            
Out[251]: 
array([[0, 1, 0],
       [2, 0, 3],
       [0, 4, 0]], dtype=int64)

【讨论】:

    【解决方案2】:

    这是我尝试过的东西,

    mask = [[0, 1, 0], [1, 0, 1], [0, 1, 0]]
    val = [1, 2, 3, 4]
    result=list()
    k=0
    
    for i in mask:
        for j in range(0,len(i)):
            if i[j]!=0:
                i[j]=val[k]
                k+=1
        result.append(i)
    print(result)
    

    输出:

    [[0, 1, 0], [2, 0, 3], [0, 4, 0]]
    

    还需要对此代码进行一些小的修改:

    1. 检查 val[k] 是否没有用完索引

    【讨论】:

      【解决方案3】:

      我不知道是否有一个 NumPy 函数来解决这个问题,所以我创建了自己的:

      import numpy as np
      
      
      def some_magical_operation_ndarray(m: np.ndarray, v: np.ndarray) -> np.ndarray:
          res = np.zeros(m.shape)
          n = 0
          for i in range(m.shape[0]):
              for j in range(m.shape[1]):
                  if not m[i, j] == 0:
                      res[i, j] = v[n]
                      n += 1
                      if n == len(v):
                          n = 0
          return res
      
      
      mask = np.asarray([[0, 1, 0], [1, 0, 1], [0, 1, 0]])
      values = np.asarray([1, 2, 3, 4])
      result = some_magical_operation_ndarray(mask, values)
      print(result)
      

      如果您想使用列表而不是 ndarray,则此解决方案可行:

      def some_magical_operation_list(m: list, v: list) -> list:
          res = []
          n = 0
          for i in range(len(m)):
              res.append([])
              for j in range(len(m[i])):
                  if not m[i][j] == 0:
                      res[i].append(v[n])
                      n += 1
                      if n == len(v):
                          n = 0
                  else:
                      res[i].append(0)
          return res
      
      
      mask = [[0, 1, 0], [1, 0, 1], [0, 1, 0]]
      values = [1, 2, 3, 4]
      result = some_magical_operation_list(mask, values)
      print(result)
      

      【讨论】:

        【解决方案4】:

        试试这个:

        _mask = np.nonzero(mask)
        mask[_mask] = values
        

        应该完全按照您的要求工作。

        测试集示例:

        mask = np.random.randint(0, 2, (7,3))
        mask[_mask] = np.arange(1, _mask[0].shape[0] + 1)    # the RHS is a test equivalent to 'values'
        

        结果:

        >>> mask (original):
        array([[0, 0, 1],
               [1, 0, 0],
               [1, 1, 1],
               [0, 1, 1],
               [0, 1, 1],
               [0, 1, 0],
               [0, 1, 1]])
        
        >>> mask (modified):
        array([[ 0,  0,  1],
               [ 2,  0,  0],
               [ 3,  4,  5],
               [ 0,  6,  7],
               [ 0,  8,  9],
               [ 0, 10,  0],
               [ 0, 11, 12]])
        

        如果您不想修改mask 本身,请复制mask 并在复制的数组上使用_mask

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-09-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-19
          相关资源
          最近更新 更多